diff --git a/apps/waterfall-wiki/tests/brand-ui-integration.ts b/apps/waterfall-wiki/tests/brand-ui-integration.ts index f1de465..d0c3bd1 100644 --- a/apps/waterfall-wiki/tests/brand-ui-integration.ts +++ b/apps/waterfall-wiki/tests/brand-ui-integration.ts @@ -17,10 +17,12 @@ export async function verifyBrandUI(base: string) { const browser = await chromium.launch({ executablePath: process.env.CHROMIUM_PATH || '/usr/bin/chromium', headless: true, args: ['--no-sandbox', '--disable-dev-shm-usage'] }); try { const page = await browser.newPage({ viewport: { width: 1440, height: 960 } }); + page.setDefaultTimeout(60000);page.setDefaultNavigationTimeout(60000); const visit = async (path: string, theme: string) => { await page.goto(base + path, { waitUntil: 'commit' }); await page.locator('button[data-theme-ready="true"]').first().waitFor(); await page.waitForFunction(expected => document.documentElement.dataset.theme === expected, theme); + console.log('Brand UI route ready:', path, theme); }; const background = (selector: string) => page.locator(selector).first().evaluate(el => getComputedStyle(el).backgroundColor); await visit('/', 'home-light'); diff --git a/apps/waterfall-wiki/tests/canvas-ui-integration.ts b/apps/waterfall-wiki/tests/canvas-ui-integration.ts index 7f882cf..d868c70 100644 --- a/apps/waterfall-wiki/tests/canvas-ui-integration.ts +++ b/apps/waterfall-wiki/tests/canvas-ui-integration.ts @@ -21,8 +21,8 @@ export async function verifyCanvasAgentUI(base:string){ page.on('requestfailed',request=>{pending.delete(request);network.push(requestName(request)+': '+request.failure()?.errorText)}); page.on('response',response=>{const url=new URL(response.url());if(url.pathname.startsWith('/api/canvases'))canvasRequests.push(`${response.request().method()} ${url.pathname} ${response.status()}`)}); try{ - page.setDefaultTimeout(20000);page.on('pageerror',e=>errors.push(e.message)); - mark('open landing');await page.goto(base+'/',{waitUntil:'domcontentloaded'}); + page.setDefaultTimeout(60000);page.setDefaultNavigationTimeout(60000);page.on('pageerror',e=>errors.push(e.message)); + mark('open landing');await page.goto(base+'/',{waitUntil:'commit'}); await page.getByRole('heading',{name:/想法不该停在对话里/,level:1}).waitFor(); const accountSession=page.waitForResponse(response=>new URL(response.url()).pathname==='/api/account/session'&&response.request().method()==='GET'); const [,sessionResponse]=await Promise.all([page.getByRole('link',{name:'开始创作',exact:true}).click(),accountSession]); @@ -97,7 +97,7 @@ export async function verifyCanvasAgentUI(base:string){ assert.equal((await fetch(base+root,{headers:{authorization:second.authorization}})).status,404); await page.setViewportSize({width:390,height:844}); const bounds=await panel.boundingBox();assert.ok(bounds&&bounds.x>=0&&bounds.x+bounds.width<=390,'Agent panel stays within the mobile viewport'); - await page.reload({waitUntil:'domcontentloaded'}); + await page.reload({waitUntil:'commit'}); await page.getByRole('link',{name:email,exact:true,includeHidden:true}).waitFor({state:'attached'}); await page.getByRole('button',{name:'Agent',exact:true}).click(); const reopened=page.getByRole('region',{name:'Agent 连接',exact:true}); diff --git a/apps/waterfall-wiki/tests/guidance-integration.ts b/apps/waterfall-wiki/tests/guidance-integration.ts index 395210c..7a9cc76 100644 --- a/apps/waterfall-wiki/tests/guidance-integration.ts +++ b/apps/waterfall-wiki/tests/guidance-integration.ts @@ -35,7 +35,7 @@ export async function verifyGuidancePublishing(base:string){ // The document discovery list hydrates from the real API; the homepage is the product landing page. const browser=await chromium.launch({executablePath:process.env.CHROMIUM_PATH||'/usr/bin/chromium',headless:true,args:['--no-sandbox','--disable-dev-shm-usage']}); try{ - const page=await browser.newPage(); + const page=await browser.newPage();page.setDefaultTimeout(60000);page.setDefaultNavigationTimeout(60000); const navigationDiagnostics:string[]=[],inflight=new Set(); const record=(value:string)=>{navigationDiagnostics.push(value.slice(0,1800));if(navigationDiagnostics.length>24)navigationDiagnostics.shift();}; page.on('pageerror',error=>record('pageerror: '+error.message)); @@ -46,30 +46,30 @@ export async function verifyGuidancePublishing(base:string){ page.on('response',response=>{const path=new URL(response.url()).pathname;if(path.startsWith('/api/')||path.includes('/_next/data/'))void response.text().then(body=>record(`data ${response.status()} ${path}: ${body.slice(0,1400)}`)).catch(()=>{});else if(response.status()>=400||response.request().resourceType()==='script')record(`resource ${response.status()} ${path}`);}); try{ const link=`a[href="/documents/${httpDoc.id}?revision=1"]`; - const navigation=await page.goto(base+'/documents',{waitUntil:'domcontentloaded'});record('directory HTTP '+navigation?.status()); + const navigation=await page.goto(base+'/documents',{waitUntil:'commit'});record('directory HTTP '+navigation?.status()); await page.locator(link).waitFor({state:'visible'});assert.equal(await page.locator(link).getByRole('heading').textContent(),httpDoc.title); // Published matches must not inherit the examples' empty state; submitted filters survive reload. const search=page.getByRole('textbox',{name:'搜索文档'}); await search.fill(httpDoc.title);await search.press('Enter'); - await page.waitForURL(url=>url.searchParams.get('q')===httpDoc.title); + await page.waitForURL(url=>url.searchParams.get('q')===httpDoc.title,{waitUntil:'commit'}); await page.getByRole('status').filter({hasText:'找到 2 篇文档'}).waitFor(); assert.equal(await page.getByText('没有匹配文档',{exact:false}).count(),0); - await page.reload({waitUntil:'domcontentloaded'}); + await page.reload({waitUntil:'commit'}); await page.getByRole('status').filter({hasText:'找到 2 篇文档'}).waitFor(); assert.equal(await search.inputValue(),httpDoc.title); await page.getByRole('tab',{name:/事实依据/}).click(); - await page.waitForURL(url=>url.searchParams.get('kind')==='evidence'); + await page.waitForURL(url=>url.searchParams.get('kind')==='evidence',{waitUntil:'commit'}); await page.getByRole('heading',{name:'没有匹配文档',exact:true}).waitFor(); await page.getByRole('button',{name:'清除所有筛选'}).click(); - await page.waitForURL(url=>url.search===''); + await page.waitForURL(url=>url.search==='',{waitUntil:'commit'}); await page.locator(link).waitFor({state:'visible'}); assert.equal(await search.inputValue(),''); await page.getByRole('navigation',{name:'主导航',exact:true}).getByRole('link',{name:'社区文档',exact:true}).click();await page.locator(link).waitFor({state:'visible'}); await page.locator(link).click(); - await page.waitForURL(url=>url.pathname==='/documents/'+httpDoc.id&&url.searchParams.get('revision')==='1'); + await page.waitForURL(url=>url.pathname==='/documents/'+httpDoc.id&&url.searchParams.get('revision')==='1',{waitUntil:'commit'}); await page.getByRole('heading',{name:httpDoc.title,exact:true,level:1}).waitFor(); assert.equal(await page.locator('h1').textContent(),httpDoc.title); - await page.goto(base+'/write',{waitUntil:'domcontentloaded'});assert.equal(await page.locator('h1').textContent(),'发布独立文档'); + await page.goto(base+'/write',{waitUntil:'commit'});await page.getByRole('heading',{name:'发布独立文档',exact:true,level:1}).waitFor();assert.equal(await page.locator('h1').textContent(),'发布独立文档'); }catch(error){console.error('Document navigation diagnostics',JSON.stringify({url:page.url(),headings:await page.locator('h1').allTextContents(),body:(await page.locator('body').innerText()).slice(0,2200),inflight:[...inflight].map(url=>new URL(url).pathname),events:navigationDiagnostics}));throw error;} await page.close(); await verifyGuidanceWorkspaceUI(base,browser); diff --git a/apps/waterfall-wiki/tests/guidance-workspace-ui.ts b/apps/waterfall-wiki/tests/guidance-workspace-ui.ts index b76792b..2ad56d8 100644 --- a/apps/waterfall-wiki/tests/guidance-workspace-ui.ts +++ b/apps/waterfall-wiki/tests/guidance-workspace-ui.ts @@ -89,7 +89,8 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) route.fulfill({ json: { document: authored } }), ); const page = await context.newPage(); - page.setDefaultTimeout(10000); + page.setDefaultTimeout(60000); + page.setDefaultNavigationTimeout(60000); page.on("pageerror", (error) => errors.push(error.message)); page.on("crash", () => errors.push("Browser renderer crashed")); const pending = new Set(), network: string[] = []; @@ -99,7 +100,7 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) async function navigate(url: string, reload = false) { const previousSessionReplies = sessionReplies; try { - const navigation = await (reload ? page.reload({waitUntil:"domcontentloaded"}) : page.goto(url,{waitUntil:"domcontentloaded"})); + const navigation = await (reload ? page.reload({waitUntil:"commit"}) : page.goto(url,{waitUntil:"commit"})); assert.ok(navigation?.ok(), "Navigation returns a successful document"); await page.getByText(signedIn ? "editor@example.com" : "登录你的账户",{exact:true}).first().waitFor({state:"attached"}); assert.ok(sessionReplies > previousSessionReplies, "The new document requests its account fixture and renders the resulting account state"); diff --git a/apps/waterfall-wiki/tests/integration.test.ts b/apps/waterfall-wiki/tests/integration.test.ts index 1f9953a..478cd5c 100644 --- a/apps/waterfall-wiki/tests/integration.test.ts +++ b/apps/waterfall-wiki/tests/integration.test.ts @@ -23,6 +23,13 @@ import {verifyFlatNoteMigration} from './flat-note-migration'; import {staticEntries} from '../src/lib/explore'; import {publishLearningSeries} from '../src/lib/publish-learning-series'; +// Browser acceptance gets its own deadline; it must not consume the existing business-flow budget. +test('Endoleap icons, persisted themes and artwork isolation in the real browser', {timeout:300000,skip:!process.env.PROMPT_TEST_BASE_URL}, async()=>{ + assert.equal(process.env.PROMPT_INTEGRATION_TEST,'1'); + const base=process.env.PROMPT_TEST_BASE_URL;assert.ok(base); + await verifyBrandUI(base); +}); + test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processing', {timeout:600000}, async()=>{ assert.equal(process.env.PROMPT_INTEGRATION_TEST,'1','Run only against an explicitly isolated test database'); const socket=createServer();socket.listen(0,'127.0.0.1');await once(socket,'listening');const address=socket.address();assert.ok(address&&typeof address!=='string');const port=address.port;await new Promise(r=>socket.close(()=>r())); @@ -34,7 +41,7 @@ test('real PostgreSQL + S3 notes, flat tags, resource sharing and video processi try{ let ready=false;for(let i=0;i<60;i++){try{if((await fetch(base+'/api/health')).ok){ready=true;break;}}catch{}await setTimeout(250);}assert.ok(ready); for(const route of ['/','/images','/videos','/audio','/articles','/motion','/library/import','/tools/doodle','/tools/skills','/tools/skills/street-people','/tools/skills/shadow-puppet'])assert.equal((await fetch(base+route)).status,200,route); - await verifyBrandUI(base); + if(!external)await verifyBrandUI(base); await verifyEmailAccounts(); await verifyCanvasWorkspace(base); if(process.env.VERIFY_CANVAS_UI==='1')await verifyCanvasAgentUI(base);