Page Object Model
Build a maintainable, scalable test suite that doesn't break every time the UI changes.
🏗️ Why POM Matters
Without POM, if a button's selector changes, you update it in 20 test files. With POM, you update it in one place.
❌ Without POM
// test1.spec.ts
await page.locator('#login-btn').click();
// test2.spec.ts
await page.locator('#login-btn').click();
// test3.spec.ts
await page.locator('#login-btn').click();
// When selector changes → update 3+ files✅ With POM
// pages/login.page.ts
get loginBtn() {
return this.page.locator('#login-btn');
}
// test1/2/3.spec.ts
await loginPage.loginBtn.click();
// Selector changes → update 1 file🏛️ Building Your First Page Object
1. Create the Page Object Class
pages/LoginPage.ts
import { Page, Locator } from '@playwright/test';
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel('Email');
this.passwordInput = page.getByLabel('Password');
this.submitButton = page.getByRole('button', { name: 'Sign In' });
this.errorMessage = page.getByRole('alert');
}
async navigate() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}2. Use It in Your Tests
tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
test('successful login', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login('user@test.com', 'password123');
await expect(page).toHaveURL('/dashboard');
});
test('shows error for invalid credentials', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login('bad@email.com', 'wrongpass');
await expect(loginPage.errorMessage).toBeVisible();
});📝 Module Quiz
Test Your Knowledge
Score 70%+ to advance to the next module
Question 1 of 4
0 answered
Q1. What is the primary benefit of the Page Object Model pattern?
Q2. In the Page Object Model, what does the constructor typically do?
Q3. Where should navigation logic (like calling page.goto()) be placed in POM?
Q4. What is PageFactory in the context of Playwright's POM?