Skip to main content
Version: 1.12.0

Page Object Model

Page Object Model is a common pattern that introduces abstractions over web app pages to simplify interactions with them in multiple tests. It is best explained by an example.

We will create a PlaywrightDevPage helper class to encapsulate common operations on the playwright.dev page. Internally, it will use the page object.

// playwright-dev-page.ts
import type { Page } from 'playwright';
export class PlaywrightDevPage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async goto() {
await this.page.goto('https://playwright.dev');
}
async toc() {
const text = await this.page.innerText('article ul');
return text.split('\n').filter(line => !!line);
}
async getStarted() {
await this.page.click('text=Get started');
await this.page.waitForSelector(`text=Core concepts`);
}
async coreConcepts() {
await this.getStarted();
await this.page.click('text=Core concepts');
await this.page.waitForSelector(`h1:has-text("Core concepts")`);
}
}

Now we can use the PlaywrightDevPage class in our tests.

// example.spec.ts
import { test, expect } from '@playwright/test';
import { PlaywrightDevPage } from './playwright-dev-page';
test('Get Started table of contents', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.getStarted();
expect(await playwrightDev.toc()).toEqual([
'Installation',
'Usage',
'First script',
'Record scripts',
'TypeScript support',
'System requirements',
'Release notes'
]);
});
test('Core Concepts table of contents', async ({ page }) => {
const playwrightDev = new PlaywrightDevPage(page);
await playwrightDev.goto();
await playwrightDev.coreConcepts();
expect(await playwrightDev.toc()).toEqual([
'Browser',
'Browser contexts',
'Pages and frames',
'Selectors',
'Auto-waiting',
'Execution contexts: Playwright and Browser',
'Evaluation Argument'
]);
});