// Explicit private case; render only, no backend mutations or paid API calls. import assert from 'node:assert/strict'; import fs from 'node:fs';import path from 'node:path'; import {execSync} from 'node:child_process'; import {fileURLToPath,pathToFileURL} from 'node:url'; import {createRequire} from 'node:module'; const require=createRequire(import.meta.url),SS=require('../js/skin-score'); const dir=process.env.H5_PIGMENTATION_CASE_DIR;assert(dir,'set private case directory'); const raw=JSON.parse(fs.readFileSync(path.join(dir,'raw.json'))); const photo='data:image/jpeg;base64,'+fs.readFileSync(path.join(dir,'front.jpg')).toString('base64'); const vm=SS.buildViewModel(raw.result,{left:raw.left_side_result,right:raw.right_side_result},{realAge:24,skinType:'混合偏油肌肤'}); assert.equal(raw.result.brown_spot.count,81);assert.equal(raw.result.freckle.value,0); const audit=vm.cats.tone.vars.tone_scoring; assert(Math.abs(audit.color_score-(audit.pigment_adjusted_score*.8+audit.dark_circle_score*.2))<1e-9); const {chromium}=await import(pathToFileURL(execSync('npm root -g',{encoding:'utf8'}).trim()+'/playwright/index.mjs').href); const browser=await chromium.launch(); try { const page=await browser.newPage({viewport:{width:375,height:812},isMobile:true,hasTouch:true});const errors=[]; page.on('pageerror',e=>errors.push(e.message)); await page.route('**/api/**',r=>{assert.equal(r.request().method(),'GET');return r.fulfill({json:{ok:true,user:{kind:'browser'}}});}); const source=fs.readFileSync(fileURLToPath(new URL('../js/app.js',import.meta.url)),'utf8'); await page.route('**/js/app.js*',r=>r.fulfill({contentType:'text/javascript',body:source.replace(/\}\)\(\);\s*$/,` window.__renderCase=function(x){renderReport(x.vm,x.photo,null,x.raw);showScreen('s-report');}; })();`)})); await page.goto(process.env.H5_BASE_URL||'http://127.0.0.1:8080/'); await page.evaluate(x=>window.__renderCase(x),{vm,photo,raw}); await page.locator('#viz-tone').scrollIntoViewIfNeeded(); await page.waitForFunction(()=>{const i=document.querySelector('#viz-tone');return i.naturalWidth&&!i.hidden&&i.dataset.overlayAlpha==='0.3';}); assert.equal(await page.locator('#tone-detections').count(),0,'detection status overlay removed'); assert.equal(await page.locator('#tone-map-note').count(),0,'technical caption removed'); assert(vm.cats.tone.vars.spot_flag.includes('褐色斑81处')); const dcDescriptions=['无明显黑眼圈','仅存在轻度黑眼圈','存在中度黑眼圈','可见明显黑眼圈']; assert((await page.locator('#tx-tone').textContent()).includes(dcDescriptions[raw.result.dark_circle_severity.value])); assert(!(await page.locator('#tx-tone').textContent()).includes('占肤色项20%')); await page.locator('#viz-tone').locator('xpath=ancestor::div[contains(@class,"card-detail")][1]').screenshot({path:path.join(dir,'pigmentation-81-color.png')}); // Display-only example, explicitly synthetic; real downloaded case is unchanged. const example=structuredClone(vm);example.skinAgeRaw=40;example.realAge=25;example.skinAgeDisplay=40; await page.evaluate(x=>window.__renderCase(x),{vm:example,photo,raw}); assert.equal(await page.locator('#stat-age b').textContent(),'30'); assert.equal(await page.locator('#stat-age-note').textContent(),'比实际年龄大5岁'); assert.equal(example.skinAgeRaw,40); assert.deepEqual(errors,[]); console.log(JSON.stringify({case:'R20261014-155810-LFB8',brownSpots:81,freckle:0,audit,toneP:vm.cats.tone.P,toneS:vm.cats.tone.S,vita:vm.dims.vita.S,total:vm.total,tests:'PASS; render only; original case unchanged'})); }finally{await browser.close();}