|

Advanced Playwright Fixtures: Worker-Scoped, Parameterized, and Auto-Cleanup Patterns

Basic fixtures inject page objects. Advanced fixtures manage database connections, share auth across workers, parameterize browser configs, and auto-cleanup test data — all with TypeScript type safety.

🎭 Want to master this with real projects? Join the Playwright Automation Mastery course at The Testing Academy.

Contents

Worker-Scoped Fixtures (Shared Across Tests)

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

// Worker-scoped: created once per worker, shared across all tests in that worker
export const test = base.extend<{}, { dbConnection: any }>({
  dbConnection: [async ({}, use) => {
    const db = await connectToDatabase();
    await use(db);
    await db.close(); // Cleanup after all tests in worker
  }, { scope: 'worker' }],
});

Parameterized Fixtures

// Run same tests across multiple configs
export const test = base.extend<{ userRole: string }>({
  userRole: ['admin', { option: true }],
});

// playwright.config.ts
projects: [
  { name: 'admin', use: { userRole: 'admin' } },
  { name: 'viewer', use: { userRole: 'viewer' } },
]

🚀 Level Up Your Playwright

From locators to CI pipelines — build a production-grade Playwright + TypeScript framework step by step.

Auto-Cleanup Fixture

export const test = base.extend<{ testUser: User }>({
  testUser: async ({ request }, use) => {
    // Setup: create via API
    const res = await request.post('/api/users', {
      data: { name: faker.person.fullName(), email: faker.internet.email() }
    });
    const user = await res.json();

    await use(user);  // Test runs here

    // Teardown: guaranteed cleanup even if test fails
    await request.delete('/api/users/' + user.id);
  },
});

Fixture Composition

// Fixtures can depend on other fixtures
export const test = base.extend<{
  api: ApiHelper;
  testUser: User;
  authenticatedPage: Page;
}>({
  api: async ({ request }, use) => {
    await use(new ApiHelper(request));
  },
  testUser: async ({ api }, use) => {
    const user = await api.createUser();
    await use(user);
    await api.deleteUser(user.id);
  },
  authenticatedPage: async ({ page, testUser }, use) => {
    await page.goto('/login');
    await page.getByLabel('Email').fill(testUser.email);
    await page.getByLabel('Password').fill(testUser.password);
    await page.getByRole('button', { name: 'Login' }).click();
    await use(page);
  },
});

When to Use Each Scope

ScopeLifetimeUse For
testPer testPage objects, test data, API client
workerPer worker processDB connections, expensive setup, shared tokens

🎓 Master Playwright End to End

Join hundreds of SDETs building real automation frameworks. Lifetime access, hands-on projects, and a job-ready portfolio.

Similar Posts

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.