29 lines
3.3 KiB
JavaScript
29 lines
3.3 KiB
JavaScript
/* Isolated Mock-only browser regression. Never touches the user's browser or frame. */
|
|||
|
|
const assert=require('assert');const fs=require('fs');const {chromium}=require('playwright');
|
||
|
|
(async()=>{
|
||
|
|
const base=process.env.FRAME_FLOW_URL;assert(base,'FRAME_FLOW_URL required');
|
||
|
|
const env=fs.readFileSync(process.env.FRAME_FLOW_ENV_FILE,'utf8');const token=env.split('\n').find(x=>x.startsWith('FRAME_FLOW_TOKEN=')).slice(17);
|
||
|
|
const config=await (await fetch(base+'/api/v1/settings',{headers:{Authorization:'Bearer '+token}})).json();assert(config.mock===true,'Mock required');
|
||
|
|
const browser=await chromium.launch({headless:true,executablePath:process.env.CHROME_EXECUTABLE||'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'});
|
||
|
|
try{
|
||
|
|
const page=await browser.newPage();const errors=[];page.on('pageerror',e=>errors.push(e.message));
|
||
|
|
await page.goto(base);await page.locator('#username').fill(process.env.FRAME_FLOW_TEST_USERNAME);await page.locator('#password').fill(process.env.FRAME_FLOW_TEST_PASSWORD);await page.locator('#login-form button').click();await page.locator('.hero').waitFor();
|
||
|
|
let checks=0;
|
||
|
|
for(const width of [1440,768,390])for(const lang of ['zh','en'])for(const theme of ['light','dark']){
|
||
|
|
await page.setViewportSize({width,height:900});await page.evaluate(({lang,theme})=>{state.lang=lang;document.documentElement.dataset.theme=theme;shell();},{lang,theme});
|
||
|
|
for(const view of ['studio','connections']){
|
||
|
|
await page.evaluate(view=>navigate(view),view);await page.locator(view==='studio'?'#studio-plan':'#mqtt-config').waitFor();
|
||
|
|
assert(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth),view+' overflow '+width);checks++;
|
||
|
|
const gaps=await page.locator('.actions').evaluateAll(rows=>rows.flatMap(row=>{const nodes=[...row.querySelectorAll('button')];return nodes.slice(1).map((node,i)=>{const a=nodes[i].getBoundingClientRect(),b=node.getBoundingClientRect();return Math.abs(a.top-b.top)<4?b.left-a.right:b.top-a.bottom;});}));
|
||
|
|
assert(gaps.every(g=>g>=8),view+' buttons touch '+width);checks++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
await page.evaluate(()=>navigate('studio'));await page.locator('#studio-files').setInputFiles({name:'fixture.png',mimeType:'image/png',buffer:Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+a1OIAAAAASUVORK5CYII=','base64')});
|
||
|
|
await page.locator('#studio-assets input:checked').waitFor();await page.locator('#studio-plan').click();await page.locator('#studio-layout img').waitFor();await page.locator('#studio-render').click();await page.locator('#studio-result').waitFor({timeout:30000});assert(await page.locator('#studio-download').isEnabled());checks++;
|
||
|
|
await page.locator('#studio-title').fill('Changed');assert(await page.locator('#studio-display').isDisabled());checks++;
|
||
|
|
assert.deepStrictEqual(errors,[]);checks++;
|
||
|
|
const out=process.env.FRAME_FLOW_SCREENSHOT_DIR;if(out){fs.mkdirSync(out,{recursive:true});await page.screenshot({path:out+'/studio-mobile.png',fullPage:true});await page.evaluate(()=>navigate('connections'));await page.locator('#mqtt-config').waitFor();await page.screenshot({path:out+'/connections-mobile.png',fullPage:true});}
|
||
|
|
console.log('Integration UI:',checks,'passed; 12 viewport/language/theme combinations; console errors:',errors.length);
|
||
|
|
}finally{await browser.close();}
|
||
|
|
})().catch(e=>{console.error(e.message);process.exit(1);});
|