Search code examples
javascriptplaywright

Locate element with specific number of child elements


Let's say I have two lists on the page, one with a single item and one with two:

<ul>
  <li>One</li>
</ul>

<ul>
  <li>One</li>
  <li>Two</li>
</ul>

I know I can find the ul that has the "Two" li, like so:

 page.locator('ul', {has: page.locator('li:text("Two")')});

But is there any way to find the ul that has two lis? Something like:

 page.locator('ul', {hasCount: [page.locator('li'),2]});

Solution

  • XPath is discouraged in Playwright, but the following locator seems to meet your needs:

    await page.locator("xpath=//ul[count(li)=2]")
    

    Variants like "//ul[count(li) >= 2]" and "//ul[count(li)=2][2]" are possible.

    This can be done without XPath, but it pretty much amounts to the same thing (selecting using a count), so I don't think this makes the locator better practice. Here's a complete example:

    const playwright = require("playwright"); // ^1.39.0
    
    const html = `
    <ul>
      <li>One</li>
    </ul>
    <ul>
      <li>One</li>
      <li>Two</li>
    </ul>
    <ul>
      <li>One</li>
      <li>Two</li>
      <li>Three</li>
    </ul>`;
    
    let browser;
    (async () => {
      browser = await playwright.firefox.launch();
      const page = await browser.newPage();
      await page.setContent(html);
      const ul = page.locator("ul", {
        has: page.locator("li:nth-child(2)"),
        hasNot: page.locator("li:nth-child(3)"),
      });
      console.log(await ul.textContent()); // => One Two
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close());
    

    See also Can CSS detect the number of children an element has?