import {chromium} from 'file:///C:/Users/JSHY/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/index.mjs'; import fs from 'node:fs/promises'; import assert from 'node:assert/strict'; const base='http://127.0.0.1:4183'; const out='docs/development-board-20261108'; await fs.mkdir(out,{recursive:true}); const browser=await chromium.launch({executablePath:'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',headless:true}); const report={ok:false,checkedAt:new Date().toISOString(),base,layouts:[],checks:[],pageErrors:[],failedResponses:[], realHardware:false,responseOverrides:0,paidCalls:0,productionWrites:0}; let current; const wait=async p=>{ await p.locator('industry-development .dr-intro').waitFor(); await p.waitForFunction(async()=>{const p=document.querySelector('kf-app')?.renderRoot.querySelector('view-industry');if(!p||p._loading||!p._data)return false;await p.updateComplete;return !p._error;}); }; const dimensions=async(p,width,section)=>{ const metrics=await p.evaluate(()=>({innerWidth,clientWidth:document.documentElement.clientWidth,scrollWidth:document.documentElement.scrollWidth})); assert.equal(metrics.innerWidth,width);assert.ok(metrics.scrollWidth<=metrics.clientWidth,JSON.stringify(metrics)); const bad=await p.locator('industry-development').evaluate(root=>[...root.renderRoot.querySelectorAll('*')].filter(e=>{ if(e.closest('dialog:not([open])'))return false; const r=e.getBoundingClientRect();return r.width>0&&r.height>0&&(r.left< -1||r.right>document.documentElement.clientWidth+1); }).map(e=>({tag:e.tagName,cls:e.className,text:e.textContent.slice(0,60)})).slice(0,10)); assert.deepEqual(bad,[],section+' '+width);report.layouts.push({width,section,...metrics,outOfBounds:bad.length}); }; const check=name=>{report.checks.push(name);console.log('PASS '+name);}; try{ for(const [width,height,mobile] of [[1440,900,false],[1024,768,false],[768,1024,false],[430,932,true],[390,844,true],[360,800,true],[320,568,true],[844,390,true]]){ const context=await browser.newContext({viewport:{width,height},isMobile:mobile,hasTouch:mobile,permissions:['clipboard-read','clipboard-write'],deviceScaleFactor:1}); const p=await context.newPage();current=p; p.on('pageerror',e=>report.pageErrors.push(e.message)); p.on('response',r=>{if(r.status()>=400)report.failedResponses.push({url:r.url(),status:r.status()});}); await p.goto(base+'/industry?tab=development');await wait(p); assert.equal(await p.locator('[data-development-direction]').count(),4); assert.equal(await p.locator('industry-development blockquote').count(),2); if([1440,390,320].includes(width))await p.screenshot({path:out+'/directions-'+width+'.png'}); for(const tab of ['directions','categories','processes','materials','standards']){ await p.locator('[data-development-tab='+tab+']').click(); await dimensions(p,width,tab); const counts={categories:16,processes:3,materials:14,standards:10}; if(tab==='categories')assert.equal(await p.locator('.dr-axis .dr-category').count(),12); if(['processes','materials','standards'].includes(tab))assert.equal(await p.locator('.dr-tab-content [data-reference]').count(),counts[tab]); if([1440,390].includes(width)&&['categories','materials','standards'].includes(tab))await p.screenshot({path:out+'/'+tab+'-'+width+'.png'}); } await p.locator('[data-development-tab=materials]').click(); await p.locator('[data-material-group="营养强化"]').click();assert.equal(await p.locator('.dr-material-grid>.dr-card').count(),2); await p.locator('[data-reference="fortifier-维生素B1"]').click(); await p.locator('.dr-detail[open]').waitFor();assert.match(await p.locator('.dr-detail').innerText(),/没有核实目标食品类别/); await dimensions(p,width,'source-dialog'); await p.locator('[data-close-reference]').click(); await p.locator('[data-material-group="全部"]').click(); await p.getByPlaceholder('搜索原料或作用').fill('硫胺素');assert.equal(await p.locator('.dr-material-grid>.dr-card').count(),1); await p.getByPlaceholder('搜索原料或作用').fill('无此原料');assert.equal(await p.locator('.dr-material-grid>.dr-card').count(),0); assert.match(await p.locator('.dr-empty').innerText(),/没有匹配/); await p.locator('[data-development-tab=directions]').click(); for(const id of ['spice','texture','nutrition','seasoning']){ await p.locator('[data-development-direction='+id+']').click(); assert.equal(await p.locator('industry-development blockquote').count(),id==='nutrition'?0:2); await dimensions(p,width,'direction-'+id); } await p.locator('[data-development-copy]').click(); const text=await p.evaluate(()=>navigator.clipboard.readText()); assert.ok(text.includes('KfMaterial/')&&text.includes('KfSource/')&&text.includes('3279276824734890')&&text.includes('待验证设想')); await p.locator('.dr-coverage>summary').click(); assert.match(await p.locator('.dr-coverage').innerText(),/快照/); await dimensions(p,width,'coverage'); if(mobile){ const controls=p.locator('industry-development button:visible'); for(let i=0;i=43.5,'touch target height'); } } check('five sections, four directions, references, filter, search, copy and layout '+width); if(width===1440){ await p.locator('industry-development a').filter({hasText:'查看原评'}).first().click(); await p.waitForURL(/\/library\/reviews\//); await p.locator('view-library').waitFor();check('review navigation validates the bound VOC generation'); } await context.close(); } assert.deepEqual(report.pageErrors,[]);assert.deepEqual(report.failedResponses,[]); report.ok=true; }catch(e){report.error=e.stack;console.error(e);if(current)await current.screenshot({path:out+'/failure.png'}).catch(()=>{});process.exitCode=1;} finally{await browser.close();await fs.writeFile(out+'/browser-acceptance.json',JSON.stringify(report,null,2)+'\n');}