DEV Community

Cover image for Filtering vs. Locating Elements by Text in Playwright: What’s the Difference?
Nathan Araújo
Nathan Araújo

Posted on

1

Filtering vs. Locating Elements by Text in Playwright: What’s the Difference?

When writing automated tests with Playwright, selecting elements efficiently is crucial to ensure reliable and maintainable test scripts. A common scenario is selecting an element that contains specific text inside a table. Playwright provides two approaches for this:

  • .filter({ hasText: 'TEXT' }) - filters elements that contain the specified text.
  • .locator('text=TEXT') - finds elements that match the exact text.

Both methods can be useful, but understanding their differences will help you write more robust selectors. Let’s dive into a practical example.

Example Scenario: Selecting a Button in a Table Row

Imagine you have the following table:

<table>
  <tr>
    <td>Processing</td>
    <td><button>Retry</button></td>
  </tr>
  <tr>
    <td>COMPLETED</td>
    <td><button>View</button></td>
  </tr>
  <tr>
    <td>Pending</td>
    <td><button>Retry</button></td>
  </tr>
</table>
Enter fullscreen mode Exit fullscreen mode

You want to select the View button that belongs to the row where the status is COMPLETED.

Using .filter({ hasText })
await expect(
        page.locator('tr')
            .filter({hasText:'COMPLETED'})
            .locator('button'))
      .toHaveText('View')
Enter fullscreen mode Exit fullscreen mode

✅ Why is this approach better?

  • It first selects all <tr>elements in the table.
  • Then, it filters the rows that contain the text COMPLETED.
  • Finally, it finds the <button> inside the filtered row
Using .locator('text=')
await expect(
         page.locator('tr')
            .locator('text=COMPLETED')
            .locator('button'))
      .toHaveText('View');
Enter fullscreen mode Exit fullscreen mode

❌ What’s the issue here?

  • .locator('text=COMPLETED') tries to find any element containing COMPLETED, even if it’s deep inside another nested element.
  • It may return unexpected results if there are multiple matching elements inside different rows.
  • The search is not restricted to the row (tr) but instead looks for any match in the selected context.

🔥 Key Takeaways

Approach Behavior Best Use Case
.filter({ hasText: 'TEXT' }) Filters elements that contain the specified text Selecting elements within a parent scope (e.g., table rows)
.locator('text=TEXT') Locates any element that exactly matches the text Quick selection when structure is simple

✅ When to Use .filter({ hasText })?

  • When dealing with structured elements (tables, lists, div containers, etc.).
  • When the text is part of a larger element (like a row containing multiple elements).
  • When you need precision and don’t want to match unintended elements.

⚠️ When .locator('text=') Can Cause Issues?

  • If the text appears multiple times on the page, you may get unexpected matches.
  • If the element you’re targeting is deeply nested, Playwright may not find it reliably.
  • It doesn’t work well when the text is inside an element with other dynamic content.

🚀 So

If you’re working with structured elements like tables or lists, prefer using .filter({ hasText }). It ensures you only interact with elements that are within the expected scope.

Use .locator('text=') carefully, as it may return unexpected elements depending on the page structure.


Follow me on Instagran and Linkedin

See more in TheCollege

Top comments (0)