cangku/backend/test/pddOpenPlatformClient.test.js

147 lines
3.9 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const test = require('node:test');
const {
createPddOpenPlatformClient,
normalizeCategoryRule,
resolvePddOpenPlatformCredential,
signPddParameters,
} = require('../src/services/pddOpenPlatformClient');
test('PDD signing uses UTF-8 and JSON encodes object values before sorting', () => {
const params = {
type: 'pdd.test',
client_id: 'cid',
timestamp: 1723723200,
data_type: 'JSON',
payload: { title: '中文', rows: [1, 2] },
};
assert.equal(
signPddParameters(params, 'secret'),
'3E0C5F16D0D478A19D44950A628411DB'
);
});
test('PDD credential resolver matches one shop and rejects ambiguous matches', async () => {
const rows = [
{
id: '1',
name: '卓禾旗舰店',
mallID: '10001',
accessToken: 'token-a',
client_id: 'client-a',
secrity: 'secret-a',
},
{
id: '2',
name: '其他旗舰店',
mallID: '10002',
accessToken: 'token-b',
client_id: 'client-b',
secrity: 'secret-b',
},
];
const credential = await resolvePddOpenPlatformCredential({
shopId: '10001',
shopName: '拼多多-卓禾旗舰店',
}, { rows });
assert.equal(credential.mallId, '10001');
assert.equal(credential.accessToken, 'token-a');
await assert.rejects(
resolvePddOpenPlatformCredential({ shopName: '卓禾旗舰店' }, {
rows: [rows[0], { ...rows[0], id: '3', mallID: '10003' }],
}),
(error) => error.code === 'PDD_CREDENTIAL_AMBIGUOUS'
);
});
test('PDD client never logs credentials and maps whitelist failures', async () => {
let sentBody;
const client = createPddOpenPlatformClient({
name: 'test',
clientId: 'client-id',
clientSecret: 'client-secret',
accessToken: 'access-token',
}, {
httpClient: {
post: async (_url, body) => {
sentBody = body;
return {
data: {
error_response: {
error_code: 20005,
error_msg: 'IP白名单校验失败',
request_id: 'request-1',
},
},
};
},
},
});
await assert.rejects(
client.getMallInfo(),
(error) => error.code === 'PDD_IP_NOT_WHITELISTED' && error.pddErrorCode === 20005
);
assert.equal(sentBody.client_secret, undefined);
assert.equal(sentBody.access_token, 'access-token');
assert.match(sentBody.sign, /^[A-F0-9]{32}$/);
});
test('only the final draft write treats transport failures as an unknown result', async () => {
const timeoutError = Object.assign(new Error('timeout'), { code: 'ETIMEDOUT' });
const client = createPddOpenPlatformClient({
name: '测试店铺',
clientId: 'client-id',
clientSecret: 'client-secret',
accessToken: 'access-token',
}, {
httpClient: { post: async () => { throw timeoutError; } },
timeout: 10,
});
await assert.rejects(
client.getMallInfo(),
(error) => error.code === 'PDD_TRANSPORT_ERROR'
&& error.retryable === true
&& error.resultUnknown === false
);
await assert.rejects(
client.saveGoodsDraft({ goods_name: '测试商品' }),
(error) => error.code === 'PDD_DRAFT_RESULT_UNKNOWN'
&& error.retryable === false
&& error.resultUnknown === true
);
});
test('category rules normalize required properties and enum values', () => {
const result = normalizeCategoryRule({
cat_rule_get_response: {
goods_properties_rule: {
properties: [{
ref_pid: 1628,
name: '环保等级',
required: false,
is_important: true,
choose_max_num: 1,
values: [{ vid: 368832, value: 'E0级' }],
}],
},
},
});
assert.deepEqual(result.properties[0], {
refPid: 1628,
name: '环保等级',
required: false,
important: true,
chooseMaxNum: 1,
valueType: 0,
minValue: null,
maxValue: null,
valueUnit: '',
showCondition: null,
values: [{ vid: 368832, value: 'E0级' }],
});
});