All challenges · Foundations
Challenge 2 of 29 · Beginner-friendly · Foundations
Click a Button with getByRole
Find a control the way a user does, by its role and visible name, and act on it. You work out which control produces the result the challenge asks for.
Skills you will practise
- locators
- getByRole
- click
The concept
A user does not see div.btn-primary-2. They see a button that says “Save”. Playwright's getByRole() locates elements the same way: by their accessible role (button, link, checkbox) and their accessible name, which is usually the visible text or an aria-label.
Role-based locators are the first choice recommended in Playwright's own docs because they survive redesigns. If a developer swaps a class name or moves a button into a new wrapper, the role and name usually stay the same. They also nudge you towards accessible markup: if you cannot find a button by role, a screen reader user probably cannot either.
Locators in Playwright are lazy and strict. A locator is not resolved until you act on it, and if it matches more than one element when you click, Playwright throws rather than guessing.
The fragile version
await page.locator('.btn.btn-primary:nth-child(2)').click();Why it breaks: This depends on styling classes and DOM order. Add a new button, reorder the toolbar or rename a CSS class and the test either fails or, worse, clicks the wrong control.
A robust Playwright version
await page.getByRole('button', { name: 'Save' }).click();
// If several buttons share a name, narrow the scope:
await page.getByRole('dialog').getByRole('button', { name: 'Save' }).click();The locator describes what the user sees. Scoping to a container resolves ambiguity without relying on position.
This is a general example on a made-up page, not the challenge’s reference solution.
Common mistakes
- Using
.first()ornth()to silence a strict-mode error instead of scoping properly. - Matching names loosely:
name: 'Save'also matches “Save draft” unless you passexact: true. - Clicking an element that looks like a button but has no button role (a styled
div).
FAQ
Why does Playwright say my locator resolved to 2 elements?
Strict mode: actions need exactly one match. Make the name more specific, use exact: true, or scope to a parent region.
Is getByRole better than CSS selectors?
For user-facing controls, usually yes. It is tied to role and name rather than implementation details, so it changes less often.
How do I find the accessible name of a button?
Open browser DevTools, inspect the element and check the Accessibility pane, or use Playwright's codegen / pick locator tool.
Try it
Practise this in Challenge 2. 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.