| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import fs from 'node:fs/promises';
- import path from 'node:path';
- import assert from 'node:assert/strict';
- import {pathToFileURL} from 'node:url';
- import {chromium} from '../work/workshop-manual-tools/node_modules/playwright/index.mjs';
- const root=path.resolve('docs/workshop-quality-r13-20261110');
- const prompts=JSON.parse(await fs.readFile(path.join(root,'prompts-and-outputs.json'),'utf8')).steps;
- const browser=await chromium.launch({headless:true,executablePath:'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe'});
- const context=await browser.newContext({permissions:['clipboard-read','clipboard-write']});
- const page=await context.newPage();
- const errors=[];page.on('pageerror',e=>errors.push(e.message));
- const cases=[];
- async function overflow(name){
- const d=await page.evaluate(()=>({viewport:innerWidth,width:document.documentElement.scrollWidth}));
- assert.ok(d.width<=d.viewport,name+' '+JSON.stringify(d));
- }
- try{
- let copies=0,exact=0,sampleLinks=0;
- for(const rel of ['康师傅工作坊操作手册-r13本地修订.html','manual/index.html']){
- await page.goto(pathToFileURL(path.join(root,rel)).href);
- assert.equal(await page.locator('.nav-item').count(),15);
- for(const width of [1440,390]){
- await page.setViewportSize({width,height:1000});
- for(const s of prompts){
- await page.evaluate(id=>location.hash=id,s.id);
- await page.waitForFunction(id=>document.querySelector('.nav-item[aria-current="step"]')?.getAttribute('href')==='#'+id,s.id);
- assert.equal(await page.locator('#prompt-text').textContent(),s.fullPrompt,s.id);exact++;
- assert.ok(await page.locator('#prompt-text').isVisible());
- assert.equal(await page.locator('.action-copy').count(),0);
- await page.locator('#copy-prompt').click();
- const text=await page.evaluate(()=>navigator.clipboard.readText());
- assert.equal(text.replaceAll('\r\n','\n'),s.fullPrompt.replaceAll('\r\n','\n'));copies++;
- if(s.example){
- const links=await page.locator('.example-link a').evaluateAll(els=>els.map(el=>el.href));
- assert.equal(links.length,2,s.id);
- assert.equal(links[0],pathToFileURL(path.join(root,s.example)).href);sampleLinks++;
- }
- await overflow(rel+' '+s.id+' '+width);
- }
- if(!rel.startsWith('manual/')){
- await page.evaluate(()=>location.hash='matrix');
- await page.waitForFunction(()=>document.querySelector('#prompt-text').textContent.includes('需求与具体供给'));
- await page.screenshot({path:path.join(root,`手册-${width}.png`),fullPage:true});
- }
- }
- }
- cases.push({check:'all-prompts-exact-visible-and-copyable',comparisons:exact,copies,sampleLinks,passed:true});
- const reports=(await fs.readdir(path.join(root,'reports'))).filter(n=>n.endsWith('.html')).map(n=>'reports/'+n);
- const others=['index.html','案例报告合集.html','旧稿逐项复核.html','参考学习与类型对应.html','选材与分析规则.html','证据底表.html','商业回推演算器.html'];
- for(const rel of [...reports,...others]){
- await page.goto(pathToFileURL(path.join(root,rel)).href);
- for(const width of [1440,390]){
- await page.setViewportSize({width,height:1000});await overflow(rel+' '+width);
- if(['index.html','reports/proposal.html','reports/matrix.html','商业回推演算器.html'].includes(rel))
- await page.screenshot({path:path.join(root,rel.replaceAll('/','-').replace('.html','')+`-${width}.png`),fullPage:rel!=='index.html'});
- }
- }
- cases.push({check:'all-local-report-pages-fit-desktop-and-mobile',pages:reports.length+others.length,widths:[1440,390],passed:true});
- await page.goto(pathToFileURL(path.join(root,'商业回推演算器.html')).href);
- assert.match(await page.locator('#model-state').textContent(),/输入未齐/);
- assert.equal(await page.evaluate(()=>typeof window.modelResult),'undefined');
- await page.locator('#example').click();
- const result=await page.evaluate(()=>window.modelResult);
- assert.equal(result.value,50);assert.equal(result.breakEven,2000);assert.equal(result.origin,'synthetic');assert.equal(result.empiricalVerified,false);
- assert.equal(await page.locator('#sensitivity tbody tr').count(),5);
- await page.locator('#Rn').fill('0');
- assert.equal(await page.evaluate(()=>window.modelResult.breakEven),null);
- await page.locator('#Qn').fill('0.5');
- assert.match(await page.locator('#model-state').textContent(),/非负整数/);
- await page.locator('#reset').click();
- assert.match(await page.locator('#model-state').textContent(),/输入未齐/);
- assert.equal(await page.locator('input').evaluateAll(els=>els.every(el=>el.value==='')),true);
- cases.push({check:'blank-financial-model-and-explicit-synthetic-sensitivity',passed:true,companyDataUsed:false});
- await page.setViewportSize({width:1440,height:1000});
- await page.goto(pathToFileURL(path.join(root,'reports/proposal.html')).href);
- const r05=page.locator('article a', {hasText:'R05'}).first();
- await r05.click();assert.match(page.url(),/证据底表\.html#R05|%E8%AF%81%E6%8D%AE%E5%BA%95%E8%A1%A8\.html#R05/);
- assert.match(await page.locator('#R05').textContent(),/R05/);
- cases.push({check:'proposal-citation-opens-exact-raw-quote',passed:true});
- assert.deepEqual(errors,[]);
- const resultFile={ok:true,cases,scriptErrors:errors,productionWrites:0,hostActualLoading:false,realEmployeeTrial:false,completeCourseEmpiricalAcceptance:false};
- await fs.writeFile(path.join(root,'浏览器核验.json'),JSON.stringify(resultFile,null,2)+'\n');
- console.log(JSON.stringify(resultFile));
- }finally{await browser.close()}
|