jd-adapters.test.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import assert from 'node:assert/strict';
  2. import test from 'node:test';
  3. import { adaptJdProductResponse } from '../src/modules/domestic-voc/adapters/jd-product.adapter.js';
  4. import { GatewayPayloadError } from '../src/modules/domestic-voc/adapters/jd-response.js';
  5. import { adaptJdReviewResponse } from '../src/modules/domestic-voc/adapters/jd-review.adapter.js';
  6. test('JD product adapter unwraps the company gateway envelope', () => {
  7. const product = adaptJdProductResponse({
  8. code: 200,
  9. data: {
  10. code: 200,
  11. data: {
  12. item: {
  13. itemId: '11266507445',
  14. itemName: 'Demashi commercial cooker',
  15. brandName: 'Demashi',
  16. model: '35P6-CM1',
  17. firstCategoryName: 'Commercial appliances',
  18. thirdCategoryName: 'Commercial cooker',
  19. },
  20. },
  21. },
  22. }, '11266507445');
  23. assert.equal(product.productId, '11266507445');
  24. assert.equal(product.productKey, 'jd:11266507445');
  25. assert.equal(product.title, 'Demashi commercial cooker');
  26. assert.equal(product.brand, 'Demashi');
  27. assert.equal(product.model, '35P6-CM1');
  28. assert.equal(product.source, 'fmode_gateway');
  29. });
  30. test('JD review adapter maps evidence and pagination without reviewer identity', () => {
  31. const page = adaptJdReviewResponse({
  32. code: 200,
  33. data: {
  34. code: 200,
  35. data: {
  36. comments: [{
  37. commentId: 'comment-1',
  38. score: 5,
  39. content: 'Easy to clean and heats quickly.',
  40. creationTime: '2026-07-20T10:00:00+08:00',
  41. nickname: 'not-exposed-by-snapshot',
  42. }],
  43. pageCount: 2,
  44. },
  45. },
  46. }, '11266507445', 1);
  47. assert.equal(page.reviews.length, 1);
  48. assert.equal(page.reviews[0]?.reviewId, 'comment-1');
  49. assert.equal(page.reviews[0]?.rating, 5);
  50. assert.equal(page.reviews[0]?.reviewDate, '2026-07-20T02:00:00.000Z');
  51. assert.match(page.reviews[0]?.reviewKey ?? '', /^jd:11266507445:/);
  52. assert.equal(page.hasNextPage, true);
  53. });
  54. test('JD adapters classify pending collection as retryable without raw body leakage', () => {
  55. assert.throws(
  56. () => adaptJdProductResponse({ code: 301, message: 'COLLECT FAILED, SEND REQUEST AGAIN', data: null }, '1'),
  57. (error: unknown) => {
  58. assert.ok(error instanceof GatewayPayloadError);
  59. assert.equal(error.retryable, true);
  60. assert.equal(error.message, 'Gateway data is not ready');
  61. assert.doesNotMatch(error.message, /COLLECT FAILED/);
  62. return true;
  63. },
  64. );
  65. });