diff --git a/docs/src/pom.md b/docs/src/pom.md index de866f1a2e..dfa42d06de 100644 --- a/docs/src/pom.md +++ b/docs/src/pom.md @@ -2,54 +2,198 @@ id: pom title: "Page Object Models" --- +Large test suites can be structured to optimize ease of authoring and maintenance. Page object models are one such approach to structure your test suite. -Large test suites can be structured to optimize ease of authoring and maintenance. Page object models are one such -approach to structure your test suite. +A page object represents a part of your web application. An e-commerce web application might have a home page, a listings page and a checkout page. Each of them can be represented by page object models. - - -## Playwright Test vs. Library -* langs: js - -:::caution -This guide is for [Playwright Library](./library.md), if you are using Playwright Test (`@playwright/test`) see [here](./test-pom.md). -::: - -## Introduction - -A page object represents a part of your web application. An e-commerce web application might have a home page, a -listings page and a checkout page. Each of them can be represented by page object models. - -Page objects **simplify authoring**. They create a higher-level API which suits your application. - -Page objects **simplify maintenance**. They capture element selectors in one place and create reusable code to avoid -repetition. +Page objects **simplify authoring** by creating a higher-level API which suits your application and **simplify maintenance** by capturing element selectors in one place and create reusable code to avoid repetition. ## Implementation +* langs: js -Page object models wrap over a Playwright [Page]. +We will create a `PlaywrightDevPage` helper class to encapsulate common operations on the `playwright.dev` page. Internally, it will use the `page` object. -```js -// models/Search.js -class SearchPage { +```js tab=js-js +// playwright-dev-page.js +const { expect } = require('@playwright/test'); + +exports.PlaywrightDevPage = class PlaywrightDevPage { + + /** + * @param {import('@playwright/test').Page} page + */ + constructor(page) { + this.page = page; + this.getStartedLink = page.locator('a', { hasText: 'Get started' }); + this.gettingStartedHeader = page.locator('h1', { hasText: 'Installation' }); + this.pomLink = page.locator('li', { hasText: 'Writing Tests' }).locator('a', { hasText: 'Page Object Model' }); + this.tocList = page.locator('article div.markdown ul > li > a'); + } + + async goto() { + await this.page.goto('https://playwright.dev'); + } + + async getStarted() { + await this.getStartedLink.first().click(); + await expect(this.gettingStartedHeader).toBeVisible(); + } + + async pageObjectModel() { + await this.getStarted(); + await this.pomLink.click(); + } +} +``` + +```js tab=js-ts +// playwright-dev-page.ts +import { expect, Locator, Page } from '@playwright/test'; + +export class PlaywrightDevPage { + readonly page: Page; + readonly getStartedLink: Locator; + readonly gettingStartedHeader: Locator; + readonly pomLink: Locator; + readonly tocList: Locator; + + constructor(page: Page) { + this.page = page; + this.getStartedLink = page.locator('a', { hasText: 'Get started' }); + this.gettingStartedHeader = page.locator('h1', { hasText: 'Installation' }); + this.pomLink = page.locator('li', { hasText: 'Playwright Test' }).locator('a', { hasText: 'Page Object Model' }); + this.tocList = page.locator('article div.markdown ul > li > a'); + } + + async goto() { + await this.page.goto('https://playwright.dev'); + } + + async getStarted() { + await this.getStartedLink.first().click(); + await expect(this.gettingStartedHeader).toBeVisible(); + } + + async pageObjectModel() { + await this.getStarted(); + await this.pomLink.click(); + } +} +``` + +```js tab=js-library +// models/PlaywrightDevPage.js +class PlaywrightDevPage { /** * @param {import('playwright').Page} page */ constructor(page) { this.page = page; - this.searchTermInput = page.locator('[aria-label="Enter your search term"]'); + this.getStartedLink = page.locator('a', { hasText: 'Get started' }); + this.gettingStartedHeader = page.locator('h1', { hasText: 'Installation' }); + this.pomLink = page.locator('li', { hasText: 'Playwright Test' }).locator('a', { hasText: 'Page Object Model' }); + this.tocList = page.locator('article div.markdown ul > li > a'); } - async navigate() { - await this.page.goto('https://bing.com'); + async getStarted() { + await this.getStartedLink.first().click(); + await expect(this.gettingStartedHeader).toBeVisible(); } - async search(text) { - await this.searchTermInput.fill(text); - await this.searchTermInput.press('Enter'); + + async pageObjectModel() { + await this.getStarted(); + await this.pomLink.click(); } } -module.exports = { SearchPage }; +module.exports = { PlaywrightDevPage }; ``` +Now we can use the `PlaywrightDevPage` class in our tests. + +```js tab=js-js +// example.spec.js +const { test, expect } = require('@playwright/test'); +const { PlaywrightDevPage } = require('./playwright-dev-page'); + +test('getting started should contain table of contents', async ({ page }) => { + const playwrightDev = new PlaywrightDevPage(page); + await playwrightDev.goto(); + await playwrightDev.getStarted(); + await expect(playwrightDev.tocList).toHaveText([ + `How to install Playwright`, + `What's Installed`, + `How to run the example test`, + `How to open the HTML test report`, + `Write tests using web first assertions, page fixtures and locators`, + `Run single tests, multiple tests, headed mode`, + `Generate tests with Codegen`, + `See a trace of your tests` + ]); +}); + +test('should show Page Object Model article', async ({ page }) => { + const playwrightDev = new PlaywrightDevPage(page); + await playwrightDev.goto(); + await playwrightDev.pageObjectModel(); + await expect(page.locator('article')).toContainText('Page Object Model is a common pattern'); +}); +``` + +```js tab=js-ts +// example.spec.ts +import { test, expect } from '@playwright/test'; +import { PlaywrightDevPage } from './playwright-dev-page'; + +test('getting started should contain table of contents', async ({ page }) => { + const playwrightDev = new PlaywrightDevPage(page); + await playwrightDev.goto(); + await playwrightDev.getStarted(); + await expect(playwrightDev.tocList).toHaveText([ + `How to install Playwright`, + `What's Installed`, + `How to run the example test`, + `How to open the HTML test report`, + `Write tests using web first assertions, page fixtures and locators`, + `Run single tests, multiple tests, headed mode`, + `Generate tests with Codegen`, + `See a trace of your tests` + ]); +}); + +test('should show Page Object Model article', async ({ page }) => { + const playwrightDev = new PlaywrightDevPage(page); + await playwrightDev.goto(); + await playwrightDev.pageObjectModel(); + await expect(page.locator('article')).toContainText('Page Object Model is a common pattern'); +}); +``` + +```js tab=js-library +// example.spec.js +const { PlaywrightDevPage } = require('./playwright-dev-page'); + +// In the test +const page = await browser.newPage(); +await playwrightDev.goto(); +await playwrightDev.getStarted(); +await expect(playwrightDev.tocList).toHaveText([ + 'Installation', + 'First test', + 'Configuration file', + 'Writing assertions', + 'Using test fixtures', + 'Using test hooks', + 'VS Code extension', + 'Command line', + 'Configure NPM scripts', + 'Release notes' +]); +``` + +## Implementation +* langs: java, csharp, python + +Page object models wrap over a Playwright [Page]. + ```java // models/SearchPage.java package models; @@ -138,17 +282,6 @@ public class SearchPage Page objects can then be used inside a test. -```js -// search.spec.js -const { SearchPage } = require('./models/Search'); - -// In the test -const page = await browser.newPage(); -const searchPage = new SearchPage(page); -await searchPage.navigate(); -await searchPage.search('search query'); -``` - ```java import models.SearchPage; import com.microsoft.playwright.*; @@ -191,6 +324,3 @@ var page = new SearchPage(await browser.NewPageAsync()); await page.GotoAsync(); await page.SearchAsync("search query"); ``` - -### API reference -- [Page]