Skip to content

Playwright Fixtures

Fixtures provide dependencies to tests — browser, context, page, request — with automatic setup and teardown. Extend fixtures for shared auth, API clients, or page objects.

Built-In Fixtures

Tests declare needed fixtures in the function signature: async ({ page, request }). The runner creates, scopes, and disposes them automatically.

Fixture scope defaults to per-test. Worker-scoped fixtures ({ scope: 'worker' }) share expensive setup across tests in a worker.

import { test as base, expect } from '@playwright/test';

type Fixtures = { todoPage: TodoPage };
export const test = base.extend<Fixtures>({
  todoPage: async ({ page }, use) => {
    const todo = new TodoPage(page);
    await todo.goto();
    await use(todo);
  },
});

test('adds todo', async ({ todoPage }) => {
  await todoPage.add('Buy milk');
});

Custom fixtures wrap setup/teardown around use().

Fixture Lifecycle

myFixture: async ({ page }, use) => {
  // setup before use
  await use(value);
  // teardown after test
},
  • Code before use() runs before the test.
  • Code after use() runs after the test completes.
  • Fixtures can depend on other fixtures via destructuring.
  • Export extended test from fixtures file; import in specs.

Built-In Fixtures

Default fixtures from @playwright/test.

Fixture Provides
page Single browser tab
context Isolated browser context
browser Browser instance
browserName 'chromium' | 'firefox' | 'webkit'
request APIRequestContext for HTTP
playwright Playwright module entry

Worker-Scoped Fixtures

db: [async ({}, use) => {
  const connection = await connectDb();
  await use(connection);
  await connection.close();
}, { scope: 'worker' }],

Use for expensive shared resources — mind parallel isolation.

Worker-Scoped Fixtures

Fixtures can be scoped to test, worker, or custom scopes — worker scope shares expensive setup like a database seed across tests in one worker process.

Common Mistakes

  • Global variables instead of fixtures for shared setup.
  • Forgetting teardown after use() for created data.
  • Worker fixtures holding per-test mutable state.
  • Circular fixture dependencies.

Key Takeaways

  • Fixtures inject setup into tests cleanly.
  • test.extend creates composable custom fixtures.
  • Setup/teardown wraps use() callback.
  • Choose test vs worker scope deliberately.

Pro Tip

Put auth + page object fixtures in tests/fixtures.ts and import test from there everywhere — one pattern for the whole repo.