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:
.png
.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");
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");
Share
Improve this question
edited Mar 19, 2021 at 11:48
hardkoded
21.6k3 gold badges60 silver badges74 bronze badges
asked Mar 19, 2021 at 4:32
RussellRussell
1611 gold badge1 silver badge7 bronze badges
2
- 1 This code worked for me gist.github.com/kblok/19b60e76197c4d8aebaba650b2b1af93 what's different there? – hardkoded Commented Mar 19, 2021 at 11:53
- Hi @hardkoded - you're response helped me. But see my answer to what the main issue was. – Russell Commented Mar 20, 2021 at 7:14
3 Answers
Reset to default 6I 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());
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"));
});
public async validListOfItems(name) {
await this.page.waitForSelector(name, {timeout: 5000});
const itemlists = await this.page.$$(name);
let allitems: string[]=new Array();
for await (const itemlist of itemlists) {
allitems.push(await itemlist.innerText());
}
return allitems;
}
Make a common method and call by sending parameters.