Page Object Model in Playwright with TypeScript
Introduction
As a suite grows, repeating locators in every test makes maintenance painful. The Page Object Model (POM) puts a page's locators and actions into one class, so a change to the page means one fix instead of dozens. This lesson builds a page object for the TodoMVC demo app.
Prerequisites
- Locators and assertions in Playwright
- TypeScript classes
Step-by-Step Guide
Step 1: Create a page class
Store locators as readonly properties and wrap user actions in methods. Keep assertions in the tests, not the page object, so the class describes the page rather than the expectations.
// tests/pages/todo-page.ts
import { type Page, type Locator } from '@playwright/test';
export class TodoPage {
readonly page: Page;
readonly newTodo: Locator;
readonly titles: Locator;
constructor(page: Page) {
this.page = page;
this.newTodo = page.getByPlaceholder('What needs to be done?');
this.titles = page.getByTestId('todo-title');
}
async goto() {
await this.page.goto('/todomvc');
}
async addTodo(text: string) {
await this.newTodo.fill(text);
await this.newTodo.press('Enter');
}
}Step 2: Set a base URL
Configure baseURL so the page object can use relative paths and the same tests can target different environments.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: 'https://demo.playwright.dev',
},
});Step 3: Use the page object in a test
The test now reads like a description of the behavior, with no selectors in sight.
import { test, expect } from '@playwright/test';
import { TodoPage } from './pages/todo-page';
test('adds a todo item', async ({ page }) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await todoPage.addTodo('Buy milk');
await expect(todoPage.titles).toHaveText(['Buy milk']);
});Step 4: Keep page objects focused
Create one class per page or significant component. Return another page object from a method when an action navigates to a new page, and avoid putting test logic or hard-coded test data inside them.
FAQs
- Should page objects contain assertions?
- Most teams keep assertions in tests and only expose locators and actions in page objects. This keeps page objects reusable across tests that expect different outcomes.
- Is the Page Object Model required with Playwright?
- No. For small suites, plain tests and helper functions are fine. POM pays off as the suite and number of contributors grow.
Summary
A page object centralizes locators and actions for one page, which makes tests short and changes cheap. In the next lesson, fixtures remove the setup boilerplate from every test.
Comments
Log in or create a free account to join the discussion.