| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- import fs from 'node:fs/promises';
- import path from 'node:path';
- import assert from 'node:assert/strict';
- import { pathToFileURL } from 'node:url';
- const out = path.resolve('docs/workshop-argument-quality-20261111');
- const raw = JSON.parse(await fs.readFile(path.join(out,'example-fixture.json'),'utf8'));
- const empty = structuredClone(raw.artifact[0]);
- empty.objectId='no-quotes-preview';empty.report.evidence={};
- empty.report.chapters=[{id:'product-proposal',title:'旧报告未保存引文',sections:[{kind:'para',text:'这是旧报告正文,不是原始引文。'}]}];
- raw.artifact.push(empty);
- const origin='http://127.0.0.1:4181';
- const {chromium}=await import(pathToFileURL(path.resolve('work/workshop-manual-tools/node_modules/playwright/index.mjs')).href);
- const browser=await chromium.launch({headless:true,executablePath:'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe'});
- const checks=[],errors=[],actions=[];
- try {
- const context=await browser.newContext({viewport:{width:1280,height:900}});
- await context.route('**/*',route=>{
- const request=route.request(),url=new URL(request.url());
- if(url.pathname==='/api/functions'||url.pathname==='/__dev/member-groups') {
- const body=request.postDataJSON();actions.push(body?.path);
- const data=body?.path==='/ksfGetPublicBoard'?raw:body?.path==='/ksfGetPublicMemberGroups'?{schema:'ksf.workshop-member-groups.v1',groups:[],members:[]}:null;
- if(!data){errors.push('Unexpected API action: '+body?.path);return route.abort();}
- return route.fulfill({contentType:'application/json',body:JSON.stringify({result:{ok:true,data}})});
- }
- if(url.origin===origin&&request.method()==='GET')return route.continue();
- errors.push('Unexpected network request: '+url.origin+url.pathname);return route.abort();
- });
- const page=await context.newPage();page.on('pageerror',error=>errors.push(error.message));
- for(const width of [1280,390]) {
- await page.setViewportSize({width,height:1000});
- await page.goto(origin+'/report/argument-preview?mode=sample');
- await page.locator('[data-evidence-reading]').waitFor();
- assert.equal(await page.locator('.finding .evidence-excerpt').count(),3);
- assert.equal(await page.locator('[data-evidence-reading] .evidence-excerpt').count(),3);
- const allText=await page.locator('[data-evidence-reading]').innerText();
- for(const evidence of Object.values(raw.artifact[0].report.evidence))assert.ok(allText.includes(evidence.quotes[0].text));
- for(const link of await page.locator('.evidence-caption a').all())assert.match(await link.getAttribute('href'),/^https:\/\//);
- assert.equal(await page.locator('.evidence-more').evaluate(el=>el.open),false);
- const dimensions=await page.evaluate(()=>({width:innerWidth,scrollWidth:document.documentElement.scrollWidth}));
- assert.ok(dimensions.scrollWidth<=dimensions.width,JSON.stringify(dimensions));
- await page.locator('.finding').first().scrollIntoViewIfNeeded();
- await page.screenshot({path:path.join(out,'report-evidence-'+width+'.png')});
- checks.push(width+'px:关键判断旁原句、全部依据、原始链接和窄屏布局');
- }
- await page.locator('.finding .evidence-caption button').first().click();
- await page.locator('kf-drawer .panel').waitFor();
- const sourceText=await page.locator('kf-drawer .panel').innerText();
- assert.ok(sourceText.replace(/\s/g,'').includes('R05京东三味六碗商品评价'),sourceText);
- await page.keyboard.press('Escape');
- await page.locator('kf-drawer .panel').waitFor({state:'hidden'});
- checks.push('原句旁来源记录按钮可打开对应记录并返回');
- await page.locator('.finding [data-anchor]').first().click();
- const drawer=page.locator('kf-drawer .panel');
- await drawer.waitFor();
- assert.ok((await drawer.innerText()).includes(raw.artifact[0].report.evidence.R05.quotes[0].text));
- checks.push('证据链仍可打开,对应原句与正文一致');
- await page.goto(origin+'/report/no-quotes-preview?mode=sample');
- await page.locator('[data-evidence-reading]').waitFor();
- assert.equal(await page.locator('.evidence-excerpt').count(),0);
- assert.ok((await page.locator('[data-evidence-reading]').innerText()).includes('尚未保存'));
- checks.push('无引文旧报告明确缺失,不由摘要补造证言');
- await page.goto(origin+'/docs/workshop-argument-quality-20261111/'+encodeURIComponent('报告内容修订示例.html'));
- for(const source of raw.source)assert.ok((await page.locator('body').innerText()).includes(source.rawText));
- for(const link of await page.locator('a[href$=".json"]').all()) {
- const response=await page.request.get(new URL(await link.getAttribute('href'),page.url()).href);
- assert.equal(response.status(),200);
- }
- await page.screenshot({path:path.join(out,'content-example-390.png'),fullPage:true});
- checks.push('独立HTML示例保留逐字原句,本地原记录链接可读取');
- assert.deepEqual(errors,[]);
- assert.ok(actions.every(action=>['/ksfGetPublicBoard','/ksfGetPublicMemberGroups'].includes(action)));
- await fs.writeFile(path.join(out,'browser-verification.json'),JSON.stringify({ok:true,checks,errors,actions,fixtureOnly:true,productionWrites:0},null,2)+'\n');
- console.log(JSON.stringify({ok:true,checks,errors,fixtureOnly:true,productionWrites:0}));
- } finally {await browser.close();}
|