39 lines
5.7 KiB
JavaScript
39 lines
5.7 KiB
JavaScript
const {chromium}=require(process.env.PLAYWRIGHT_MODULE || 'playwright');
|
|
const fs=require('fs');const path=require('path');
|
|
const adapter=path.resolve(__dirname,'..');
|
|
const web=process.env.PIGWAY_WEB_ROOT || path.resolve(adapter,'../pigway-web-manager/web');
|
|
const output=adapter+'/.data/audit-validation';fs.mkdirSync(output,{recursive:true});
|
|
(async()=>{const browser=await chromium.launch({headless:true});const page=await browser.newPage();let errors=[];page.on('pageerror',e=>errors.push(e.message));
|
|
await page.route('http://audit.local/**',async route=>{const u=new URL(route.request().url());let body,type='text/javascript';
|
|
if(u.pathname==='/'){type='text/html';body=`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="/assets/css/base.css"><link rel="stylesheet" href="/assets/css/layout.css"><link rel="stylesheet" href="/assets/css/controls.css"><link rel="stylesheet" href="/plugin/styles.css"><main id="cards"></main><script type="module">import {agentHostCard} from '/plugin/overview.js';import {state} from '/assets/js/state.js';window.render=(lang,plugins={})=>{state.LANG=lang;document.querySelector('#cards').innerHTML=agentHostCard({host:{id:'gateway',name:'Gateway'},online:true,status:{version:'3.11.2',machine:{id:'gateway',name:'家庭网关 100%',hostname:'gateway'},device:{model:'Raspberry Pi 4',os:'Debian 13',architecture:'aarch64',cpu_count:4},system:{cpu_percent:12,memory_percent:25,temperature_c:42,cpu_freq_mhz:1500,memory_used_bytes:1000000,memory_total_bytes:4000000,memory_available_bytes:3000000,storage_inventory:[]},network:{interface:'eth0',kind:'ETH',link_speed_mbps:1000,link:true,ip_label:'IP4',ip:'192.168.1.2',rx_bytes_per_second:10,tx_bytes_per_second:20},display:{owner:'DISK_CRITICAL',alerts:[{id:'DISK_CRITICAL'}]},plugins,watches:[]}})};render('zh');</script>`;}
|
|
else if(u.pathname==='/assets/js/state.js')body='export const state={LANG:"zh"};';
|
|
else if(u.pathname==='/assets/js/i18n.js')body='export const tr=x=>x;';
|
|
else if(u.pathname==='/assets/js/overview.js'){let source=fs.readFileSync(web+'/js/overview.js','utf8');body='import {state as appState} from "/assets/js/state.js";\n'+source.slice(source.indexOf('export function bytes'),source.indexOf('export const connectionLabels')); }
|
|
else if(u.pathname==='/plugin/hardware.js')body='export const fanMetric=()=>"";export const pluginSummary=()=>"";';
|
|
else {let file=u.pathname.startsWith('/plugin/')?adapter+'/plugin/ui/'+u.pathname.slice(8):web+'/'+u.pathname.replace('/assets/','');if(!fs.existsSync(file))throw Error(file);body=fs.readFileSync(file);if(file.endsWith('.css'))type='text/css';}
|
|
await route.fulfill({status:200,contentType:type,body});});
|
|
await page.goto('http://audit.local/');await page.waitForFunction(()=>typeof window.render==='function');
|
|
for(const [name,width,height] of [['desktop',1440,1000],['tablet',768,1024],['mobile',390,844]]){await page.setViewportSize({width,height});for(const lang of ['zh','en']){await page.evaluate(lang=>render(lang),lang);await page.waitForTimeout(100);const text=await page.locator('body').innerText();if(!text.includes(lang==='zh'?'主要告警':'Primary alert'))throw Error('Missing label');if(text.includes('显示状态'))throw Error('Old label');if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('Overflow '+name);await page.screenshot({path:output+'/'+name+'-'+lang+'.png',fullPage:true});}}
|
|
const hardware={hat:{name:'Yahboom RGB Cooling HAT',online:true,capabilities:{display:true,rgb:true},status:{available:true,oled_page:'NORMAL_HOME',rgb_mode:'OFF'}}};
|
|
for(const width of [1440,768,390]){
|
|
await page.setViewportSize({width,height:1000});
|
|
await page.evaluate(p=>render('zh',p),hardware);
|
|
const primary=page.locator('[data-refresh-group="display"]');
|
|
if((await primary.locator('.value').innerText())!=='OLED 正常主页 · RGB 全灭')throw Error('Merged OLED/RGB text');
|
|
if((await primary.locator('.pi-alert-heading .semantic-status').innerText())!=='正常')throw Error('Missing hardware normal status');
|
|
if((await primary.locator('.pi-alert-heading .semantic-status').getAttribute('data-semantic'))!=='normal')throw Error('Hardware status must use normal blue');
|
|
if(await page.locator('[data-manage-plugin-host]').count())throw Error('Overview must not expose plugin management');
|
|
if(await page.locator('.group.action-row').count())throw Error('Standalone hardware row remains');
|
|
if(!(await primary.innerText()).includes('Yahboom RGB Cooling HAT'))throw Error('Hardware name missing');
|
|
if(!(await primary.locator('.pi-alert-heading').evaluate(n=>Math.abs(n.lastElementChild.getBoundingClientRect().right-n.getBoundingClientRect().right)<1)))throw Error('Hardware status is not right aligned');
|
|
if(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth))throw Error('Merged display overflow');
|
|
await page.screenshot({path:output+'/merged-'+width+'.png',fullPage:true});
|
|
}
|
|
hardware.hat.online=false;
|
|
await page.evaluate(p=>render('zh',p),hardware);
|
|
if((await page.locator('.pi-alert-heading .semantic-status').innerText())!=='离线')throw Error('Offline hardware shown online');
|
|
if((await page.locator('[data-refresh-group="display"] .value').innerText()).includes('RGB 全灭'))throw Error('Stale RGB shown as current');
|
|
await page.evaluate(()=>render('zh',{}));
|
|
if((await page.locator('.pi-alert-heading .semantic-status').innerText())!=='未接入')throw Error('Absent hardware shown online');
|
|
if(errors.length)throw Error(errors.join('\n'));console.log('PASS: merged hardware display; online/offline/absent state; plugin management removed from overview; desktop/tablet/mobile; Chinese/English; no overflow or browser errors');await browser.close();})().catch(e=>{console.error(e);process.exit(1)});
|