Rayrun
← Back to Discord Forum

dynamic locator in POM

Hello, is there a way to create in page's constructor a parameterized locator? Something like this

this.streetOption = streetName => page.getByRole('treeitem', { name: ${streetName}) });

I want to pass an actual street's name as an argument in the test that will use the above locator, somehow.

A similar approach in TestCafe would look like this, for reference this.timeOffCard = id => Selector(div.card[data-id="${id}"]);

This thread is trying to answer question "Is there a way to create a parameterized locator in a page's constructor in Playwright's testing library?"

7 replies

Bad example of a dynamic locator but it works:

import { Locator, Page } from "@playwright/test";

export class homePage {
  readonly link: (text: string) => Locator;

  constructor(readonly page: Page) {
    this.link = (text: string) => page.locator("a", { hasText: text });
  }

  async clickLinkByText(text: string) {
    await this.link(text).click();
  }
}

Test:

test("Using dynamic locators", async ({ page }) => {
  const homePage = new homePage(page);
  await page.goto("/");
  await playwrightHomePage.clickLinkByText("GET STARTED");
});

Trying to find the similar approach you mentioned above as that would be useful to me too...

codendeavor

I feel that to use dynamic locators you must stick with the xpath approach

codendeavor

The new locators don't work with dynamic stuff

codendeavor

We have to use page.locator itself new locator strategies won't work

great, thanks for your suggestions! the code snippet looks good, I will try it out. Cheers!

@.gleedo I tried your approach but the line inside constructor's throw a TS error Type '(city: string) => Locator' is not assignable to type 'Locator'.

@iamrv Interesting...could be a tsconfig.json key/value difference here. I have target = ES2020 and module = commonjs

Answer

Creating Parameterized Locators in Playwright

Creating parameterized locators in Playwright is a breeze. You can use methods like getByRole, CSS selectors, XPath selectors, or test ids.

Using getByRole

The getByRole method lets you locate elements based on their role and accessible name. Here's how you can use it:

page.getByRole('button', { name: 'Sign in' })

This will locate a button element with the accessible name "Sign in".

Using CSS or XPath Selectors

You can also use CSS or XPath selectors with the locator method. Playwright automatically detects them if you omit the prefix (css= or xpath=). But remember, long CSS or XPath chains can lead to unstable tests when the DOM structure changes.

page.locator('.my-class')
page.locator('//div[@id="my-id"]')

Using Test Ids

Defining an explicit testing contract using test ids is another great option. This approach can lead to more resilient tests.

page.locator('[data-testid="my-test-id"]')

Playwright also supports locating elements within Shadow DOM by default. But, there may be exceptions where certain locators do not work within Shadow DOM.

Remember, the key is to come up with locators that closely resemble how users perceive the page. For more insights, check out Understanding the Difference Between Locators and Selectors in @playwright/test.

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.