Set up stable node:test E2E lifecycle with env, withBrowser and e2eSuite
Use this skill when creating or refactoring LiveChange frontend E2E tests.
Avoid flaky teardown where only the first test file runs because shared env teardown calls process.exit.
Create e2e/env.ts with:
getTestEnv() that starts TestServer once and memoizes with envPromisedisposeTestEnv() that resets memoized state and disposes serverprocess.on('beforeExit', () => {
void disposeTestEnv()
})
Keep startup failure process.exit(1) inside getTestEnv() catch.
Do not add to this file.
after(...process.exit(...))Create e2e/withBrowser.ts with Playwright setup/teardown in try/finally:
getTestEnv() once per test executionfinallyCreate e2e/e2eSuite.ts:
import { after, describe } from 'node:test'
import { disposeTestEnv } from './env.js'
export function e2eSuite(name: string, define: () => void): void {
describe(name, () => {
after(async () => {
await disposeTestEnv()
process.exit(0)
})
define()
})
}
Each e2e/*.test.ts file should use one wrapper:
import test from 'node:test'
import { e2eSuite } from './e2eSuite.js'
e2eSuite('example-suite', () => {
test('renders page', async () => {
// test body
})
})
Run from project root with fnm exec:
fnm exec -- npm run e2e
Confirm multiple test files execute and process exits only after full suite teardown.