Is there any method (didn't find in API) or solution to click on element with text?
For example I have html:
<div class="elements">
    <button>Button text</button>
    <a href=#>Href text</a>
    <div>Div text</div>
</div>
And I want to click on element in which text is wrapped (click on button inside .elements), like:
Page.click('Button text', '.elements')
                We can get element text in Puppeteer. This is done with the help of the textContent property. This property of the element is passed as a parameter to the getProperty method.
page. $eval() function is used to get the value for an element in puppeteer. $eval will stage two-parameter as an argument first parameter will be the selector and the second parameter will be element= element.
This XPath expression will query a button which contains the text "Button text":
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
    await button.click();
}
To also respect the <div class="elements"> surrounding the buttons, use the following code:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
To explain why using the text node (text()) is wrong in some cases, let's look at an example:
<div>
    <button>Start End</button>
    <button>Start <em>Middle</em> End</button>
</div>
First, let's check the results when using contains(text(), 'Text'):
//button[contains(text(), 'Start')] will return both two nodes (as expected)//button[contains(text(), 'End')] will only return one nodes (the first) as text() returns a list with two texts (Start  and  End), but contains will only check the first one//button[contains(text(), 'Middle')]  will return no results as text() does not include the text of child nodesHere are the XPath expressions for contains(., 'Text'), which works on the element itself including its child nodes:
//button[contains(., 'Start')] will return both two buttons//button[contains(., 'End')] will again return both two buttons//button[contains(., 'Middle')]  will return one (the last button)So in most cases, it makes more sense to use the . instead of text() in an XPath expression.
You may use a XPath selector with page.$x(expression):
const linkHandlers = await page.$x("//a[contains(text(), 'Some text')]");
if (linkHandlers.length > 0) {
  await linkHandlers[0].click();
} else {
  throw new Error("Link not found");
}
Check out clickByText in this gist for a complete example. It takes care of escaping quotes, which is a bit tricky with XPath expressions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With