const {chromium}=require('playwright');const fs=require('fs');const path=require('path');const assert=require('assert'); const root=path.resolve(__dirname,'../pigway_frame_flow/web');const out=process.env.FRAME_FLOW_SCREENSHOT_DIR;if(out)fs.mkdirSync(out,{recursive:true}); (async()=>{const b=await chromium.launch({headless:true,executablePath:'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'});let count=0; try{for(const width of [1440,768,390,320])for(const lang of ['zh','en'])for(const theme of ['dark','light']){ const p=await b.newPage({viewport:{width,height:900}});const errors=[];p.on('pageerror',e=>errors.push(e.message)); await p.addInitScript(({lang,theme})=>{localStorage.setItem('ff-language',lang);localStorage.setItem('ff-theme',theme)},{lang,theme}); await p.route('**/*',async r=>{const u=new URL(r.request().url());if(u.pathname.startsWith('/api/')){if(u.pathname==='/api/v1/version')return r.fulfill({json:{version:'0.1.9',commit:'ba9424a-ui',build_time:'validation'}});return r.fulfill({status:401,json:{error:{code:'UNAUTHORIZED',message:'Sign in required'}}});}let f=u.pathname==='/'?'index.html':u.pathname.replace(/^\/ui\//,'');const file=path.join(root,f);if(!file.startsWith(root)||!fs.existsSync(file))return r.fulfill({status:404,body:''});return r.fulfill({body:fs.readFileSync(file),contentType:f.endsWith('.css')?'text/css':f.endsWith('.js')?'application/javascript':'text/html'});}); await p.goto('http://frame.test/');await p.locator('#login-form').waitFor();await p.waitForTimeout(60); assert.equal(await p.locator('#device option:checked').innerText(),lang==='zh'?'客厅':'Living room'); const layout=await p.evaluate(()=>{const q=s=>document.querySelector(s).getBoundingClientRect();return {overflow:document.documentElement.scrollWidth>innerWidth,card:q('.login-card').toJSON(),form:q('#login-form').toJSON(),user:q('#username').toJSON(),password:q('#password').toJSON(),remember:document.querySelector('#remember-login').closest('label').getBoundingClientRect().toJSON(),button:q('#login-form button').toJSON(),label:document.querySelector('#remember-login').labels[0].innerText}}); assert(!layout.overflow,JSON.stringify({width,lang,theme,layout}));assert(layout.password.top-layout.user.bottom>=24);assert(layout.button.top-layout.remember.bottom>=20);assert(layout.button.width>=layout.form.width-1);assert.equal(errors.length,0,errors.join('\n')); // Language switching and custom names must not change the internal device ID. await p.evaluate(()=>{state.devices=[{id:'living-room',name:'我的画框'}];shell()});assert.equal(await p.locator('#device option:checked').innerText(),'我的画框'); await p.evaluate(()=>{state.devices=[];shell();login()}); if(out&&lang==='zh'&&theme==='dark'&&[1440,390].includes(width))await p.screenshot({path:path.join(out,`login-${width}.png`),fullPage:true}); console.log('PASS',width,lang,theme);count++;await p.close();} console.log('TOTAL',count,'profiles');}finally{await b.close()}})().catch(e=>{console.error(e);process.exit(1)});