A full parallel run intermittently failed the first few tests: unmocked /api/v1 calls fell through to the dev proxy, whose backend isn't running under E2E, so each incurred a slow ECONNREFUSED round-trip + Vite error logging that piled up across 8 workers at cold start. - Add e2e/fixtures.ts: a shared `test` whose auto-use fixture installs an `**/api/v1/**` fallback (fast 503, logged) for any endpoint a spec didn't mock. Registered before the test body, so per-test routes still win; only genuine gaps land here. Turns silent mock-gap hangs into instant, attributable failures — and cuts the full run ~96s → ~25s. - Point all 22 specs at ./fixtures instead of @playwright/test. - retries: 1 in the config as a safety net for the residual Vite cold-compile timing (re-runs on the now-warm server). Two consecutive full runs: 110 passed, 0 flaky, no retries consumed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
import { test as base, expect } from '@playwright/test';
|
|
|
|
export { expect };
|
|
export type { Page } from '@playwright/test';
|
|
|
|
/**
|
|
* Shared Playwright `test` for the E2E suite.
|
|
*
|
|
* Adds an auto-use fallback for the `/api` surface: any request a spec
|
|
* forgot to mock is fulfilled here with a fast 503 instead of falling
|
|
* through to the SvelteKit dev proxy. That proxy targets a backend that
|
|
* isn't running under E2E (`BACKEND_URL` in `.env`), so an unmocked call
|
|
* otherwise incurs a proxy round-trip + Vite error logging — which, under
|
|
* 8 parallel workers at cold start, piles up and flakes the first tests.
|
|
*
|
|
* Because this route is registered during fixture setup (before the test
|
|
* body runs), any `page.route(...)` a spec registers later takes
|
|
* precedence — only genuinely-unmocked calls land here. The 503 also
|
|
* surfaces mock gaps loudly (a clear warning + a fast, attributable
|
|
* failure) instead of a 30s "element never appeared" timeout.
|
|
*/
|
|
export const test = base.extend<{ apiFallback: void }>({
|
|
apiFallback: [
|
|
async ({ page }, use) => {
|
|
// Scope to `/api/v1/**` (the real backend surface). A broader
|
|
// `**/api/**` would also swallow Vite's own dev module requests
|
|
// under `/src/lib/api/*.ts` and break the app bundle.
|
|
await page.route('**/api/v1/**', (route) => {
|
|
const { pathname } = new URL(route.request().url());
|
|
console.warn(`[e2e] unmocked API call: ${route.request().method()} ${pathname}`);
|
|
return route.fulfill({
|
|
status: 503,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
error: { code: 'e2e_unmocked', message: `unmocked in test: ${pathname}` }
|
|
})
|
|
});
|
|
});
|
|
await use();
|
|
},
|
|
{ auto: true }
|
|
]
|
|
});
|