import test from 'node:test'; import assert from 'node:assert/strict'; import { libraryMaterial, addLibraryMaterials, restoreLibrarySelection, libraryMaterialsText, librarySelectionPath, withoutLibrarySelectionQuery, LIBRARY_SELECTION_LIMIT } from '../src/core/library-selection.js'; test('多选按资料类型和完整ID去重,政策编号不要求平台前缀', () => { const document = libraryMaterial({ id: 'GB14880-2012', title: '标准' }, 'documents'); const clause = libraryMaterial({ id: 'GB14880-2012' }, 'clauses'); assert.equal(addLibraryMaterials([document], [document, clause]).items.length, 2); assert.equal(libraryMaterial({ id: '' }, 'products'), null); assert.equal(libraryMaterial({ id: 'x' }, 'not-a-type'), null); assert.equal(libraryMaterial({ id: 'jd:1\nnew-task' }, 'products'), null); }); test('跨页追加保留每条选取条件,达到上限不悄悄丢掉已有选择', () => { const context = { filters: { brand: 'ksf' }, quality: 'audit' }; const product = libraryMaterial({ id: 'jd:123' }, 'products', context); context.filters.brand = 'changed'; const social = libraryMaterial({ id: 'bilibili:123' }, 'social', { filters: {}, quality: 'analysis' }); const { items } = addLibraryMaterials([product], [social]); assert.equal(items[0].context.filters.brand, 'ksf'); assert.equal(items[1].context.quality, 'analysis'); const full = Array.from({ length: LIBRARY_SELECTION_LIMIT }, (_, i) => libraryMaterial({ id: `jd:${i}` }, 'products')); const result = addLibraryMaterials(full, [social]); assert.equal(result.items.length, LIBRARY_SELECTION_LIMIT); assert.equal(result.skipped, 1); assert.deepEqual(result.items, full); }); test('刷新恢复选择,代际变化清空,损坏的浏览器保存不当成有效资料', () => { const items = [libraryMaterial({ id: 'jd:123', source_record_id: 'source-1' }, 'products')]; const saved = JSON.stringify({ generation: 'g1', items }); assert.deepEqual(restoreLibrarySelection(saved, 'g1'), { items, stale: false }); assert.deepEqual(restoreLibrarySelection(saved, 'g2'), { items: [], stale: true }); assert.deepEqual(restoreLibrarySelection('{broken', 'g1'), { items: [], stale: false }); }); test('复制仅包含资料名称与数据库定位键,保留完整ID和版本,省去提示词', () => { const review = libraryMaterial({ record_id: 'jd:123:r1', title: '含换行\n标题', content: '真'.repeat(800), product_id: 'jd:123', source_record_id: 'source-1', is_default: null, rating_scale: null, token: 'MUST_NOT_COPY' }, 'reviews', { filters: { productId: 'jd:123' }, quality: 'audit' }); const report = libraryMaterial({ id: 'artifact-1', title: '报告', updatedAt: '2026-11-07' }, 'reports'); const text = libraryMaterialsText([review, report], { generation: 'g1' }); const rows = text.split('\n').filter(line => line.startsWith('{')).map(JSON.parse); assert.equal(rows.length, 2); assert.equal(rows[0].id, 'jd:123:r1'); assert.equal(rows[0].title, '含换行\n标题'); assert.ok(text.includes('generation:g1')); assert.equal(rows[0].source_record_id, 'source-1'); assert.equal(rows[0].productId, 'jd:123'); assert.deepEqual(Object.keys(rows[0]).sort(), ['database', 'entity', 'id', 'productId', 'source_record_id', 'title', 'type'].sort()); assert.equal(rows[1].className, 'KfArtifact'); assert.equal(rows[1].objectId, 'artifact-1'); assert.equal(rows[1].database, 'workshop'); assert.equal(rows[1].updatedAt, '2026-11-07'); for (const phrase of ['员工', '请返回', '请你', '查库要求', '分析要求', 'ksf-voc-library', 'workshop-read', 'MUST_NOT_COPY', 'jd:jd:', 'selectionContext', 'previewNote', 'selectedData']) assert.ok(!text.includes(phrase), phrase); assert.ok(text.length < 700); assert.throws(() => libraryMaterialsText([], { generation: 'g1' })); }); test('行业监测转入精确商品及版本,清理旧对比参数后保留浏览范围', () => { const url = new URL(librarySelectionPath(['jd:123', 'jd:123', 'tmall:456'], 'g1'), 'http://localhost'); assert.deepEqual(JSON.parse(url.searchParams.get('selectProducts')), ['jd:123', 'tmall:456']); assert.equal(url.searchParams.get('selectionGeneration'), 'g1'); assert.deepEqual(withoutLibrarySelectionQuery({ compare: '["jd:123"]', comparing: '1', selectProducts: '[]', selectionGeneration: 'g1', type: 'products', brand: 'ksf' }), { type: 'products', brand: 'ksf' }); });