Playwright Test Fixtures

A hotel room arrives fully prepared with clean towels, working lights, and made beds before a guest ever checks in. A fixture prepares a test the same way, handing over a ready-to-use resource before the actual test steps even begin.

How a Fixture Supplies a Test

Fixture Definition (the recipe)
        |
        v
Playwright Prepares the Resource
        |
        v
Test Receives It Automatically as a Parameter

The Built-In Page Fixture

test('checks homepage title', async ({ page }) => {
  await page.goto('https://example.com');
});

The page object seen in every test is itself a fixture. Playwright creates a brand new browser page automatically before each test starts, and closes it automatically afterward.

Why Custom Fixtures Help

Many tests share the exact same starting requirement, such as being logged in already. Writing a custom fixture handles that shared requirement once, instead of repeating the same setup lines inside every test file.

Creating a Custom Fixture

const base = require('@playwright/test');

const test = base.test.extend({
  loggedInPage: async ({ page }, use) => {
    await page.goto('https://example.com/login');
    await page.getByLabel('Username').fill('admin');
    await page.getByLabel('Password').fill('secret123');
    await page.getByRole('button', { name: 'Log In' }).click();
    await use(page);
  },
});

module.exports = { test };

This fixture performs the login steps once, then hands over the already logged-in page to any test requesting it through the use function.

Using the Custom Fixture in a Test

const { test } = require('./fixtures');
const { expect } = require('@playwright/test');

test('view dashboard after login', async ({ loggedInPage }) => {
  await expect(loggedInPage.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});

This test skips writing any login steps at all, since the fixture already delivered a ready, logged-in page.

A Fixture That Provides Test Data

const test = base.test.extend({
  testUser: async ({}, use) => {
    const user = { name: 'Jane Doe', email: `jane${Date.now()}@example.com` };
    await use(user);
  },
});

This fixture generates a unique email address for every test run, avoiding conflicts when a website does not allow duplicate account registrations.

A Real-World Example

A banking website test suite needs an authenticated user for almost every test, such as checking balances or transferring funds. A single loggedInPage fixture removes login code from fifty separate test files, keeping every one of them shorter and easier to read.

Quick Practice Task

Identify a setup step repeated across several of your tests. Convert that step into a custom fixture and update one test to use it.

Key Takeaways

  • Fixtures supply ready-made resources directly to a test.
  • The built-in page fixture creates and closes a browser page automatically.
  • Custom fixtures remove repeated setup code across many tests.
  • Fixtures can also generate unique test data, such as random emails.

Leave a Comment

Your email address will not be published. Required fields are marked *