Skip to contentPlayForge

How do I filter a list of elements by text in Playwright?

Written by Jatin Thacker, Automation Architect · Updated

Call filter({ hasText: 'some text' }) on a locator that matches the whole list; it keeps only the elements that contain that text somewhere inside them. Use hasNotText to keep the ones that do not.

This answer is one piece of Chapter 10: Locators II: Scoping and Rot.

  • Scoping and Filtering
  • CSS Selectors, and the Ones That Rot
  • XPath, and What Replaced It
  • Locators That Rot
  • Locator Factories
  • Practice and interview questions: Locators Masterclass

A list locator such as page.getByTestId('order-row') matches every row. filter() narrows it without losing what the row is, so you can keep working inside the row you want.

hasText searches anywhere inside each element, including its children. With a string, the match is case-insensitive and finds substrings, so 'cancelled' matches a row whose badge reads Cancelled. Pass a regular expression when you need more control.

The orders table at ?seed=42 shows ten rows on page one:

  • rows.filter({ hasText: 'cancelled' }) matches two rows, ORD-4104 and ORD-4108.
  • rows.filter({ hasText: 'ORD-4104' }) matches one row, and getByTestId('cell-customer') inside it reads Nikhil Varma.
  • rows.filter({ hasNotText: 'Cancelled' }) keeps the other eight.

Watch the substring rule. Filtering for 'ORD-410' would match ten rows, not one, because every id on the page starts that way. Pick text that only the row you want contains, or use a regular expression with anchors.

qa-045.spec.js(https://practice.learnplayforge.com)
import { test, expect } from '@playwright/test'; test('filter order rows by the text they contain', async ({ page }) => { await page.goto('/orders.html?mock=static&seed=42&autologin=1'); const rows = page.getByTestId('order-row'); await expect(rows).toHaveCount(10); // A string matches as a case-insensitive substring await expect(rows.filter({ hasText: 'cancelled' })).toHaveCount(2); // Filter down to one row, then look inside it const order = rows.filter({ hasText: 'ORD-4104' }); await expect(order.getByTestId('cell-customer')).toHaveText('Nikhil Varma'); // hasNotText keeps the rows that do not contain the text await expect(rows.filter({ hasNotText: 'Cancelled' })).toHaveCount(8); });
Output
1 passed (2.3s)
Test yourself
A row's status badge reads Cancelled. Does rows.filter({ hasText: 'cancelled' }) keep that row?

Practised in the full course: the drill One row out of ten.

See the chapter

AI can write the test now. The job is knowing whether it checks anything. That's what the course teaches, one chapter at a time.

163 lessons · 226 drills · start free

← All questions

Training a team? Talk to us.