| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- import test from 'node:test';
- import assert from 'node:assert/strict';
- import { workshopQuery, workshopPatch, workshopBrief, workshopResultView, WORKSHOP_RESULT_TABS } from '../src/core/industry-workshop.js';
- test('结果分页默认商品,保留旧版原评与市场链接的实际目的地', () => {
- assert.equal(workshopResultView({}), 'products');
- assert.equal(workshopResultView({w_view:'summary'}), 'products');
- assert.equal(workshopResultView({w_view:'missing'}), 'products');
- assert.equal(workshopResultView({w_view:'evidence'}), 'reviews');
- assert.equal(workshopResultView({w_view:'evidence',w_data:'products'}), 'products');
- assert.equal(workshopResultView({w_view:'market',w_market:'people'}), 'pains');
- assert.equal(workshopResultView({w_view:'market',w_market:'trend'}), 'trend');
- for (const [id] of WORKSHOP_RESULT_TABS) assert.equal(workshopResultView({w_view:id}), id);
- assert.equal(workshopQuery({w_view:'pains',w_brands:'2'}).theme,'');
- });
- test('研究多选在组内取或、清除时移除限定,并重置商品与原评页码', () => {
- const q = { w_format: 'bag', w_flavor: 'spicy,sour', w_products: '3' };
- assert.deepEqual(workshopQuery(q).format, ['bag']);
- assert.deepEqual(workshopQuery(q).flavor, ['spicy','sour']);
- assert.equal(workshopPatch(q,'format','bowl').w_format,'bag,bowl');
- assert.equal(workshopPatch(q,'format','bag').w_format,'');
- assert.equal(workshopPatch(q,'flavor','').w_flavor,'');
- assert.equal(workshopPatch(q,'flavor','local').w_products,'');
- assert.equal(workshopQuery({w_reviews:'2',w_product:'jd:1',w_theme:'seasoning',w_kind:'problem'}).reviewPage,2);
- assert.deepEqual(workshopQuery({w_nutrition:'nonfried,protein',w_portion:'small',w_need:'value'}).nutrition,['nonfried','protein']);
- assert.deepEqual(workshopQuery({w_nutrition:'nonfried',w_portion:'small',w_need:'value'}).need,['value']);
- assert.equal(workshopPatch({w_nutrition:'nonfried'},'nutrition','protein').w_nutrition,'nonfried,protein');
- });
- test('分析复制保留版本、选项、完整引用,重复证据不反复添加', () => {
- const review={reviewId:'jd:1:r1',productId:'jd:1',sourceRecordId:'source-1'};
- const d={generation:'g1',rulesVersion:'v1',choices:{format:['bag']},scope:{products:1,reviewRows:2,evidenceUnits:1,eligibleRows:0},products:{rows:[{productId:'jd:1',title:'拌面'}]},reviewEvidence:{rows:[review]},themes:[{name:'口味',types:{problem:1,benefit:0,wish:0},qualifiedUnits:0}],opportunities:[{title:'调味控制',supportUnits:1,qualifiedUnits:0,action:'核原件',support:[review]}],motives:[],audiences:[],scenarios:[],trend:{note:'暂无趋势',noteTimeline:'不是销量'}};
- const text=workshopBrief(d,{category:'banmian'});
- const refs=text.split('\n').filter(s=>s.startsWith('{')).map(s=>JSON.parse(s));
- assert.equal(refs.length,2);
- assert.equal(refs.find(r=>r.entity==='reviews').id,'jd:1:r1');
- assert.equal(refs.find(r=>r.entity==='products').title,'拌面');
- assert.match(text,/generation:g1/);assert.match(text,/"format":\["bag"\]/);
- assert.match(text,/非全量导出/);assert.doesNotMatch(text,/jd:jd:/);
- assert.throws(()=>workshopBrief({}),/UNAVAILABLE/);
- });
- test('复制保留关键词、原文筛选和重复关联编号,不把其他关联的来源冒充主来源', () => {
- const review={reviewId:'jd:1:a',productId:'jd:1',sourceRecordId:'source-a',associationIds:['jd:1:a','jd:2:a'],content:'太辣,希望分次投料',appendContent:'少放一些合适',analysisEligible:false};
- const d={generation:'g1',rulesVersion:'v1',choices:{},filterPolicy:{keyword:'小龙虾',reviewSelection:{theme:'seasoning',kind:'problem'}},scope:{products:2,reviewRows:2,evidenceUnits:1,eligibleRows:0},products:{rows:[]},reviewEvidence:{rows:[review]},themes:[],opportunities:[],motives:[],audiences:[],scenarios:[],trend:{note:'不能判断市场增长',noteTimeline:'不是销量'},prices:{groups:[{date:'2026-11-01',currency:'CNY',basis:'listed',minMinor:1000,maxMinor:1000,products:1,conflicts:0,examples:[{recordId:'price-1',productId:'jd:1',title:'拌面'}]}]}};
- d.claims=[{label:'香辣',products:1,examples:['jd:30']}];
- const text=workshopBrief(d);
- const refs=text.split('\n').filter(s=>s.startsWith('{')&&s.includes('"database"')).map(s=>JSON.parse(s));
- assert.match(text,/商品关键词:小龙虾/);assert.match(text,/"theme":"seasoning"/);
- assert.match(text,/太辣,希望分次投料/);assert.match(text,/少放一些合适/);
- assert.equal(refs.find(r=>r.id==='jd:1:a').source_record_id,'source-a');
- assert.equal(refs.find(r=>r.id==='jd:2:a').source_record_id,undefined);
- assert.equal(refs.find(r=>r.id==='price-1').productId,'jd:1');
- assert.ok(refs.some(r=>r.entity==='products'&&r.id==='jd:30'));
- });
- test('复制决策包含业务假设、验证条件、优势与不在当前页的依据和竞品编号', () => {
- const r={reviewId:'jd:9:r',productId:'jd:9',sourceRecordId:'src-r',associationIds:['jd:9:r','jd:10:r'],content:'太辣',analysisEligible:false};
- const strength={reviewId:'jd:8:b',productId:'jd:8',sourceRecordId:'src-b',content:'面条筋道',analysisEligible:true};
- const o={name:'调味更可控',status:'先核关键线索',supportUnits:1,products:2,qualifiedUnits:0,pendingUnits:1,adjustmentUnits:0,concept:'比较分次投料',businessValue:'降低尝试门槛',test:{method:'核说明后对照',measure:'辣咸接受度',decisionRule:'先改指引再研究配方'},preserve:'保留特色风味',unknown:'实际投料量未知',representatives:[{productId:'jd:9',title:'拌面9'}],supply:[{label:'香辣',products:1,denominator:20,examples:[{productId:'jd:20',title:'香辣面'}]}],evidenceIds:['jd:9:r'],evidence:[r],benefits:[],adjustments:[],segments:[]};
- const d={generation:'g2',rulesVersion:'v2',choices:{},scope:{products:20,reviewRows:30,evidenceUnits:18,eligibleRows:4},products:{rows:[]},reviewEvidence:{rows:[]},themes:[],opportunities:[],motives:[],audiences:[],scenarios:[],trend:{note:'不能估市场增长',noteTimeline:'非销量'},decisions:{headline:'优先研究:调味更可控',reason:'先核依据',ordering:'仅为研究顺序',directions:[o],strengths:[{name:'口感',units:10,qualifiedUnits:1,preserve:'保留筋道',examples:[strength]}],brandThemes:[{name:'调味',brands:[{brand:'ksf',supportUnits:1,qualifiedSupportUnits:0,benefitUnits:2}]}],limits:['业务作用待验证']}};
- d.claims=[{label:'香辣',products:1,examples:['jd:30']}];
- const text=workshopBrief(d);
- d.decisions.eligibleUnits=3;d.scope.reviewedProducts=5;
- assert.match(workshopBrief(d),/评价覆盖:5\/20件/);
- assert.match(workshopBrief(d),/去重可读依据:3组/);
- assert.match(text,/本轮产品判断\n优先研究/);
- assert.match(text,/预期业务作用(待验证):降低尝试门槛/);
- assert.match(text,/决策条件:先改指引再研究配方/);
- assert.match(text,/合格0组、待确认1组/);
- assert.match(text,/保留筋道/);assert.match(text,/太辣/);
- assert.match(text,/不能证明已解决问题或市场空白/);
- const refs=text.split('\n').filter(s=>s.startsWith('{')&&s.includes('"database"')).map(s=>JSON.parse(s));
- for(const id of ['jd:9','jd:20','jd:9:r','jd:10:r','jd:8','jd:8:b','jd:30'])assert.ok(refs.some(r=>r.id===id),id);
- assert.equal(refs.find(r=>r.id==='jd:9:r').source_record_id,'src-r');
- assert.equal(refs.find(r=>r.id==='jd:10:r').source_record_id,undefined);
- });
|