What you seem to be asking for is possible:
public getNestedElementByTestIds(testIds: Array<string>) {
if (testIds.length === 0) {
throw Error("testIds must contain at least one element");
}
let locator = this.page.getByTestId(testIds[0]);
for (const testId of testIds.slice(1)) {
locator = locator.getByTestId(testId);
}
return locator;
}
Runnable example:
const playwright = require("playwright"); // ^1.30.1
const html = `
<div data-testid="foo">
ignore this
<div data-testid="bar">
ignore this
<div data-testid="baz">
ignore this
<div data-testid="quux">
PRINT ME
</div>
</div>
</div>
</div>`;
const getNestedElementByTestIds = (page, testIds) => {
if (testIds.length === 0) {
throw Error("testIds must contain at least one element");
}
let locator = page.getByTestId(testIds[0]);
for (const testId of testIds.slice(1)) {
locator = locator.getByTestId(testId);
}
return locator;
}
let browser;
(async () => {
browser = await playwright.chromium.launch();
const page = await browser.newPage();
await page.setContent(html);
console.log((await getNestedElementByTestIds(page, [
"foo", "bar", "baz", "quux"
]).textContent()).trim()); // => PRINT ME
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
Caveat emptor: This may be too clever. I would rather chain 2-3 getByTestIds in the caller, or use a more robust selection mechanism than test ids and rely on direct, user visible properties.
In general, I'm not eager to abstract Playwright calls into helpers if it's avoidable, even at the cost of some duplication across tests. They're already quite high-level. Anything more than a simple POM may become challenging to maintain for anyone but the author.
locatorintestIds. But that also makes no sense because you can't usefor .. ofover a string in the first place. Can you clarify the fundamental goal, requirements and code? Thanks.