diff --git a/apps/waterfall-wiki/tests/creative-browser-diagnostics.test.ts b/apps/waterfall-wiki/tests/creative-browser-diagnostics.test.ts index 72a6b97..46842ba 100644 --- a/apps/waterfall-wiki/tests/creative-browser-diagnostics.test.ts +++ b/apps/waterfall-wiki/tests/creative-browser-diagnostics.test.ts @@ -1,6 +1,6 @@ import {test} from 'node:test'; -import {verifyCanvasAgentUI} from './canvas-ui-integration'; -import {db} from '../src/lib/db'; +import {chromium} from 'playwright-core'; +import {verifyGuidanceWorkspaceUI} from './guidance-workspace-ui'; const originalFetch=globalThis.fetch; globalThis.fetch=async(input,init)=>{ const url=typeof input==='string'?input:input instanceof URL?input.href:input.url; @@ -8,6 +8,7 @@ globalThis.fetch=async(input,init)=>{ try{const response=await originalFetch(input,init);console.log('Diagnostic HTTP',JSON.stringify({path,method:init?.method||'GET',status:response.status,ms:Date.now()-started}));return response} catch(error){console.error('Diagnostic HTTP failed',JSON.stringify({path,method:init?.method||'GET',ms:Date.now()-started,error:error instanceof Error?error.message:String(error)}));throw error} }; -test('diagnose canvas navigation against prebuilt review images',{timeout:300000},async()=>{ - try{await verifyCanvasAgentUI(process.env.PROMPT_TEST_BASE_URL!)}finally{await db().end()} +test('diagnose guidance session readiness against the same images',{timeout:300000},async()=>{ + const browser=await chromium.launch({executablePath:process.env.CHROMIUM_PATH||'/usr/bin/chromium',headless:true,args:['--no-sandbox','--disable-dev-shm-usage']}); + try{await verifyGuidanceWorkspaceUI(process.env.PROMPT_TEST_BASE_URL!,browser)}finally{await browser.close()} }); diff --git a/apps/waterfall-wiki/tests/guidance-workspace-ui.ts b/apps/waterfall-wiki/tests/guidance-workspace-ui.ts index a1b8f6e..0d91ce6 100644 --- a/apps/waterfall-wiki/tests/guidance-workspace-ui.ts +++ b/apps/waterfall-wiki/tests/guidance-workspace-ui.ts @@ -27,9 +27,11 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) requestedAuthor: string | null = null, published: Guidance | null = null; const errors: string[] = []; + const started=performance.now(),trace:{ms:number;event:string;path?:string}[]=[]; + const mark=(event:string,path?:string)=>trace.push({ms:Math.round(performance.now()-started),event,path}); try { await context.route("**/api/account/session", (route) => - route.fulfill({ + (mark("session route handler"),route.fulfill({ json: { user: signedIn ? { @@ -39,7 +41,7 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) } : null, }, - }), + })), ); await context.route( (url) => url.pathname === "/api/documents", @@ -87,6 +89,8 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) ); const page = await context.newPage(); page.setDefaultTimeout(10000); + page.on('domcontentloaded',()=>mark('domcontentloaded',new URL(page.url()).pathname)); + page.on('response',response=>{if(new URL(response.url()).pathname==='/api/account/session')mark('session response '+response.status())}); page.on("pageerror", (error) => errors.push(error.message)); page.on("crash", () => errors.push("Browser renderer crashed")); const pending = new Set(), network: string[] = []; @@ -94,12 +98,14 @@ export async function verifyGuidanceWorkspaceUI(base: string, browser: Browser) page.on("requestfinished", request => pending.delete(request.url())); page.on("requestfailed", request => {pending.delete(request.url());network.push(new URL(request.url()).pathname+": "+request.failure()?.errorText);}); async function navigate(url: string, reload = false) { + mark("navigate begin",new URL(url).pathname); const session = page.waitForResponse(response => new URL(response.url()).pathname === "/api/account/session" && response.status() === 200); try { const [navigation] = await Promise.all([reload ? page.reload({waitUntil:"domcontentloaded"}) : page.goto(url,{waitUntil:"domcontentloaded"}),session]); assert.ok(navigation?.ok(), "Navigation returns a successful document"); await page.getByText(signedIn ? "editor@example.com" : "登录你的账户",{exact:true}).first().waitFor({state:"attached"}); } catch (error) { + console.error("Guidance ordered readiness",JSON.stringify(trace)); const probeStarted=Date.now(); const server=await fetch(url,{signal:AbortSignal.timeout(3000)}).then(async response=>{await response.body?.cancel();return {status:response.status,elapsedMs:Date.now()-probeStarted}}).catch(error=>({error:error instanceof Error?error.name:"unknown",elapsedMs:Date.now()-probeStarted})); console.error("Workspace UI navigation diagnostics",JSON.stringify({url:page.url(),browserConnected:browser.isConnected(),server,pending:[...pending].map(value=>new URL(value).pathname),network:network.slice(-20),errors,body:(await page.locator("body").innerText().catch(()=>"unavailable")).slice(0,1600)})); diff --git a/compose.creative-diagnostics.yml b/compose.creative-diagnostics.yml index 572b3bf..c8da89e 100644 --- a/compose.creative-diagnostics.yml +++ b/compose.creative-diagnostics.yml @@ -4,3 +4,4 @@ services: volumes: - ./apps/waterfall-wiki/tests/canvas-ui-integration.ts:/app/tests/canvas-ui-integration.ts:ro - ./apps/waterfall-wiki/tests/creative-browser-diagnostics.test.ts:/app/tests/integration.test.ts:ro + - ./apps/waterfall-wiki/tests/guidance-workspace-ui.ts:/app/tests/guidance-workspace-ui.ts:ro diff --git a/scripts/integration.sh b/scripts/integration.sh index 1a3e93c..05fc51a 100644 --- a/scripts/integration.sh +++ b/scripts/integration.sh @@ -16,6 +16,9 @@ if [[ "${CREATIVE_BROWSER_DIAGNOSTICS:-}" == "1" ]]; then COMPOSE_FILES+=(-f com compose(){ docker compose -p "$COMPOSE_PROJECT_NAME" --env-file "$TEST_ENV" "${COMPOSE_FILES[@]}" "$@"; } diagnostic_state(){ if [[ "${CREATIVE_BROWSER_DIAGNOSTICS:-}" != "1" ]]; then return; fi + for metric in /proc/pressure/cpu /proc/pressure/memory /proc/pressure/io; do + if [[ -r "$metric" ]]; then echo "$metric"; cat "$metric"; fi + done local ids ids=$(compose ps -aq) if [[ -n "$ids" ]]; then