playwright find child element(s) within locator
Asked Answered
M

6

13

I'm trying to write a function to find child(ren) element(s) within a locator something like:

async findElements(locator: Locator){
  return locator.querySelector(some/xpath/or/css);
}

However, I'm seeing the querySelector is not available in Locator. What is the equivalent of querySelector?

Magnesite answered 14/10, 2022 at 21:48 Comment(2)
This question would benefit from a minimal reproducible example with sample HTML so the context is clear.Flemming
See this- stackoverflow.com/a/78085021Anthracene
M
8

I figured it out,

locator.locator(some/xpath/)

or

locator.locator(some_locator)

Or, if you don't already have a variable called "locator"

page.locator(parent_selector).locator(child_selector)

where parent_selector and child_selector are strings that contain selectors

https://playwright.dev/docs/api/class-locator#locator-locator

Magnesite answered 14/10, 2022 at 22:1 Comment(2)
Here's mine: const review = await element.locator.locator(xpathReviews).innerText(); Result: TypeError: element.locator.locator is not a functionRecoil
the first "locator" is a locator object so you would not actually type locator.locator unless you defined a variable called locator as the OP has done. @Recoil it would be something like page.locator(some_selector).locator(some_other_selector)Pomerleau
S
0

I have just started working with playwright. So this may not be the exact answer that are looking for.

I am studying playwright with an existing repository.

[https://github.com/twerske/ng-tube/blob/main/src/app/video-grid/video-grid.component.html]

In this scenario I just want to know that I am getting a list of cards back.

<div class="videos-grid">
  <mat-card *ngFor="let video of videos" class="video-card">

I don't need a reference to a parent for this situation. I am able to simply reference the child by class videos-grid. This all exists inside of a angular's For loop. I know Svelte and other frameworks iterate through lists in different ways.

test.only('ngTube has header and cardList', async ({browser}) => {
    const page = await browser.newPage();
    const context = await browser.newContext();
    await page.goto("http://localhost:4200/")
    const title = await page.locator('.header-title').textContent();
    const videoList = (await page.locator('.video-card').allTextContents()).length;
    // await page.pause();
    expect(title).toStrictEqual('ngTube');
    expect(videoList).toBeGreaterThan(0)
})

Because I want all text contents I can get everything with the classname '.video-card'.

I guess what I am getting at is as long as you can access an identifier you should be able to directly access it. As I run through the documentation more and scenarios I will update/add to this answer.

Selfrestraint answered 3/1, 2023 at 0:2 Comment(0)
A
0

You may use Filter by child/descendant:

Simple Example: enter image description here

await page
    .getByRole('listitem')
    .filter({ has: page.getByRole('heading', { name: 'Product 2' }) })
    .getByRole('button', { name: 'Add to cart' })
    .click();
Anthracene answered 1/3, 2024 at 0:39 Comment(0)
B
0

I check if child div (or whatever) exists with count() function:

if el.locator('div').count():
    pass
Benefield answered 17/5, 2024 at 9:54 Comment(0)
T
0

I find it so weird that this was not the way to narrow down the search

this.page
      .getByTestId('some-wrapper-over-input')
      // this finds any text box on the page, NOT withing the found wrapper
      .getByRole('textbox') 
      .fill('blah');

So I had to replace it with

    await this.page
      .locator('[data-testid="some-wrapper-over-input"] input')
      .fill('blah');
Tomlinson answered 9/7, 2024 at 16:29 Comment(0)
R
-1

The best way I found to do this is to add a second testId in the nested elements then

parentLocator.getByTestId('nested-test-id')
Remember answered 28/2, 2024 at 5:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.