KailashPathak
4 min readMar 20, 2025

--

Playwright Fixtures or POM: Which One Should You Choose?

Playwright Fixtures and traditional Page Object Models (POM) are both used in test automation, but they serve different purposes and can be integrated for better results. Playwright Fixtures help set up and manage test environments, while POM organizes page interactions. In Playwright, you can use fixtures to handle POM instances, making tests cleaner and more maintainable.

Traditional POM Approach?

POM (Page Object Model) is a design pattern where you create separate classes for each page and manually create objects in each test.

class LoginPage {
constructor(page) {
this.page = page;
this.usernameInput = "#username";
this.passwordInput = "#password";
this.loginButton = "#login";
}

async goToLoginPage() {
await this.page.goto("https://example.com/login");
}

async enterUsername(username) {
await this.page.fill(this.usernameInput, username);
}

async enterPassword(password) {
await this.page.fill(this.passwordInput, password);
}

async clickLoginButton() {
await this.page.click(this.loginButton);
}
}

export { LoginPage };
import { test, expect } from "@playwright/test";
import { LoginPage } from "../pages/loginPage";

test("Login Test", async ({ page }) => {
const loginPage = new LoginPage(page);

await loginPage.goToLoginPage();
await loginPage.enterUsername("testuser");
await loginPage.enterPassword("password");
await loginPage.clickLoginButton();

expect(await page.url()).toBe("https://example.com/home");
});

Limitations in the Traditional POM Approach

  • Code Duplication — You have to create new LoginPage(page) in every test.
  • Hard to Maintain — If LoginPage changes, all test files using it must be updated.
  • Longer Test Setup — Every test has repeated setup code (new LoginPage(page)).

** — Get Book On Playwright Here — Click Now — **

Playwright Fixture Approach

Playwright Fixtures are built-in mechanisms to manage reusable objects (like LoginPage). Instead of creating objects manually, fixtures inject them automatically.

Let see below code where we have loginPage class, fixture class and finally test class where we executing our test cases

loginPage.js (Same Page Object)

class LoginPage {
constructor(page) {
this.page = page;
this.usernameInput = "#username";
this.passwordInput = "#password";
this.loginButton = "#login";
}

async goToLoginPage() {
await this.page.goto("https://example.com/login");
}

async enterUsername(username) {
await this.page.fill(this.usernameInput, username);
}

async enterPassword(password) {
await this.page.fill(this.passwordInput, password);
}

async clickLoginButton() {
await this.page.click(this.loginButton);
}
}

export { LoginPage };

fixture.js (Fixture Definition)

We can create custom fixtures for your tests to provide reusable objects or actions. For example, the loginPage fixture in the code you provided is a custom fixture for interacting with a login page.

import { test as base } from "@playwright/test";
import { LoginPage } from "../pages/loginPage";

export const test = base.extend({
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await use(loginPage);
}
});

export { expect } from "@playwright/test";

Summary of What This Code Does:

  1. Custom Test Fixture: It creates a custom fixture (loginPage) that initializes the LoginPage class using the current browser page object.
  2. Extending Base Test: This fixture is made available in tests that are defined using the extended test function (export const test = base.extend({...})).
  3. Using LoginPage: The loginPage fixture can be injected into the test and used to interact with the login page, for example, to perform login-related actions (like typing in credentials or clicking the login button).
  4. Exports expect: The expect assertion library is also exported, making it available for test assertions.

Test Case using Fixtures

Below code snippet tests the login functionality of a web application using a custom loginPagefixture.

import { test, expect } from "../utils/fixture";

test("Login Test", async ({ loginPage }) => {
await loginPage.goToLoginPage();
await loginPage.enterUsername("testuser");
await loginPage.enterPassword("password");
await loginPage.clickLoginButton();

expect(await loginPage.page.url()).toBe("https://example.com/home");
});

Benefit of Fixture-Based Approach ?

Using fixtures (like in your code) removes duplication and makes tests cleaner.

1️No Need to Create Objects in Every Test

Instead of const loginPage = new LoginPage(page); in every test, we automatically inject loginPage using Playwright fixtures.

2️Improved Readability & Maintainability

  • If the LoginPage constructor changes, we only update it in one place (fixtures).
  • All tests automatically use the updated version.

3️Faster Test Execution (Fixture Reuse)

  • Playwright reuses fixtures across tests when possible.
  • If multiple tests use the same page (e.g loginPage and inventoryPage), Playwright does not create a new object every time, which speeds up execution.

4️Shared Setup for Multiple Tests

  • If all tests require login, you can automate it in the fixture instead of repeating login in every test.
export const test = base.extend<SauceDemoFixtures>({
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await loginPage.goToLoginPage();
await loginPage.enterUsername("testuser");
await loginPage.enterPassword("password");
await loginPage.clickLoginButton();
await use(loginPage);
},
});

5️Cleaner and More Scalable Test Suite

  • As the project grows, managing hundreds of test cases with traditional POM can be painful.
  • With fixtures, the test structure stays organized even with many test cases.

When to Use Fixtures vs. POM?

The choice between Fixtures and the Page Object Model (POM) depends on the use case in test automation.

Conclusion:

By using Playwright’s base.extend and combining it with the Page Object Model (POM), you're creating a clean, maintainable, and efficient test suite. This approach allows you to manage page-specific interactions in dedicated classes while leveraging fixtures to handle setup and teardown, making the tests simpler and faster to maintain as your project grows.

--

--

KailashPathak
KailashPathak

Written by KailashPathak

Author of book "Web Automation Testing Using Playwright", is a certified PMI-ACP®, ITIL®, PRINCE2 Practitioner®, ISTQB, professional.

Responses (6)

Write a response