Home > Enterprise >  Question about Puppeteer xpath element evaluation
Question about Puppeteer xpath element evaluation

Time:03-19

I am working on some puppeteer code and ran into an issue that I'm looking to better understand.

When working with XPaths I'm having trouble wrapping my head around why this code works:

   await page.goto(url)
   //identify element with absolute xpath then click
   const b = (await page.$x("<absolute XPath>"))[0]
   //Works!
   b.click()

   //But this won't work
   const b = (await page.$x("<absolute XPath>"))
   b.click()

   //And this won't work
   b.click()
   const b = await page.$x("<absolute XPath>")

Why does encasing the await page.$x statement in parenthesis work? What's happening there?

When I remove the parenthesis, remove the array index, any changes... etc... I then get the standard errors like "click is not a function of b" for example. I was under the impression that I'm evaluating an absolute XPath... a single element. Where does the Array come from? And what is happening when wrapping the entire thing in parenthesis, and specifying the array element, that evaluates this out perfectly and straight to the element I want with no issues?

Would appreciate any insight or links to the right information. I hope it's not something I missed in the docs

CodePudding user response:

It is not parenthesis but [0] changes everything.

xpath can find many elements so it always returns list/array - even if it finds only one element or nothing - and you have to use [0] to get first element from list. Or you can use other index to get other element from list (if list is longer). (Of course list can be also empty and [0] may raise error)

You can't do list.click(). You have to do first = list[0] and later first.click(). Or you may use forEach to execute click on all elements on list.

It needs parenthesis only to execute commands in correct order - first await, later [0].

If you don't use parenthesis then it will try first execute [0] and later await.

So you could rewrite it on more lines

const all_results = await page.$x("<XPath>")

const first = all_results[0]

first.click()

or write shorter

const all_results = await page.$x("<XPath>")

all_results[0].click()

or

const first = (await page.$x("<XPath>"))[0]

first.click()

If you would use console.log(b) then you should see what you really have in this variable in different versions.


BTW:

The same can be with CSS selector - page.$("<css selection>") - it also returns list/array.


EDIT:

As @ggorlen he mentioned in a comment you can assign first element using array on left size

[first] = await page.$x("<XPath>")

first.click()
  • Related