| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- import test from 'node:test';
- import assert from 'node:assert/strict';
- import { libraryFilterPatch, libraryRequest } from '../src/core/library.js';
- import { comparisonIds, comparisonQuery, toggleComparison, comparisonProductUrl, comparisonEvidenceUrl, comparisonPriceRows, matchingPrice, comparisonMoney } from '../src/core/library-comparison.js';
- import { readProductComparison } from '../src/services/library-comparison.js';
- test('店铺必须绑定平台,跨平台/移除平台清店铺和游标,不因店名更改品牌', () => {
- const query = { type: 'products', platform: 'jd', shopId: 'same-shop', brand: 'other', cursor: 'old' };
- assert.deepEqual(libraryFilterPatch(query, { platform: 'tmall' }), { type: 'products', platform: 'tmall', brand: 'other' });
- assert.deepEqual(libraryFilterPatch(query, { platform: null }), { type: 'products', brand: 'other' });
- assert.equal(libraryFilterPatch(query, { sort: 'price_asc' }).shopId, 'same-shop');
- assert.equal(libraryRequest({ platform: 'tmall', shopId: 'same-shop' }).filters.shopId, 'same-shop');
- assert.equal(libraryRequest({ shopId: 'same-shop' }).filters.shopId, undefined);
- assert.equal(libraryFilterPatch({ shopId: 'same-shop', cursor: 'old' }, {}).shopId, undefined);
- });
- test('2–4件对比按完整复合编号去重、拒绝第5件,URL刷新可恢复', () => {
- const ids = ['jd:1', 'tmall:1', 'jd:2', 'jd:3'];
- assert.deepEqual(comparisonIds(JSON.stringify([...ids, 'jd:1', 'jd:4'])), ids);
- assert.deepEqual(toggleComparison(ids, 'jd:4'), { ids, full: true });
- assert.deepEqual(toggleComparison(ids, 'tmall:1').ids, ['jd:1', 'jd:2', 'jd:3']);
- assert.deepEqual(comparisonIds('bad-json'), []);
- assert.deepEqual(comparisonIds(['title', null, 'jd:1', 'jd:1', 'jd:\n2']), ['jd:1']);
- const query = comparisonQuery({ platform: 'jd', cursor: 'page2' }, ids, true);
- assert.equal(query.comparing, '1'); assert.equal(query.cursor, 'page2');
- assert.deepEqual(comparisonIds(new URLSearchParams(new URL('https://example.test' + comparisonProductUrl('tmall:1', query)).search).get('compare')), ids);
- assert.equal(comparisonQuery(query, ['jd:1'], true).comparing, undefined);
- assert.equal(comparisonQuery(query, []).compare, undefined);
- });
- test('原评价证据固定商品与评价编号,跳详情关闭弹窗但保留列表筛选和所选项', () => {
- const context = { platform: 'jd', shopId: 'shop1', cursor: 'page2', panel: 'prices', comparing: '1', compare: '["jd:1","tmall:1"]', relatedCursor: 'old' };
- assert.equal(comparisonEvidenceUrl('jd:1', { productId: 'tmall:1', reviewId: 'r1' }, context), null);
- const url = new URL(comparisonEvidenceUrl('jd:1', { productId: 'jd:1', reviewId: 'r 1' }, context), 'https://example.test');
- assert.equal(url.pathname, '/library/products/jd%3A1');
- assert.equal(url.searchParams.get('panel'), 'reviews'); assert.equal(url.searchParams.get('relatedReviewId'), 'r 1');
- assert.equal(url.searchParams.get('comparing'), null); assert.equal(url.searchParams.get('relatedCursor'), null);
- assert.equal(url.searchParams.get('shopId'), 'shop1'); assert.equal(url.searchParams.get('cursor'), 'page2');
- });
- test('价格严格按币种和口径拆行,0元和缺失不混淆,不补算单位价格', () => {
- const group = (currency, price_basis, min) => ({ currency, price_basis, min, max: min, count: 1 });
- const record = { overview: { prices: [group('CNY', 'listing', 0), group('USD', 'listing', 100), group('CNY', 'reference', 200)] } };
- const rows = comparisonPriceRows([{ detail: { record } }, { error: 'failed' }]);
- assert.equal(rows.length, 3);
- assert.equal(matchingPrice(record, rows[0]).min, 0);
- assert.equal(comparisonMoney(0, 'CNY'), '¥0.00'); assert.equal(comparisonMoney(null, 'CNY'), '金额未知');
- assert.equal(matchingPrice({ overview: { prices: [] } }, rows[0]), undefined);
- });
- test('固定同一代际并限制两路并发,局部失败保留成功列且不填0', async () => {
- let active = 0, maxActive = 0;
- const calls = [];
- const result = await readProductComparison(['jd:1', 'tmall:1', 'jd:2', 'jd:3'], { read: async request => {
- calls.push(request);
- if (request.op === 'summary') return { generation: 'one' };
- assert.equal(request.generation, 'one'); active++; maxActive = Math.max(active, maxActive);
- await new Promise(resolve => setTimeout(resolve, 5)); active--;
- if (request.id === 'tmall:1') throw Error('暂不可用');
- return { generation: 'one', record: { id: request.id, overview: { reviews: { collected: 0 } } } };
- } });
- assert.equal(maxActive, 2); assert.equal(calls.length, 5); assert.equal(result.stale, false);
- assert.equal(result.items[0].detail.record.overview.reviews.collected, 0);
- assert.equal(result.items[1].error, '暂不可用'); assert.equal(result.items[1].detail, undefined);
- });
- test('代际错误/响应代际不一致使整组失效,再读取从新summary开始;不同编号响应不能串列', async () => {
- let generation = 'old';
- const read = async request => {
- if (request.op === 'summary') return { generation };
- if (generation === 'old' && request.id === 'jd:2') throw Object.assign(Error('changed'), { code: 'LIBRARY_VERSION_CHANGED' });
- return { generation, record: { id: request.id } };
- };
- const stale = await readProductComparison(['jd:1', 'jd:2'], { read });
- assert.equal(stale.stale, true); assert.ok(stale.items.every(item => !item.detail));
- generation = 'new';
- assert.ok((await readProductComparison(['jd:1', 'jd:2'], { read })).items.every(item => item.detail.generation === 'new'));
- const mismatch = await readProductComparison(['jd:1'], { read: async r => r.op === 'summary' ? { generation: 'one' } : { generation: 'two', record: { id: 'jd:1' } } });
- assert.equal(mismatch.stale, true);
- const wrongId = await readProductComparison(['jd:1'], { read: async r => r.op === 'summary' ? { generation: 'one' } : { generation: 'one', record: { id: 'tmall:1' } } });
- assert.ok(wrongId.items[0].error); assert.equal(wrongId.items[0].detail, undefined);
- });
|