All challenges · Core Interactions
Challenge 15 of 29 · Building fluency · Core Interactions
Filter Table Rows
Narrow a locator to one table row by its text, then act on a control inside that row. The hidden check confirms you picked the right one.
Skills you will practise
- filter()
- tables
- scoped locators
The concept
Tables are full of repeated controls. Every row has an “Edit” button, so getByRole('button', { name: 'Edit' }) matches dozens. The fix is to narrow the search: first find the row you care about, then the control inside it.
locator.filter() keeps only matches that satisfy a condition. filter({ hasText: 'Ada Lovelace' }) keeps rows containing that text; filter({ has: page.getByRole('cell', { name: 'Overdue' }) }) keeps rows containing a matching element. Then you chain a locator onto the result to act inside that row only.
This is called scoping, and it is one of the most useful habits in Playwright: describe where something is in human terms, not by its index.
The fragile version
await page.locator('table tr:nth-child(3) td:nth-child(5) button').click();Why it breaks: Sort the table, add a row, or insert a column and this clicks the wrong person's button, without failing.
A robust Playwright version
const row = page.getByRole('row').filter({ hasText: 'Ada Lovelace' });
await row.getByRole('button', { name: 'Edit' }).click();
await expect(page.getByRole('dialog', { name: /edit ada lovelace/i })).toBeVisible();It finds the row by its content and the button by its role, so reordering does not matter.
This is a general example on a made-up page, not the challenge’s reference solution.
Common mistakes
- Filtering by text that appears in more than one row (for example a first name only).
- Using
nth()on rows after sorting or paging. - Filtering the cell instead of the row, then failing to find the button.
FAQ
What does filter() do in Playwright?
It narrows a locator to elements that contain given text (hasText) or a matching child (has).
What is the difference between filter hasText and getByText?
filter({ hasText }) keeps containers that include the text; getByText finds the element holding the text.
Can I filter out rows?
Yes, with hasNotText or hasNot.
Try it
Practise this in Challenge 15. 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. Create a free account to open the practice page and its hints. The reference solution and the hidden validator are shown only after you pass. We never publish solutions here.