LazyBoy2/tests/mobile_inbox_ui.mjs

99 lines
7.2 KiB
JavaScript
Raw Permalink Normal View History

2026-09-16 08:17:38 +00:00
import { chromium } from '../tools/playwright/node_modules/playwright/index.mjs';
import assert from 'node:assert/strict';
const browser=await chromium.launch({headless:true});
try {
for(const theme of ['dark','light']) {
const page=await browser.newPage({viewport:{width:390,height:844},hasTouch:true,isMobile:true,serviceWorkers:'block'});
page.setDefaultTimeout(8000);
await page.addInitScript(theme=>{localStorage.setItem('lazyboy.theme',theme);localStorage.setItem('lazyboy.locale','zh-Hant');localStorage.setItem('lazyboy.agent','beta')},theme);
const errors=[];page.on('pageerror',e=>errors.push(e.message));
let opened=[],computers=0,globalActions=[];
page.on('dialog',dialog=>dialog.accept());
const activity={state:'idle',running:false,queued:false,active_task_ids:[],observed_at_ms:Date.now()};
const agents=[{id:'alpha',name:'小麻糬',avatar_color:'#edc585',preview:'今天想一起完成什麼?',last_at:'2026-09-16T08:00:00Z'},{id:'beta',name:'程式小幫手',avatar_color:'#a3cfef',preview:'剛才的修改已經完成。',last_at:'2026-09-16T07:55:00Z'}];
await page.route('**/api/**',route=>{
const path=new URL(route.request().url()).pathname;
if(path==='/api/agents')return route.fulfill({json:{agents}});
if(path.endsWith('/activity'))return route.fulfill({json:activity});
if(path.endsWith('/events'))return route.fulfill({contentType:'text/event-stream',body:'data: {"events":[]}\n\n'});
if(path==='/api/computer'){globalActions.push(route.request().postDataJSON().action);return route.fulfill({json:{ready:false,error:'測試電腦回應'}})}
if(path.endsWith('/computer')){computers++;return route.fulfill({json:{ready:false}})}
const a=agents.find(a=>path===`/api/agents/${a.id}`);
if(a){opened.push(a.id);return route.fulfill({json:{...a,activity,transcript:[{role:'assistant',content:`你好,我是${a.name}`,at:'2026-09-16T08:00:00Z'}]}})}
return route.fulfill({json:{}});
});
await page.goto('http://127.0.0.1:5173');
await page.getByRole('button',{name:/小麻糬 今天/}).waitFor();
assert.equal(await page.locator('.chat-panel').isVisible(),false);
assert.deepEqual(opened,[],'remembered agent must not open on mobile');assert.equal(computers,0);
const list=await page.locator('.sidebar').boundingBox();assert.equal(list.x,0);assert.equal(list.width,390);assert.equal(list.height,844);
assert.equal(await page.locator('.mobile-nav-backdrop').count(),0);
assert.equal(await page.locator('.brand-icon').count(),0,'phone header has no brand row');
const heading=await page.locator('.mobile-profile').boundingBox(),add=await page.locator('.brand .icon-button').boundingBox();
assert.ok(Math.abs(heading.y+heading.height/2-add.y-add.height/2)<1);
await page.getByRole('button',{name:'設定',exact:true}).click();
const dialog=page.getByRole('dialog');await dialog.waitFor();
const settings=await dialog.boundingBox();assert.equal(settings.width,374);assert.equal(settings.height,740);assert.equal(settings.x,8);
assert.equal(await page.locator('.lb-settings-nav').count(),0);
await page.screenshot({path:`.run/mobile-settings-${theme}.png`});
await dialog.getByRole('button',{name:/電腦.*更新/}).click();
await dialog.getByRole('button',{name:'更新',exact:true}).click();
await dialog.getByText('測試電腦回應').waitFor();
await dialog.getByRole('button',{name:'重啟',exact:true}).click();
await page.waitForFunction(()=>!document.querySelector('.lb-settings-control button:disabled'));
assert.deepEqual(globalActions,['update','restart']);
await dialog.getByRole('button',{name:'設定',exact:true}).click();
await dialog.getByRole('button',{name:/外觀/}).click();
const themeOption=dialog.getByRole('radio',{name:theme==='dark'?'淺色':'深色',exact:true});
await themeOption.click();assert.equal(await themeOption.getAttribute('aria-checked'),'true');
assert.equal(await page.locator('html').getAttribute('data-theme'),theme==='dark'?'light':'dark');
await dialog.getByRole('radio',{name:theme==='dark'?'深色':'淺色',exact:true}).click();
await page.screenshot({path:`.run/mobile-theme-${theme}.png`});
await dialog.getByRole('button',{name:'設定',exact:true}).click();
await dialog.getByRole('button',{name:/語言/}).click();
await dialog.getByRole('radio',{name:'English',exact:true}).click();
await dialog.getByRole('button',{name:'Settings',exact:true}).click();
await dialog.getByRole('button',{name:/Language/}).click();
await dialog.getByRole('radio',{name:'繁體中文',exact:true}).click();
await dialog.getByRole('button',{name:'設定',exact:true}).click();
await dialog.getByRole('button',{name:/關於/}).click();
await page.locator('.mobile-about-page').waitFor();
await dialog.getByRole('button',{name:'設定',exact:true}).click();
await dialog.getByRole('button',{name:'返回聊天列表',exact:true}).click();
await dialog.waitFor({state:'hidden'});
await page.getByRole('button',{name:'設定',exact:true}).click();
await dialog.waitFor();await page.goBack();await dialog.waitFor({state:'hidden'});
await page.screenshot({path:`.run/mobile-inbox-${theme}.png`});
await page.getByRole('button',{name:/小麻糬 今天/}).click();
await page.locator('.messages').getByText('你好,我是小麻糬。').waitFor();
assert.equal(await page.locator('.sidebar').isVisible(),false);
assert.equal(await page.locator('.chat-panel').isVisible(),true);assert.equal(computers,0,'chat selection must not boot a remote desktop');
await page.locator('.composer textarea').fill('保留中的草稿');
await page.screenshot({path:`.run/mobile-chat-${theme}.png`});
await page.getByRole('button',{name:'返回聊天列表'}).click();
await page.locator('.sidebar').waitFor({state:'visible'});
await page.getByRole('button',{name:'搜尋',exact:true}).click();
await page.getByRole('textbox',{name:'搜尋'}).fill('程式');
assert.equal(await page.locator('.bot-row').count(),1);
await page.locator('.bot-row').click();
await page.locator('.messages').getByText('你好,我是程式小幫手。').waitFor();
await page.goBack();await page.locator('.sidebar').waitFor({state:'visible'});
await page.getByRole('textbox',{name:'搜尋'}).fill('');
await page.getByRole('button',{name:/小麻糬 今天/}).click();
await page.locator('.chat-panel').waitFor({state:'visible'});
await page.reload();await page.locator('.sidebar').waitFor({state:'visible'});
assert.equal(await page.locator('.chat-panel').isVisible(),false,'reload starts at list');
await page.setViewportSize({width:844,height:390});
assert.equal(await page.locator('.sidebar').isVisible(),true,'phone landscape keeps full-page list');
assert.equal((await page.locator('.sidebar').boundingBox()).width,844);
await page.setViewportSize({width:1440,height:900});
await page.locator('.chat-panel').waitFor({state:'visible'});
assert.equal(await page.locator('.sidebar').isVisible(),true,'desktop keeps both panels');
await page.locator('.messages').getByText('你好,我是小麻糬。').waitFor();
assert.ok(computers>0);
assert.deepEqual(errors,[]);
console.log(`PASS ${theme}: full-page inbox, choose chat, UI/browser back, search, reload, rotation and desktop layout`);
await page.close();
}
}finally{await browser.close()}