Playwright Test Hooks

A theater crew sets the stage before every performance and clears it after the show ends, without repeating those steps inside the actual script the actors perform. Test hooks give Playwright the same separation, running setup and cleanup code automatically around each test.

How Hooks Wrap Around Tests

beforeAll (runs once)
   |
   v
beforeEach --> Test 1 --> afterEach
   |
   v
beforeEach --> Test 2 --> afterEach
   |
   v
afterAll (runs once)

Using beforeEach for Repeated Setup

test.beforeEach(async ({ page }) => {
  await page.goto('https://example.com/login');
  await page.getByLabel('Username').fill('testuser');
  await page.getByLabel('Password').fill('testpass');
  await page.getByRole('button', { name: 'Log In' }).click();
});

This code logs in before every single test in the file. Each test then starts already logged in, without repeating these four lines inside every test manually.

Using afterEach for Cleanup

test.afterEach(async ({ page }, testInfo) => {
  if (testInfo.status !== testInfo.expectedStatus) {
    await page.screenshot({ path: `failure-${testInfo.title}.png` });
  }
});

This code checks whether a test failed and, if so, saves a screenshot automatically, giving the team a visual clue about what went wrong without any manual effort.

Using beforeAll for One-Time Setup

test.beforeAll(async () => {
  console.log('Starting the checkout test suite');
});

This code runs exactly once before any test in the file begins, useful for tasks like preparing a shared test database or logging the start of a test run.

Using afterAll for Final Cleanup

test.afterAll(async () => {
  console.log('Checkout test suite finished');
});

This runs once after every test in the file completes, useful for tasks such as clearing temporary test data created during the run.

A Real-World Example: An E-Commerce Suite

A test file covering the shopping cart uses beforeEach to log in and navigate to the products page automatically. Ten separate tests then each start from that same ready state, focusing purely on cart-specific actions instead of repeating login steps ten times.

Hooks Inside a Describe Block

test.describe('Cart Feature', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('https://example.com/cart');
  });

  test('shows empty cart message', async ({ page }) => {
    await expect(page.getByText('Your cart is empty')).toBeVisible();
  });
});

A hook placed inside a describe block only applies to tests within that same group, keeping different feature areas independent from each other.

Quick Practice Task

Take any two tests that repeat the same first few lines and move those lines into a shared beforeEach hook.

Key Takeaways

  • Hooks run setup and cleanup code automatically around tests.
  • beforeEach and afterEach run around every individual test.
  • beforeAll and afterAll run once for an entire test file.
  • Hooks reduce repeated code and keep tests focused on their real purpose.

Leave a Comment

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