Use Playwright getByTestId() locator with your own custom test id name.

One of the new page locators that was released with v1.27 was await page.getByTestId("username") makes utilizing custom test attributes easy!

Take the example HTML below for a login. In the 3 input fields there is a custom data attribute data-test-id below.

<!DOCTYPE html>
        <div class="box">
            <div class="form">
                <div class="inputBox">
                    <input data-test-id="username" type="text" required="required">
                <div class="inputBox">
                    <input data-test-id="password" type="password" required="required">
                <input data-test-id="login" type="submit" value="Login">
</html> example

These are hidden identifier that can be added to elements within a web page during development to make a site more testable. The problem is there is no standard for these test ids. For example in the Cypress documentation they call out three different patterns:

  • data-cy
  • data-test
  • data-testid

While Playwright documentation gives examples:

  • data-test
  • data-testid
  • data-test-id

And in other places around the web I've seent examples such as:

  • data-qa-id
  • data-qe-id
  • data-test-automation
  • etc

Back to Playwright this new locator page.getByTestId("username") needs to know which custom attribute name is being used. Playwright by default expects data-testid. If you use any custom attribute name that is different, you have to explicitly configure this in within Playwright. See the example below where I am set testIdAttribute to 'data-test-id'.

# playwright.config.ts
const config: PlaywrightTestConfig = {
  use: {
    browserName: "chromium",
    headless: true,
    screenshot: "only-on-failure",
    testIdAttribute: 'data-test-id',

Once this is set you will be able to successfully interact with the custom data attribute ids using the getByTestId! This is an example taking the above HTML and interacting with it via Playwright test. This is easy to read, and much cleaner than what was previously needed.

import { test, expect } from "@playwright/test";

test("basic test", async ({ page }) => {
  await page.goto("");

  await page.getByTestId("username").fill("Butch");          // new way
  await page.locator("data-test-id=username").fill("Butch"); // old way

  await page.getByTestId("password").fill("Password");
  await page.getByTestId("login").click();
  await expect(page).toHaveTitle(/Dashboard/);

Thanks for reading! If you found this helpful, reach out and let me know on LinkedIn or consider buying me a cup of coffee.