Rayrun
← Back to Discord Forum

Question about PW constructor practice in POM (typescript) (solved)

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?"

6 replies

Question about PW constructor practice in POM (typescript)

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. 🙂

This is the problem with POM. It is not really a 'pattern' but more of a vague 'guideline'. Everyone does it differently....🙈

You can use https://github.com/Widen/lariat/ if you want to adhere to some framework.

I see, I also had the feeling that everyone was implementing things differently without a standard but I never could had a chat with anyone about this. It brings me ease of mind to realize that I was overthinking😀 Thank you both @.gleedo @shivaguy

Question about PW constructor practice in POM (typescript) (solved)

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

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 luc@ray.run.