Search code examples
typescriptplaywright

Filter for a class and role in Playwright?


I want to filter for a link with the navbar__brand class on the Playwright website - via Playwright:

enter image description here

My code:

test("homepage has title and links to intro page", async ({ page }) => {
  await page.goto("https://playwright.dev/");

  const links = page.getByRole("link").locator(".navbar__brand");

  const count = await links.count();
  console.log("count is " + count); // zero instead of the expected one!
});

What am I doing wrong? Why doesn't it find the link?


Solution

  • It's not finding the link because the locator is only searching children of the <a> element, already found by getByRole. In other words, it can't find itself in its children.

    If I understand your HTML correctly, the :scope pseudoselector should work, which essentially lets an element query itself as well as its children:

    const playwright = require("playwright"); // ^1.28.1
    
    const html = `<a class="navbar__brand" href="/">hello world</a>`;
    
    let browser;
    (async () => {
      browser = await playwright.chromium.launch();
      const page = await browser.newPage();
      await page.setContent(html);
      const result = await page.getByRole("link")
        .locator(":scope.navbar__brand") // or ".navbar__brand:scope"
        .textContent();
      console.log(result); // => hello world
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    Of course, page.getByRole("a.navbar__brand") is possible but less of a best practice web-first selection than selecting by role. Then again, .navbar__brand isn't web-first either, so ideally you'd combine everything into one page.getByRole("link", {name: "link text"}) call.