Fixtures & Factories
Centralize setup so tests start from a known state without copy-paste.
- unit
- e2e
- fixtures
Problem
The same setup — a logged-in user, a seeded cart, a configured client — is copy-pasted across files. It drifts over time and each test re-implements teardown.
Solution
Use the framework’s fixture mechanism to declare setup once and inject it where needed, with automatic teardown. A factory creates fresh, independent instances per test so there is no shared mutable state.
Compose fixtures: a "logged-in page" fixture builds on a "page" fixture, keeping each piece small and reusable.
Snippet
export const test = base.extend<{ authedPage: Page }>({
authedPage: async ({ page }, use) => {
await new LoginPage(page).login('user@example.com', 'secret');
await use(page); // teardown (if any) runs after the test
},
});
test('shows the dashboard', async ({ authedPage }) => {
await expect(authedPage.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});Pitfalls
- A shared fixture instance mutated across tests — defeats isolation. Build fresh per test.
- Heavy fixtures that do far more than a test needs, slowing every run.
- Forgetting teardown, leaking resources (open handles, seeded rows) between tests.