Hi I wanted to ask about the POM implementation in PW.
When I read the page I see all properties (locators in this case) implemented in the constructor. Why take this approach? it seems like an anti pattern at first glance. I am on the other side trying to inherit only page and let the properties handle the rest without passing them in the constructor.
PW example docs
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: 'Guides' }).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');
}
etc
In my case I would do something like (note the inheritance that lets me implement this pattern)
import { expect, Locator, Page } from '@playwright/test';
export class PlaywrightDevPage extends BasePage {
readonly page: Page;
readonly getStartedLink: Locator = this.page.locator('a', { hasText: 'Get started' });;
readonly gettingStartedHeader: Locator = this.page.locator('h1', { hasText: 'Installation' });;
readonly pomLink: Locator = this.page.locator('li', { hasText: 'Guides' }).locator('a', { hasText: 'Page Object Model' });;
readonly tocList: Locator = this.page.locator('article div.markdown ul > li > a');;
constructor(page: Page) {
super(page) = page;
}
async goto() {
await this.page.goto('https://playwright.dev');
}
etc
And maybe move the locators below the methods to avoid clogging with many properties
This thread is trying to answer question "Why does the POM implementation in PW use properties in the constructor, and is there a better approach?"
You're allowed to do whatever you want. Basically, examples in Playwright docs != recommendation from Playwright
Someone would argue that the inheritance is unnecessary in the example you shared.
import { Page } from '@playwright/test';
export class PlaywrightDevPage {
constructor(
readonly page: Page,
readonly getStartedLink = page.locator('a', { hasText: 'Get started' }),
readonly gettingStartedHeader = page.locator('h1', { hasText: 'Installation' }),
readonly pomLink = page.locator('li', { hasText: 'Guides' }).locator('a', { hasText: 'Page Object Model' }),
readonly tocList = page.locator('article div.markdown ul > li > a'),
) { }
async goto() {
await this.page.goto('https://playwright.dev');
}
}
It's just TypeScript. 🙂
You can use https://github.com/Widen/lariat/ if you want to adhere to some framework.
Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email [email protected].