Search code examples
css-selectorsplaywright

Playwright selector for combining predicates


I need to find the button within the li that contains in its children both the text 6:00pm and the text Alpha.

<li>
  <div>6:00pm</div>
  <div>Alpha</div>
  <button>Do it!</button>
</li>
<li>
  <div>6:00pm</div>
  <div>Beta</div>
  <button>Do it!</button>
</li>
...

I have

li:has(div:text("6:00pm")) button

which gives me both buttons for "6:00pm", but how to limit the selector to also match Alpha so I only get one button?

I basically need to add a conjunction to the predicate.


Solution

  • You can combine filter calls to create a logical "and" of your conditions:

    const playwright = require("playwright"); // ^1.30.0
    
    const html = `<!DOCTYPE html>
    <li>
      <div>6:00pm</div>
      <div>Alpha</div>
      <button>Do it!</button>
    </li>
    <li>
      <div>6:00pm</div>
      <div>Beta</div>
      <button>Do it!</button>
    </li>`;
    
    let browser;
    (async () => {
      browser = await playwright.chromium.launch();
      const page = await browser.newPage();
      await page.setContent(html);
      const btn = page
        .getByRole("listitem")
        .filter({hasText: "Alpha"})
        .filter({hasText: "6:00pm"})
        .getByRole("button");
      console.log(await btn.textContent()); // => Do it!
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    Although this doesn't use the preferred role locator and presupposes a text ordering, the following is also possible:

    page.locator("li:text('6:00pm Alpha') button");