import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test from 'node:test'; import { collectCurrentProduct } from '../lib/source-parsers.ts'; import { collectedProductPayloadSchema } from '@atlas/contracts'; function fixtureSkuModel(html: string) { const marker = '"skuModel": '; const start = html.indexOf(marker); assert.ok(start >= 0); const source = html.slice(start + marker.length); let depth = 0; let quoted = false; let escaped = false; for (let index = 0; index < source.length; index += 1) { const char = source[index]; if (quoted) { if (escaped) escaped = false; else if (char === '\\') escaped = true; else if (char === '"') quoted = false; } else if (char === '"') quoted = true; else if (char === '{') depth += 1; else if (char === '}' && --depth === 0) return JSON.parse(source.slice(0, index + 1)); } throw new Error('1688 样本缺少完整 skuModel'); } test('1688 真实样本按 skuInfoMap 的 price 和规格图片生成逐 SKU 数据', async () => { const html = await readFile(new URL('../../../packages/reference/1688.html', import.meta.url), 'utf8'); const skuModel = fixtureSkuModel(html); const root = { scripts: [], querySelector: () => null, querySelectorAll: () => [], } as unknown as Document; const payload = await collectCurrentProduct( root, 'https://detail.1688.com/offer/123456789.html', undefined, async () => ({ skuModel }), ); assert.equal(payload.variants.length, Object.keys(skuModel.skuInfoMap).length); assert.equal(collectedProductPayloadSchema.safeParse(payload).success, true); for (const [name, row] of Object.entries(skuModel.skuInfoMap)) { const variant = payload.variants.find((item) => item.sourceSku === String(row.skuId)); assert.ok(variant, `缺少 ${name}`); assert.equal(variant.displayName, name); assert.equal(variant.sourcePrice?.amount, row.price); const image = skuModel.skuProps[0].value.find((item: any) => item.name === name)?.imageUrl; assert.ok(payload.assets.some((asset) => asset.variantSourceKey === variant.sourceVariantKey && asset.url === image ), `${name} 未关联规格图片`); } const scriptRoot = { ...root, scripts: [{ type: 'text/javascript', textContent: html }], } as unknown as Document; const withoutBridge = await collectCurrentProduct( scriptRoot, 'https://detail.1688.com/offer/123456789.html', ); assert.equal(withoutBridge.variants.length, payload.variants.length); assert.equal(withoutBridge.assets.filter((asset) => asset.variantSourceKey).length, payload.variants.length); }); test('1688 超过 100 条真实可售记录完整解析,不按旧上限裁剪', async () => { const root = { scripts: [], querySelector: () => null, querySelectorAll: () => [] } as unknown as Document; const skuInfoMap = Object.fromEntries(Array.from({ length: 200 }, (_, index) => [ `组合 ${index}`, { skuId: String(8_000_000_000_000 + index), price: '20.00' }, ])); const payload = await collectCurrentProduct(root, 'https://detail.1688.com/offer/123456789.html', undefined, async () => ({ skuModel: { skuInfoMap } })); assert.equal(payload.variants.length, 200); assert.equal(payload.variants.at(-1)?.sourceSku, String(8_000_000_000_199)); assert.equal(collectedProductPayloadSchema.safeParse(payload).success, true); }); test('字段名字符串与后续 150 个无关对象不会被误采为 SKU', async () => { const unrelated = Object.fromEntries(Array.from({ length: 150 }, (_, index) => [ `metadata${index}`, { label: '推荐数据' }, ])); const model = { skuInfoMap: { 白色: { skuId: '1001', price: '20.00' }, 蓝色: { skuId: '1002', price: '20.00' } }, skuProps: [{ prop: 'color', name: '颜色', value: [{ valueId: 'white', name: '白色' }, { valueId: 'blue', name: '蓝色' }] }], }; const script = `const key="skuInfoMap";const unrelated=${JSON.stringify(unrelated)};window.context=${JSON.stringify({ skuModel: model })};`; const root = { scripts: [{ type: 'text/javascript', textContent: script }], querySelector: () => null, querySelectorAll: () => [] } as unknown as Document; const payload = await collectCurrentProduct(root, 'https://detail.1688.com/offer/123456789.html'); assert.deepEqual(payload.variants.map((variant) => variant.sourceSku), ['1001', '1002']); assert.deepEqual(payload.variants.map((variant) => variant.displayName), ['白色', '蓝色']); }); test('skuInfoMap 为 null 时不跳读后续对象,仍读取明确的原始可售表', async () => { const script = `window.context={"skuInfoMap":null,"unrelated":{"bad":{"title":"不是 SKU"}},"skuMapOriginal":[{"skuId":"1001","specAttrs":"白色","price":"20.00"}]};`; const root = { scripts: [{ type: 'text/javascript', textContent: script }], querySelector: () => null, querySelectorAll: () => [] } as unknown as Document; const payload = await collectCurrentProduct(root, 'https://detail.1688.com/offer/123456789.html'); assert.equal(payload.variants.length, 1); assert.equal(payload.variants[0].sourceSku, '1001'); }); test('真实规格表内的元数据不生成 SKU,无 ID 的完整可售组合仍保留', async () => { const root = { scripts: [], querySelector: () => null, querySelectorAll: () => [] } as unknown as Document; const model = { skuInfoMap: { metadata: { label: '元数据' }, 未匹配颜色: { price: '30.00' }, 白色: { price: '20.00', canBookCount: 0 }, }, skuProps: [{ prop: 'color', name: '颜色', value: [{ valueId: 'white', name: '白色' }] }], }; const payload = await collectCurrentProduct(root, 'https://detail.1688.com/offer/123456789.html', undefined, async () => ({ skuModel: model })); assert.equal(payload.variants.length, 1); assert.equal(payload.variants[0].sourceVariantKey, '1688:白色'); assert.equal(payload.variants[0].selections[0].valueKey, 'white'); });