I want to filter for a link with the navbar__brand
class on the Playwright website - via Playwright:
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?
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:
import {expect, test} from "@playwright/test"; // ^1.46.1
test("nav link has text 'hello world'", async ({page}) => {
const html = `<a class="navbar__brand" href="/">hello world</a>`;
await page.setContent(html); // for demonstration
const navLink = page
.getByRole("link")
.locator(":scope.navbar__brand"); // or ".navbar__brand:scope"
await expect(navLink).toHaveText("hello world");
});
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.