Playwright Test Lifecycle – Complete Beginner Guide with Hooks, Fixtures & Execution Flow (2026 Guide)

Introduction: Why Every Playwright Engineer Should Understand the Playwright Test Lifecycle

If you are learning Playwright Automation Testing, one of the most important topics you should understand is the Playwright Test Lifecycle.

Many beginners learn how to write Playwright scripts but don’t know what happens internally before and after a test runs. Understanding the lifecycle helps you organize your tests, manage resources efficiently, and build scalable automation frameworks.

Whether you are:

  • A QA Automation Engineer
  • An SDET
  • A Selenium engineer transitioning to Playwright
  • A Software Testing Student
  • A Developer learning Playwright
  • Preparing for Playwright interviews

Learning the Playwright Test Lifecycle will help you write cleaner, reusable, and more maintainable automation code.

In this guide, you’ll learn:

  • What the Playwright Test Lifecycle is
  • How Playwright executes tests
  • Hooks (beforeAll, beforeEach, afterEach, afterAll)
  • Browser, BrowserContext, and Page lifecycle
  • Fixtures and execution flow
  • Enterprise framework implementation
  • Best practices
  • Interview questions
  • FAQs

Let’s begin with the fundamentals.


What Is the Playwright Test Lifecycle?

The Playwright Test Lifecycle is the sequence of events that Playwright follows while executing automation tests.

It starts when the Playwright Test Runner begins execution and ends after all resources are cleaned up.

Simple Definition

The Playwright Test Lifecycle is the complete execution flow of a Playwright test, including setup, hooks, fixtures, test execution, cleanup, and reporting.

Understanding this lifecycle helps you:

  • Organize test execution
  • Avoid duplicate code
  • Manage browsers efficiently
  • Reduce flaky tests
  • Build enterprise-ready automation frameworks

Why Is the Playwright Test Lifecycle Important?

Understanding the lifecycle provides several benefits:

  • Cleaner test organization
  • Better resource management
  • Faster execution
  • Improved test isolation
  • Easier debugging
  • Reusable setup and teardown logic

Most automation interviewers ask lifecycle-related questions because they indicate your understanding of Playwright’s architecture.


Playwright Test Execution Flow

The Playwright Test Runner follows a well-defined execution order.

Playwright Test Runner

        │

        ▼

beforeAll()

        │

        ▼

beforeEach()

        │

        ▼

Test Execution

        │

        ▼

afterEach()

        │

        ▼

afterAll()

        │

        ▼

HTML Report

Every Playwright test follows this lifecycle.


How the Playwright Test Lifecycle Works

Let’s understand each stage.

1. Test Runner Starts

The Playwright Test Runner begins execution.

It:

  • Reads configuration
  • Discovers test files
  • Creates workers
  • Loads fixtures

2. beforeAll()

Runs once before any test in the file.

Common uses:

  • Launch database
  • Initialize API clients
  • Create test data
  • Read configuration

3. beforeEach()

Runs before every individual test.

Common uses:

  • Login
  • Open application
  • Create Browser Context
  • Prepare test data

4. Test Execution

The actual automation steps run here.

Example:

  • Login
  • Search
  • Add product
  • Checkout

5. afterEach()

Runs after every test.

Common uses:

  • Capture screenshots
  • Close Browser Context
  • Delete test data
  • Clear temporary files

6. afterAll()

Runs once after all tests finish.

Common uses:

  • Close browser
  • Disconnect database
  • Generate reports
  • Send notifications

Lifecycle Diagram (Text-Based)

Playwright Test Runner

       │

       ▼

beforeAll()

       │

       ▼

beforeEach()

       │

       ▼

Browser Launch

       │

       ▼

Browser Context

       │

       ▼

Page

       │

       ▼

Test Steps

       │

       ▼

Assertions

       │

       ▼

afterEach()

       │

       ▼

afterAll()

       │

       ▼

HTML Report


Browser, BrowserContext, and Page Lifecycle

Playwright manages browser resources efficiently.

Browser

   │

   ▼

Browser Context

   │

   ▼

Page

   │

   ▼

Website

Browser

Represents the browser instance.

Example:

const browser = await chromium.launch();


Browser Context

Represents an isolated session.

Example:

const context = await browser.newContext();


Page

Represents a browser tab.

Example:

const page = await context.newPage();

Each component is created and destroyed according to the lifecycle, ensuring test isolation.


Real-World Example

Imagine testing an e-commerce website.

The lifecycle is:

  1. Launch browser
  2. Create Browser Context
  3. Open page
  4. Login
  5. Search product
  6. Add to cart
  7. Checkout
  8. Verify confirmation
  9. Close context
  10. Close browser

Following this sequence keeps tests isolated and repeatable.

Understanding Hooks in the Playwright Test Lifecycle

Hooks are one of the most important concepts in the Playwright Test Lifecycle. They allow you to execute setup and cleanup code automatically before or after tests.

Instead of repeating the same code in every test, you can place it inside hooks.

For example, imagine you have 100 login test cases.

Without hooks, you would have to open the browser and navigate to the application 100 times by writing the same code repeatedly.

Hooks solve this problem.


What Are Playwright Hooks?

Playwright provides four lifecycle hooks:

  • beforeAll()
  • beforeEach()
  • afterEach()
  • afterAll()

Each hook runs at a different stage of the Playwright Test Lifecycle.

Playwright Test Runner

        │

        ▼

beforeAll()

        │

        ▼

beforeEach()

        │

        ▼

Test Execution

        │

        ▼

afterEach()

        │

        ▼

afterAll()

Let’s understand each hook with practical examples.


beforeAll()

The beforeAll() hook runs only once before all tests in a test file.

It is commonly used for:

  • Launching a browser
  • Reading configuration files
  • Connecting to a database
  • Creating test data
  • Setting up APIs

Example

import { test } from ‘@playwright/test’;

test.beforeAll(async () => {

    console.log(“Opening Application Resources”);

});

test(“Test 1”, async () => {

    console.log(“Running Test 1”);

});

test(“Test 2”, async () => {

    console.log(“Running Test 2”);

});

Output

Opening Application Resources

Running Test 1

Running Test 2

Notice that beforeAll() executes only once.


beforeEach()

The beforeEach() hook runs before every test case.

It is the most commonly used Playwright hook.

Typical uses include:

  • Login
  • Opening the application
  • Creating Browser Context
  • Creating Page objects
  • Preparing test data

Example

import { test } from ‘@playwright/test’;

test.beforeEach(async ({ page }) => {

    await page.goto(“https://example.com”);

});

test(“Home Page”, async ({ page }) => {

    console.log(“Executing Home Test”);

});

test(“About Page”, async ({ page }) => {

    console.log(“Executing About Test”);

});

Execution Flow

beforeEach()

Home Page Test

beforeEach()

About Page Test

Each test starts with a fresh setup.


afterEach()

The afterEach() hook executes after every test.

It is commonly used for:

  • Capturing screenshots
  • Closing Browser Context
  • Logging results
  • Cleaning test data
  • Removing temporary files

Example

import { test } from ‘@playwright/test’;

test.afterEach(async () => {

    console.log(“Cleaning Test Data”);

});

test(“Login Test”, async () => {

    console.log(“Executing Login”);

});

Output

Executing Login

Cleaning Test Data


afterAll()

The afterAll() hook runs once after every test has completed.

Typical uses:

  • Close browser
  • Disconnect database
  • Generate reports
  • Send email notifications

Example

import { test } from ‘@playwright/test’;

test.afterAll(async () => {

    console.log(“Closing Browser”);

});

test(“Test One”, async () => {

});

test(“Test Two”, async () => {

});

Output

Test One

Test Two

Closing Browser


Complete Hook Execution Order

Suppose we have two test cases.

import { test } from ‘@playwright/test’;

test.beforeAll(async () => {

    console.log(“beforeAll”);

});

test.beforeEach(async () => {

    console.log(“beforeEach”);

});

test.afterEach(async () => {

    console.log(“afterEach”);

});

test.afterAll(async () => {

    console.log(“afterAll”);

});

test(“Test 1”, async () => {

    console.log(“Executing Test 1”);

});

test(“Test 2”, async () => {

    console.log(“Executing Test 2”);

});

Output

beforeAll

beforeEach

Executing Test 1

afterEach

beforeEach

Executing Test 2

afterEach

afterAll

This sequence represents the standard Playwright Test Lifecycle.


Test Fixtures and Lifecycle

Fixtures provide reusable resources for your tests. Playwright automatically creates and cleans them up based on their scope.

Common built-in fixtures include:

  • browser
  • context
  • page
  • request

Example:

import { test, expect } from ‘@playwright/test’;

test(“Login Test”, async ({ page }) => {

    await page.goto(“https://example.com”);

    await expect(page).toHaveTitle(/Example/);

});

Here, the page fixture is created before the test begins and cleaned up automatically afterward.


Fixture Scope

Playwright supports different fixture scopes.

ScopeDescription
Test ScopeA new fixture instance is created for every test.
Worker ScopeOne fixture instance is shared across tests running in the same worker process.

Test Scope

Use when each test should have a completely isolated environment.

Example:

Test 1

New BrowserContext

New Page

—————-

Test 2

New BrowserContext

New Page

Worker Scope

Use for expensive resources that can safely be shared within a worker.

Examples:

  • Database connections
  • API clients
  • Configuration
  • Shared authentication setup

Real-World Enterprise Lifecycle

Most enterprise Playwright frameworks follow this flow:

Playwright Test Runner

        │

        ▼

Load Configuration

        │

        ▼

beforeAll()

        │

        ▼

Create Browser

        │

        ▼

beforeEach()

        │

        ▼

Create BrowserContext

        │

        ▼

Create Page

        │

        ▼

Execute Test

        │

        ▼

Capture Screenshots (if needed)

        │

        ▼

afterEach()

        │

        ▼

Close BrowserContext

        │

        ▼

afterAll()

        │

        ▼

Close Browser

        │

        ▼

Generate HTML Report

This approach keeps tests isolated, reusable, and easy to maintain.


Why Hooks Matter in Enterprise Projects

Hooks help automation teams:

  • Reduce duplicate code
  • Improve framework maintainability
  • Manage browser resources efficiently
  • Ensure consistent test setup and cleanup
  • Build scalable automation frameworks for large projects

Best Practices for Managing the Playwright Test Lifecycle

Managing the Playwright Test Lifecycle correctly is one of the biggest differences between a beginner and an experienced automation engineer. A well-designed lifecycle improves execution speed, reduces flaky tests, and makes automation frameworks easier to maintain.

Follow these best practices to build scalable Playwright frameworks.


1. Use Hooks Only for Common Setup and Cleanup

Hooks should contain only reusable setup and cleanup code.

Good Examples

  • Launch Browser
  • Create Browser Context
  • Open Application
  • Login
  • Capture Screenshot
  • Close Browser Context

Avoid

  • Business validations
  • Assertions
  • Test-specific logic

Keep test-specific actions inside the actual test case.


2. Create a Fresh Browser Context for Every Test

Playwright is designed around isolated Browser Contexts.

Example:

test.beforeEach(async ({ browser }) => {

    const context = await browser.newContext();

});

Benefits

  • Independent sessions
  • Fresh cookies
  • Fresh Local Storage
  • No shared login
  • Reliable execution

3. Close Browser Context After Every Test

Always clean resources.

Example

test.afterEach(async ({ context }) => {

    await context.close();

});

This:

  • Releases memory
  • Removes temporary data
  • Improves execution speed

4. Keep beforeAll() Lightweight

Good use cases:

  • Read Configuration
  • Load Test Data
  • Connect Database
  • Create API Client

Avoid launching Pages or Browser Contexts here unless they are intentionally shared.


5. Prefer Fixtures Over Global Variables

Bad Practice

let page;

Good Practice

test(‘Login’, async ({ page }) => {

});

Fixtures improve readability and prevent shared state issues.


6. Never Use Hard Waits

Avoid

await page.waitForTimeout(5000);

Instead

await page.getByRole(‘button’, {

    name: ‘Login’

}).click();

Playwright automatically waits for elements to become actionable.


7. Use Page Object Model (POM)

Separate page logic from test logic.

Example Structure

tests/

pages/

fixtures/

utils/

config/

reports/

This makes your framework modular and maintainable.


8. Keep Tests Independent

Every test should:

  • Create its own data
  • Use its own Browser Context
  • Run without depending on previous tests

Independent tests are easier to debug and execute in parallel.


9. Capture Screenshots on Failure

Example

test.afterEach(async ({ page }, testInfo) => {

    if (testInfo.status !== testInfo.expectedStatus) {

        await page.screenshot({

            path: ‘failure.png’

        });

    }

});

Screenshots help identify UI issues quickly.


10. Use HTML Reports

Enable Playwright’s built-in HTML Reporter to review execution results, screenshots, traces, and failure details.


Common Mistakes to Avoid

Many automation engineers make lifecycle-related mistakes that lead to unstable frameworks.


Mistake 1: Repeating Login in Every Test

Instead of writing:

await page.goto(…);

await page.fill(…);

await page.click(…);

inside every test, move common setup into beforeEach() or reusable fixtures.


Mistake 2: Using One Browser Context Everywhere

Sharing one Browser Context causes:

  • Shared cookies
  • Shared authentication
  • Flaky tests

Create a new Browser Context for independent tests.


Mistake 3: Forgetting Cleanup

Always close:

  • Browser Context
  • Browser
  • Database Connections
  • Temporary Files

Mistake 4: Putting Assertions Inside Hooks

Avoid

test.beforeEach(async () => {

    expect(…);

});

Assertions belong inside test cases.


Mistake 5: Large beforeEach() Methods

Avoid performing unnecessary setup.

Keep hooks focused and efficient.


Playwright Test Lifecycle vs Selenium TestNG Lifecycle

Many Selenium engineers transitioning to Playwright ask how the lifecycle compares.

FeaturePlaywrightSelenium + TestNG
Test RunnerBuilt-inExternal (TestNG/JUnit)
HooksbeforeAll, beforeEach, afterEach, afterAll@BeforeSuite, @BeforeClass, @BeforeMethod, @AfterMethod, etc.
Browser ManagementBuilt-inManual
Browser ContextBuilt-inNot available
Auto WaitingYesManual waits required
Parallel ExecutionBuilt-inConfiguration required
HTML ReportsBuilt-inThird-party tools often used
FixturesBuilt-inCustom implementation

Enterprise Test Lifecycle Workflow

Large organizations follow a structured execution flow.

Developer Commit

        │

        ▼

GitHub / Azure DevOps

        │

        ▼

Playwright Test Runner

        │

        ▼

Load Configuration

        │

        ▼

beforeAll()

        │

        ▼

beforeEach()

        │

        ▼

Create BrowserContext

        │

        ▼

Create Page

        │

        ▼

Execute Test

        │

        ▼

Assertions

        │

        ▼

Capture Screenshot (On Failure)

        │

        ▼

afterEach()

        │

        ▼

Close BrowserContext

        │

        ▼

afterAll()

        │

        ▼

Generate HTML Report

        │

        ▼

CI/CD Pipeline Result

This lifecycle ensures consistent execution across local environments and CI/CD pipelines.


Playwright Test Lifecycle Interview Questions

1. What is the Playwright Test Lifecycle?

Answer:
The Playwright Test Lifecycle is the sequence of events that occurs during test execution, including setup, hooks, fixtures, test execution, cleanup, and reporting.


2. Which hooks are available in Playwright?

Answer:

  • beforeAll()
  • beforeEach()
  • afterEach()
  • afterAll()

3. What is the purpose of beforeEach()?

Answer:
It runs before every test and is commonly used to navigate to the application, log in, or prepare test data.


4. What is the purpose of afterEach()?

Answer:
It performs cleanup after each test, such as closing Browser Contexts, capturing screenshots, or deleting temporary data.


5. What are Playwright fixtures?

Answer:
Fixtures are reusable resources provided by Playwright, such as browser, context, page, and request, which simplify setup and cleanup.


6. What is the difference between Test Scope and Worker Scope?

Answer:

  • Test Scope: Creates a new fixture instance for each test.
  • Worker Scope: Shares a fixture instance across tests running in the same worker process.

7. Why should Browser Contexts be closed after tests?

Answer:
Closing Browser Contexts releases memory, removes session data, and keeps tests isolated.


8. Why is the Playwright Test Lifecycle important?

Answer:
It helps organize setup and cleanup, improves maintainability, enables resource management, and supports scalable automation frameworks.


9. How does Playwright improve test reliability?

Answer:
Playwright provides Auto Waiting, isolated Browser Contexts, built-in fixtures, and predictable lifecycle management.


10. How does Playwright differ from Selenium in lifecycle management?

Answer:
Playwright includes a built-in test runner, hooks, fixtures, and browser management, whereas Selenium typically relies on external frameworks like TestNG or JUnit for lifecycle management.


Frequently Asked Questions (FAQs)

What is the Playwright Test Lifecycle?

It is the complete sequence of setup, execution, cleanup, and reporting performed by Playwright while running tests.


Why are hooks important?

Hooks reduce duplicate code by handling common setup and teardown tasks automatically.


When should I use beforeAll()?

Use it for tasks that should run once, such as loading configuration or creating shared resources.


When should I use beforeEach()?

Use it for tasks that every test requires, such as opening the application or creating a fresh Browser Context.


Can I use multiple hooks in one file?

Yes. You can use all four lifecycle hooks together in the same test file.


What are fixtures in Playwright?

Fixtures are reusable objects that automatically manage resources like browsers, pages, contexts, and API clients.


Should every test create a new Browser Context?

For most UI tests, yes. This ensures proper isolation and prevents session leakage between tests.


Does Playwright automatically clean up resources?

Yes. Built-in fixtures are cleaned up automatically, but custom resources should also be closed explicitly when needed.

Leave a Comment

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