const test = require('node:test'); const assert = require('node:assert/strict'); const { _test: { COMPANY_TASK_WORKFLOW_STEPS, buildPreferredMarketReferenceSeed, buildSelectionFissionPlanListSummary, buildWorkflowSummary, getSelectionFissionItemNodeState, isRetryableAlibaba1688ImageSearchFailure, }, } = require('../src/services/planningSelectionFissionService'); test('1688 sourcing keeps the selected market result as the later image reference', () => { const seeded = buildPreferredMarketReferenceSeed({ marketItemId: '897171229570', channelName: '淘宝', title: '市场参考商品', imageUrl: 'https://example.com/reference.jpg', detailUrl: 'https://item.taobao.com/item.htm?id=897171229570', }); assert.equal(seeded.candidate.marketItemId, '897171229570'); assert.equal(seeded.candidate.imageUrl, 'https://example.com/reference.jpg'); assert.equal(seeded.batch.source, 'alibaba_1688_sourcing_context'); assert.deepEqual(seeded.batch.candidates, [seeded.candidate]); }); test('1688 sourcing does not seed an incomplete market image reference', () => { assert.deepEqual(buildPreferredMarketReferenceSeed({ marketItemId: '897171229570' }), { candidate: null, batch: null, }); }); test('1688 sourcing retries only transient upstream failures', () => { assert.equal(isRetryableAlibaba1688ImageSearchFailure({ status: 502, message: '后端服务调用失败', }), true); assert.equal(isRetryableAlibaba1688ImageSearchFailure({ response: { status: 504, data: { message: 'Gateway Timeout' } }, }), true); assert.equal(isRetryableAlibaba1688ImageSearchFailure({ status: 502, message: 'AccessKey已被禁用', }), false); assert.equal(isRetryableAlibaba1688ImageSearchFailure({ response: { status: 400, data: { message: '参数错误' } }, }), false); }); test('company product workflow restores pricing before image generation', () => { assert.deepEqual(COMPANY_TASK_WORKFLOW_STEPS, [8, 3, 4, 6, 7]); const task = { selectedSpuCode: 'SPU-1', selectedMainSkuImageUrl: 'https://example.com/sku.jpg', whiteBackgroundAssets: { rows: [{ skuCode: 'SKU-1' }] }, skuSnapshot: { rows: [{ skuCode: 'SKU-1' }] }, skuSceneImages: {}, pricingRows: [], activityPricingRows: [], }; assert.equal(getSelectionFissionItemNodeState(task).step, 8); task.pricingRows = [{ skuCode: 'SKU-1' }]; task.activityPricingRows = [{ skuCode: 'SKU-1' }]; task.pricingTableSavedAt = '2026-08-20T00:00:00.000Z'; assert.equal(getSelectionFissionItemNodeState(task).step, 3); }); test('selection plan list summary excludes heavy workflow payloads', () => { const summary = buildSelectionFissionPlanListSummary({ id: 7, sourceItems: [{ id: 11, sourceItemId: 11, marketItemId: 'm-1', workflowStatus: 'running' }], listingTasks: [{ id: 12, selectedSpuCode: 'SPU-1', listingStatus: 'draft' }], items: [{ id: 12, pricingRows: Array.from({ length: 100 }, () => ({ skuCode: 'sku' })) }], }); assert.equal(summary.detailLoaded, false); assert.equal(summary.items.length, 0); assert.deepEqual(summary.sourceItems[0], { id: 11, sourceItemId: 11, slotNo: undefined, marketItemId: 'm-1', channelName: undefined, title: undefined, mainImageUrl: undefined, workflowStep: undefined, workflowStatus: 'running', workflowErrorMessage: undefined, }); assert.equal(summary.listingTasks[0].selectedSpuCode, 'SPU-1'); assert.equal(summary.listingTasks[0].pricingRows, undefined); }); test('workflow summary exposes a failed child node immediately', () => { const summary = buildWorkflowSummary({ workflowStatus: 'waiting', workflowStep: 2, workflowProgress: 20, items: [{ id: 101, sourceItemId: 101, slotNo: 1, variantNo: 0, selectedSpuCode: '', workflowStatus: 'failed', workflowStep: 2, workflowErrorMessage: '公司 SPU 匹配服务不可用', }], }); assert.equal(summary.status, 'failed'); assert.equal(summary.currentStep, 2); assert.equal(summary.errorMessage, '公司 SPU 匹配服务不可用'); assert.equal(summary.requiresUser, false); });