'use strict'; const assert=require('node:assert/strict'),SS=require('../js/skin-score'),UI=require('../js/report-ui'),Copy=require('../js/report-copy'); const keys=['contour','wrinkles','color','smooth','water','sens','acne']; function sample(scores,focus='firm'){ const vm=SS.buildViewModel(structuredClone(SS.MOCK_RESULT),SS.MOCK_SIDE,{}); for(const k of ['contour','wrinkles','smooth','sens','acne']){vm.cats[k].P=scores[k];vm.cats[k].level=scores[k]==null?null:scores[k]<80?'预警':scores[k]<90?'改善':'良好';} Object.assign(vm.cats.tone.vars,{melanin:scores.color,color_score:scores.color,water_score:scores.water,water_sev:0}); vm.cats.tone.vars.tone_scoring.color_score=scores.color; vm.cats.acne.vars.acne_counts={closed_comedones:0,acne:0,acne_pustule:0,acne_nodule:0,acne_mark:0}; vm.cats.acne.vars.acne_cnt=0; for(const dim of ['firm','vita','stab'])vm.dims[dim].P=focus==null?null:dim===focus?10:99; const before=JSON.stringify(vm),ui=UI.build(vm,SS.MOCK_RESULT);assert.equal(JSON.stringify(vm),before); return{vm,ui}; } function check(values,focus,expected){const scores=Object.fromEntries(keys.map((k,i)=>[k,values[i]])),x=sample(scores,focus);assert.deepEqual(x.ui.care.map(v=>v.key),expected);assert(x.ui.care.length<=3);for(const c of x.ui.care){assert.equal(c.text,Copy.care[c.key][c.level].care+Copy.care[c.key][c.level].lifestyle);assert.equal(c.priority,c.dim===focus);}return x;} check([20,10,30,90,95,92,99],'firm',['wrinkles','contour','color']); check([30,95,10,90,20,99,98],'firm',['contour','color','water']); check([90,30,10,20,95,96,99],'firm',['wrinkles','color','smooth']); check([99,98,40,30,20,97,96],'vita',['water','smooth','color']); check([95,96,10,20,30,90,99],'firm',['color','smooth','water']); check([80,80,80,80,80,80,80],'stab',['sens','acne','contour']); check([80,80,80,80,80,80,80],null,['contour','wrinkles','color']); check([79.999,79.998,79.997,99,99,99,99],'firm',['wrinkles','contour','color']); check([null,null,50,null,60,null,null],'firm',['color','water']); check([null,null,null,null,null,null,null],null,[]); const x=check([99,98,79.99,99,90,99,99],'vita',['color','water','wrinkles']); assert.equal(x.ui.views.find(v=>v.key==='color').level,'优秀');assert.equal(x.ui.views.find(v=>v.key==='water').level,'优秀'); assert.equal(x.ui.careRule,'seven-lowest-three-focus-first-v1'); const heavy=sample(Object.fromEntries(keys.map(k=>[k,95])),'stab');heavy.vm.cats.acne.vars.acne_counts.acne_nodule=1;heavy.vm.cats.acne.vars.acne_cnt=1; assert.equal(UI.build(heavy.vm,{}).views.find(v=>v.key==='acne').level,'优秀'); assert(UI.build(heavy.vm,{}).views.find(v=>v.key==='acne').text.includes('结节')); assert(!Copy.care.wrinkles['改善'].lifestyle.startsWith('保证睡眠')); console.log('PASS care: global lowest3, focus-first selected only, two/one/no focus members, tie/document order, raw precision, missing, independent color/water, acne guard, exact copy and immutable scores');