patterntypescriptTip
Playwright fixtures: share reusable setup and teardown across test files
Viewed 0 times
playwright fixturestest setupbeforeEach reuseworker fixturetest fixture scope
Problem
Every Playwright test file duplicates login setup, database seeding, and authenticated page navigation. Copy-pasted
beforeEach blocks drift out of sync and become a maintenance problem.Solution
Extend Playwright's base test with custom fixtures. Define authenticated pages, seeded database states, or API clients as fixture properties. Fixtures are scoped (test, worker, or project) and automatically torn down after the test.
Why
Fixtures compose cleanly: a test that needs an authenticated admin with a pre-seeded cart simply destructures
{ adminPage, cart } from the test function. Setup logic lives in one place and is reused without copy-paste.Gotchas
- Worker-scoped fixtures are shared across tests in the same worker — avoid mutating state in worker fixtures
- Fixtures that call
await use(value)must be async; forgetting await causes the fixture to be torn down immediately - Circular fixture dependencies cause a runtime error — keep fixture graphs acyclic
- Test-scoped fixtures run for every test; prefer worker scope for expensive setup like database seeding
Code Snippets
Custom Playwright fixture for authenticated page
// fixtures.ts
import { test as base, Page } from '@playwright/test';
type Fixtures = { authedPage: Page };
export const test = base.extend<Fixtures>({
authedPage: async ({ page }, use) => {
await page.goto('/login');
await page.getByLabel('Email').fill('admin@example.com');
await page.getByLabel('Password').fill('secret');
await page.getByRole('button', { name: 'Log in' }).click();
await page.waitForURL('/dashboard');
await use(page); // hand off to the test
// teardown here if needed
},
});
// my.spec.ts
import { test } from './fixtures';
test('sees dashboard', async ({ authedPage }) => {
await authedPage.getByText('Welcome').isVisible();
});Revisions (0)
No revisions yet.