Initial commit: Memind H5 portal with MindSpace, Plaza, and agent jobs.
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
buildXml,
|
||||
createWechatPayClient,
|
||||
loadWechatPayConfig,
|
||||
parseXmlFields,
|
||||
signV2Params,
|
||||
} from './wechat-pay.mjs';
|
||||
|
||||
test('signV2Params is deterministic and uppercase MD5', () => {
|
||||
const params = {
|
||||
appid: 'wx8888888888888888',
|
||||
mch_id: '1900000109',
|
||||
body: 'test',
|
||||
nonce_str: 'ibuaiVcKdpRxkhJA',
|
||||
};
|
||||
const apiKey = '8934e7d15453e97507ef794cf7b0519d';
|
||||
const sign = signV2Params(params, apiKey);
|
||||
assert.match(sign, /^[0-9A-F]{32}$/);
|
||||
assert.equal(sign, signV2Params(params, apiKey));
|
||||
assert.notEqual(sign, signV2Params({ ...params, body: 'other' }, apiKey));
|
||||
});
|
||||
|
||||
test('parseXmlFields and buildXml round-trip', () => {
|
||||
const xml = buildXml({
|
||||
return_code: 'SUCCESS',
|
||||
out_trade_no: 'TK123',
|
||||
total_fee: '500',
|
||||
});
|
||||
const fields = parseXmlFields(xml);
|
||||
assert.equal(fields.return_code, 'SUCCESS');
|
||||
assert.equal(fields.out_trade_no, 'TK123');
|
||||
assert.equal(fields.total_fee, '500');
|
||||
});
|
||||
|
||||
test('loadWechatPayConfig selects v2 when APIv2 key is configured', () => {
|
||||
const previous = {
|
||||
enabled: process.env.H5_WECHAT_PAY_ENABLED,
|
||||
appId: process.env.H5_WECHAT_APP_ID,
|
||||
mchId: process.env.H5_WECHAT_MCH_ID,
|
||||
apiV2Key: process.env.H5_WECHAT_API_V2_KEY,
|
||||
apiVersion: process.env.H5_WECHAT_API_VERSION,
|
||||
notifyUrl: process.env.H5_WECHAT_NOTIFY_URL,
|
||||
v3Key: process.env.H5_WECHAT_API_V3_KEY,
|
||||
serialNo: process.env.H5_WECHAT_SERIAL_NO,
|
||||
privateKey: process.env.H5_WECHAT_PRIVATE_KEY,
|
||||
};
|
||||
process.env.H5_WECHAT_PAY_ENABLED = '1';
|
||||
process.env.H5_WECHAT_APP_ID = 'wxtestappid';
|
||||
process.env.H5_WECHAT_MCH_ID = '1234567890';
|
||||
process.env.H5_WECHAT_API_V2_KEY = 'test-api-v2-key-32chars-long!!!!';
|
||||
process.env.H5_WECHAT_NOTIFY_URL = 'https://example.com/webhooks/wechat-pay/notify';
|
||||
delete process.env.H5_WECHAT_API_VERSION;
|
||||
delete process.env.H5_WECHAT_API_V3_KEY;
|
||||
delete process.env.H5_WECHAT_SERIAL_NO;
|
||||
delete process.env.H5_WECHAT_PRIVATE_KEY;
|
||||
try {
|
||||
const config = loadWechatPayConfig();
|
||||
assert.equal(config.apiVersion, 'v2');
|
||||
assert.equal(config.enabled, true);
|
||||
const client = createWechatPayClient(config);
|
||||
assert.equal(client.apiVersion, 'v2');
|
||||
assert.equal(client.enabled, true);
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previous)) {
|
||||
const envKey = {
|
||||
enabled: 'H5_WECHAT_PAY_ENABLED',
|
||||
appId: 'H5_WECHAT_APP_ID',
|
||||
mchId: 'H5_WECHAT_MCH_ID',
|
||||
apiV2Key: 'H5_WECHAT_API_V2_KEY',
|
||||
apiVersion: 'H5_WECHAT_API_VERSION',
|
||||
notifyUrl: 'H5_WECHAT_NOTIFY_URL',
|
||||
v3Key: 'H5_WECHAT_API_V3_KEY',
|
||||
serialNo: 'H5_WECHAT_SERIAL_NO',
|
||||
privateKey: 'H5_WECHAT_PRIVATE_KEY',
|
||||
}[key];
|
||||
if (value === undefined) delete process.env[envKey];
|
||||
else process.env[envKey] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('verifyNotify validates v2 callback signature', () => {
|
||||
const apiKey = 'test-api-v2-key-32chars-long!!!!';
|
||||
const fields = {
|
||||
return_code: 'SUCCESS',
|
||||
result_code: 'SUCCESS',
|
||||
out_trade_no: 'TKORDER001',
|
||||
transaction_id: '4200001234',
|
||||
total_fee: '1000',
|
||||
nonce_str: 'abc123',
|
||||
};
|
||||
fields.sign = signV2Params(fields, apiKey);
|
||||
const body = buildXml(fields);
|
||||
const client = createWechatPayClient({
|
||||
enabled: true,
|
||||
apiVersion: 'v2',
|
||||
appId: 'wxtest',
|
||||
mchId: '123',
|
||||
apiKey,
|
||||
notifyUrl: 'https://example.com/notify',
|
||||
skipNotifyVerify: false,
|
||||
});
|
||||
const { transaction } = client.verifyNotify({ headers: {}, body });
|
||||
assert.equal(transaction.out_trade_no, 'TKORDER001');
|
||||
assert.equal(transaction.trade_state, 'SUCCESS');
|
||||
assert.equal(transaction.amount.total, 1000);
|
||||
});
|
||||
Reference in New Issue
Block a user