I spent hours debugging a flaky test that broke because of one line of XPath.
The fix? A single Playwright locator that took 10 seconds to write.
Here's what I wish I knew earlier.
The Hard Truth
If your tests are flaky, your locators are the problem.
Traditional XPath and CSS selectors navigate the DOM like a tree. The moment a developer reorders elements or changes structure — your tests break. Every. Single. Time.
// Brittle - breaks if DOM structure changes
page.locator('div#main > ul:nth-child(2) > li:first-child > button')
Human Vision vs Robot Vision
Playwright takes a completely different approach. Instead of hunting for IDs and class names (robot vision), it targets elements the way a real user would — by what they see on screen (human vision).
The gold standard? page.getByRole()
It taps into the accessibility tree — the same structure screen readers use. If a screen reader can find it, Playwright can test it. And it survives refactors.
// Smart - survives DOM changes
page.getByRole('button', { name: 'Sign up' })
The Locator Priority Hierarchy
Follow this order and you'll solve 80% of your locator problems:
1. getByRole — Always start here. Works for buttons, headings, checkboxes, links, and more.
2. getByText / getByLabel — Fall back to visible on-screen text or form labels.
3. getByTestId — Ask your dev to add a data-testid attribute. It's stable and won't change by accident.
4. CSS/XPath — Last resort only. Even then, paste it into an LLM — it'll convert it to a getByRole locator for you.
Bonus: No More sleep() Hacks
Playwright's built-in auto-wait means every locator automatically waits for the element to be attached, visible, stable, and enabled before acting. No more arbitrary timeouts.
js
// You no longer need this
await page.waitForTimeout(3000)
In this code snippet, the playwright library is being used to automatically handle clicking on a button element with the role of 'button' and the name 'Submit'. The code is locating the button using the getByRole query function and then triggering a click event on it using the click() method. This allows for automated interaction with the webpage in order to submit a form or perform some other action.y {
const submitButton = await page.getByRole('button', { name: 'Submit' });
await submitButton.click();
} catch(err) {
console.error("Error clicking submit button: ", err);
}
This is Part 2 of my Playwright 80/20 Pareto Principle series. Part 3 covers Playwright Actions — coming soon!
🎬 Watch the full video here: https://www.youtube.com/watch?v=6IaCQ70cNVc
Top comments (0)