jd-sp-client.signature.test.ts 1.9 KB

12345678910111213141516171819202122232425
  1. import assert from 'node:assert/strict';
  2. import { createHash } from 'node:crypto';
  3. import test from 'node:test';
  4. import { JdSpClient } from '../src/modules/listing-ai/clients/jd-sp.client.js';
  5. import { normalizeJdListing } from '../src/modules/listing-ai/normalization/jd-listing.normalizer.js';
  6. test('JD detail path productId participates in signature but not query string', async () => {
  7. let capturedUrl='';let capturedHeaders:Headers|null=null;
  8. const fetchImpl:typeof fetch=async(input,init)=>{capturedUrl=String(input);capturedHeaders=new Headers(init?.headers);return new Response(JSON.stringify({success:true,data:{productInfo:{productId:1001}}}),{status:200,headers:{'content-type':'application/json'}});};
  9. const client=new JdSpClient({baseUrl:'https://api-cn.jd.com/rest',appKey:'app-key',appSecret:'app-secret',timeoutMs:1_000,retries:0},fetchImpl);
  10. await client.get('/sp-product/v0/products/1001',{scene:'pop'},'access-token',{productId:'1001'});
  11. assert.equal(new URL(capturedUrl).searchParams.get('scene'),'pop');
  12. assert.equal(new URL(capturedUrl).searchParams.has('productId'),false);
  13. const timestamp=capturedHeaders!.get('X-JOS-Timestamp')!;
  14. const fields:Record<string,string>={'X-JOS-Access-Token':'access-token','X-JOS-App-Key':'app-key','X-JOS-Timestamp':timestamp,productId:'1001',scene:'pop'};
  15. const plain=Object.keys(fields).sort().map((key)=>`${key}${fields[key]}`).join('');
  16. const expected=createHash('md5').update(`app-secret${plain}app-secret`).digest('hex').toUpperCase();
  17. assert.equal(capturedHeaders!.get('X-JOS-Sign'),expected);
  18. });
  19. test('JD image paths are converted to safe HTTPS CDN URLs',()=>{
  20. const source=normalizeJdListing({workspaceId:'demashi',shopId:'shop',row:{productId:1001},detail:{productInfo:{productId:1001,productName:'商品'},material:{mainImages:[{imageInfoList:[{imgUrl:'jfs/t1/demo.jpg',orderSort:1,primaryFlag:true}]}]}}});
  21. assert.equal(source.images[0]?.url,'https://img10.360buyimg.com/n1/jfs/t1/demo.jpg');
  22. });