fix: add catch-all API mock and socket.io block for base screenshots

Base screenshots showed loading spinners or were missing entirely because:
1. Unmocked API calls (e.g. /api/people, /api/search/explore) hit the static
   preview server which returns HTML instead of JSON, preventing networkidle
2. Socket.io WebSocket connections never complete handshake, blocking networkidle

Add a catch-all /api/** mock (registered first, so specific mocks take priority)
that returns empty JSON for any unmocked endpoint. Block socket.io connections.
Also add a networkidle timeout fallback in run-scenarios.ts so screenshots are
still captured even if networkidle doesn't resolve within 15s.

https://claude.ai/code/session_01XSTqDJXuR4jaLN7SGm3uES
This commit is contained in:
Claude
2026-03-01 19:24:05 +00:00
committed by Zack Pollard
parent feacf9b134
commit cf1a9ed3f5
2 changed files with 30 additions and 2 deletions

View File

@@ -97,8 +97,15 @@ for (const scenario of allScenarios) {
});
}
// Navigate to the page
await page.goto(scenario.url, { waitUntil: 'networkidle' });
// Navigate to the page. Use networkidle so SvelteKit hydrates and API
// calls complete, but fall back to domcontentloaded if it times out
// (e.g. a persistent connection the catch-all mock didn't cover).
try {
await page.goto(scenario.url, { waitUntil: 'networkidle', timeout: 15_000 });
} catch {
console.warn(`networkidle timed out for ${scenario.name}, falling back to current state`);
// Page has already navigated, just continue with what we have
}
// Wait for specific selector if specified
if (scenario.waitForSelector) {

View File

@@ -10,6 +10,27 @@ export const setupBaseMockApiRoutes = async (context: BrowserContext, adminUserI
path: '/',
},
]);
// Block socket.io connections — these are persistent WebSocket connections
// that prevent networkidle from resolving since there's no real server.
await context.route('**/api/socket.io**', async (route) => {
return route.abort('connectionrefused');
});
// Catch-all for any /api/ endpoint not explicitly mocked below.
// Registered FIRST so specific routes (registered after) take priority
// (Playwright checks routes in reverse registration order).
// Without this, unmocked API calls hit the static preview server which
// either hangs or returns HTML, preventing networkidle and causing timeouts.
await context.route('**/api/**', async (route) => {
const method = route.request().method();
return route.fulfill({
status: 200,
contentType: 'application/json',
json: method === 'GET' ? [] : {},
});
});
await context.route('**/api/users/me', async (route) => {
return route.fulfill({
status: 200,