All challenges · Foundations
Challenge 5 of 29 · Beginner-friendly · Foundations
Follow a Navigation Link
Move between pages by clicking a link found by its role and name. A hidden check confirms where you landed.
Skills you will practise
- link role
- accessible names
- navigation
The concept
Links are one of the most common things a test clicks, and they have their own role: link. Their accessible name comes from the visible link text, or from aria-label or an image's alt text when the link wraps an icon. getByRole('link', { name: 'Pricing' }) finds the link a user would read as “Pricing”.
Clicking a link usually triggers navigation. Playwright's click waits for the action itself, and your next assertion should confirm where you landed. expect(page).toHaveURL() retries until the URL matches, so you do not need to guess how long navigation takes.
Navigation menus often repeat the same link in a header, a footer and a mobile menu. When that happens, scope the locator to the region you mean, such as getByRole('navigation').
The fragile version
await page.locator('a[href="/p/2024/pricing-v3"]').click();Why it breaks: The href is an implementation detail. A URL restructure, a tracking parameter or a version bump breaks the test even though the user still sees the same “Pricing” link.
A robust Playwright version
await page.getByRole('navigation')
.getByRole('link', { name: 'Pricing' })
.click();
await expect(page).toHaveURL(/pricing/);It finds the link by what users read, scoped to the main navigation, and then checks the destination.
This is a general example on a made-up page, not the challenge’s reference solution.
Common mistakes
- Not asserting the destination, so a broken link still “passes”.
- Hitting strict-mode errors when the same link appears in header and footer.
- Using
getByTextfor links, which can also match plain text that is not clickable.
FAQ
What is the accessible name of a link?
Usually its text content. For icon links it comes from aria-label, title or a contained image's alt text.
How do I wait for navigation after a click?
Assert on the result: await expect(page).toHaveURL(...) retries until the URL matches.
Why does my link locator match two elements?
The link probably appears more than once. Scope it, for example to getByRole('navigation').
Try it
Practise this in Challenge 5. You write the code in the browser editor with no setup. It runs in a fresh Chromium, a hidden validator checks what actually happened, and you get pass or fail, the logs and a video of the run. Challenges 1 to 10 are open without an account; create a free one any time to keep your progress. The reference solution and the hidden validator are shown only after you pass. We never publish solutions here.