I’m trying to get the innerText of child <h4> elements for a list of elements selected by a common data-testid in Playwright:
const headers = await page.$$("data-testid=my-custom-id");
const rawData = await Promise.all(headers.map(async (header) => {
return await (await header.$('h4')).innerText;
}));
console.log(rawData);
Problem:
When I log rawData, I get [AsyncFunction: innerText] instead of the actual text.
In your code, innerText is a function, so you need to call it with ():
const headers = await page.$$("data-testid=my-custom-id");
const rawData = await Promise.all(
headers.map(async (header) => {
const h4 = await header.$("h4");
return await h4.innerText(); // <--- call it as a function
})
);
console.log(rawData);
The key difference: innerText is not a property, it’s an async method, so omitting () gives you the function itself.
Playwright’s locator API can get all inner texts in one call without mapping manually:
const rawData = await page.locator('[data-testid="my-custom-id"] h4').allInnerTexts();
console.log(rawData);
This avoids the Promise.all and map boilerplate and works efficiently even if some elements appear/disappear dynamically.
If you want to extract text via page context, you can use evaluate:
const rawData = await page.$$eval(
'[data-testid="my-custom-id"] h4',
elements => elements.map(el => el.innerText)
);
console.log(rawData);
This runs in the browser context and directly returns an array of strings, which is very fast for scraping scenarios.