Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Playwright - Find multiple elements or class names

I have read a few different QAs related to this but none seem to be working.

I am trying to target an element (Angular) called mat-radio-button with a class called mat-radio-checked. And then select the inner text.

In Chrome this is easy:

https://i.sstatic.net/Ev0iQ.png

https://i.sstatic.net/lVoG3.png

To find the first element that matches in Playwright I can do something like:

      let test: any = await page.textContent(
      "mat-radio-button.mat-radio-checked"
    );

    console.log(test);

But if I try this:

      let test: any = await page.$$(
      "mat-radio-button.mat-radio-checked"
    );

    console.log(test);
    console.log(test[0]);
    console.log(test[1]);
  });

It does not return an array of elements I can select the inner text of.

I need to be able to find all elements with that class so I can use expect to ensure the returned inner text is correct, eg:

    expect(test).toBe("Australian Citizen");
like image 919
Russell Avatar asked Apr 27 '26 04:04

Russell


2 Answers

I found out the issue was due to the page generating beforehand and the elements were not available. So I added a waitForSelector:

await page.waitForSelector("mat-radio-button");

const elements = await page.$$("mat-radio-button.mat-radio-checked");
console.log(elements.length);
console.log(await elements[0].innerText());
console.log(await elements[1].innerText());
console.log(await elements[2].innerText());
like image 93
Russell Avatar answered Apr 28 '26 17:04

Russell


Approaches in existing answers are no longer considered idiomatic Playwright. The current preferred approach is to use locators, which auto-wait for the element(s) to be available. Locators usually mitigate the need for page.$ and waitForSelector, wich are legacy Puppeteer-style methods.

To extract text from a locator matching more than one element, you can use allTextContents:

const playwright = require("playwright"); // 1.30.0

let browser;
(async () => {
  browser = await playwright.chromium.launch();
  const page = await browser.newPage();
  await page.setContent(`<p>a</p><p>b</p>`);
  console.log(await page.locator("p").allTextContents()); // => [ 'a', 'b' ]
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

Now, you mention:

I need to be able to find all elements with that class so I can use expect to ensure the returned inner text is correct, eg:

expect(test).toBe("Australian Citizen");

In this case, use toHaveText, a web-first assertion:

import {expect, test} from "@playwright/test"; // ^1.30.0

test("has the right text", async ({page}) => {
  await page.setContent("<p>a</p><p>a</p>");
  await expect(page.locator("p")).toHaveText(["a", "a"]);
});

If you have a ton of elements, all with the same text, even if you're not sure how many are there in advance:

test("has the right text", async ({page}) => {
  await page.setContent("<p>a</p>".repeat(30));
  const loc = page.locator("p");
  const quantity = await loc.count();
  await expect(loc).toHaveText(Array(quantity).fill("a"));
});
like image 20
ggorlen Avatar answered Apr 28 '26 17:04

ggorlen