2026-10-17 23:07:49 +08:00
const { chromium } = require ( 'playwright' );
const fs = require ( 'node:fs' ), path = require ( 'node:path' ), assert = require ( 'node:assert/strict' );
( async ()=>{
const browser = await chromium . launch ({ headless : true , channel : 'chrome' });
try {
const source = fs . readFileSync ( path . join ( __dirname , '../plugin/ui/index.js' ), 'utf8' ). replace ( /^import .*;\n/gm , '' ). replace ( 'export function hostCard' , 'function hostCard' );
const labels = { service_ready : { zh : '服务就绪' , en : 'Service ready' }, device_online : { zh : '画框在线' , en : 'Frame online' }, battery_percent : { zh : '电量' , en : 'Battery' }};
const entry = { host : { name : 'Frame Flow' }, dataCurrent : true , snapshot : { resources : [{ id : 'service' , name : 'Frame Flow' , type : 'service' },{ id : 'device:living-room' , name : '渡口浪人的相框' , type : 'device' }], metrics : [{ resource_id : 'service' , key : 'service_ready' , value : 1 , unit : 'boolean' , label : labels . service_ready },{ resource_id : 'device:living-room' , key : 'device_online' , value : 1 , unit : 'boolean' , label : labels . device_online },{ resource_id : 'device:living-room' , key : 'battery_percent' , value : 28 , unit : 'percent' , label : labels . battery_percent }], alerts : []}};
2026-10-17 23:31:38 +08:00
entry . snapshot . resources . push ({ id : 'job:slideshow' , name : '家庭照片轮播' , type : 'job' });
entry . snapshot . metrics . push ({ resource_id : 'job:slideshow' , key : 'job_enabled' , value : 1 , unit : 'boolean' },{ resource_id : 'job:slideshow' , key : 'last_run_success' , value : 1 , unit : 'boolean' });
2026-10-17 23:07:49 +08:00
for ( const lang of [ 'zh' , 'en' ]) for ( const width of [ 1440 , 820 , 390 ]) {
2026-10-17 23:45:14 +08:00
const page = await browser . newPage ({ bypassCSP : true , viewport : { width , height : 1000 }});
2026-10-17 23:07:49 +08:00
await page . goto ( 'http://192.168.89.19/' );
2026-10-17 23:45:14 +08:00
const result = await page . evaluate ( async ({ source , entry , lang })=>{
const { scopeAlertHealth , summaryStatus } = await import ( '/assets/js/overview-health.js' );
2026-10-17 23:07:49 +08:00
const state = { LANG : lang }; const text = ( zh , en )=> lang === 'zh' ? zh : en ;
const esc = v => String ( v ?? '' ). replace ( /[&<>"']/g , c =>({ '&' : '&' , '<' : '<' , '>' : '>' , '"' : '"' , "'" : ''' }[ c ]));
const html = eval ( source + '\nhostCard(entry)' );
document . body . innerHTML = `<main style="max-width:100%;padding:16px"> ${ html } </main>` ;
2026-10-17 23:31:38 +08:00
return { text : document . body . innerText , overflow : document . documentElement . scrollWidth > innerWidth , subtitle : document . querySelector ( ".host-head .device-details" ) ? . textContent , nested : document . querySelectorAll ( ".group .metric, .metric .metric" ). length , status : document . querySelector ( ".metric [data-semantic]" ) ? . textContent };
2026-10-17 23:07:49 +08:00
},{ source , entry , lang });
assert ( result . text . includes ( '渡口浪人的相框' ));
assert ( ! result . text . includes ( 'living-room' ));
assert ( result . text . includes ( lang === 'zh' ? '服务就绪' : 'Service ready' ));
assert . equal ( result . overflow , false );
2026-10-17 23:31:38 +08:00
assert . equal ( result . nested , 0 );
assert . equal ( result . subtitle , '渡口浪人的相框' );
assert . equal ( result . status , lang === 'zh' ? '正常' : 'Normal' );
assert ( result . text . includes ( lang === 'zh' ? '轮播任务' : 'Slideshow task' ));
2026-10-17 23:34:26 +08:00
assert ( result . text . includes ( '家庭照片轮播 · ' + ( lang === 'zh' ? '启用' : 'Enabled' )));
2026-10-17 23:07:49 +08:00
await page . close ();
}
console . log ( '6 browser checks passed' );
} finally { await browser . close ()}
})(). catch ( e =>{ console . error ( e ); process . exit ( 1 )});