Puppeteer 19.7.1 added "p" (pseudo) selectors, so text/
is deprecated in favor of ::-p-text
. For example:
const el = await page.waitForSelector("::-p-text(Button text)");
Pseudoselectors can work in conjunction with CSS selectors, like
const el = await page.$(".container button::-p-text(Button text)");
In Puppeteer >= 18.0.0, selectors have a text/
prefix:
const el = await page.waitForSelector("text/Button text");
With regards to XPath specifically:
Since OP's use case appears to be an exact match on the target string "Button text"
, <button>Button text</button>
, text()
seems like the correct method rather than the less-precise contains()
.
Although Thomas makes a good argument for contains
when there are sub-elements, avoiding false negatives, using text()
avoids a false positive when the button is, say, <button>Button text and more stuff</button>
, which seems just as likely a scenario. It's useful to have both tools on hand so you can pick the more appropriate one on a case-by-case basis.
const xp = '//*[@class="elements"]//button[text()="Button text"]';
const [el] = await page.$x(xp);
await el?.click();
Note that many other answers missed the .elements
parent class requirement.
Another XPath function is [normalize-space()="Button text"]
which "strips leading and trailing white-space from a string, replaces sequences of whitespace characters by a single space" and may be useful for certain cases.
Also, it's often handy to use waitForXPath
which waits for, then returns, the element matching the XPath or throws if it's not found within the specified timeout:
const xp = '//*[@class="elements"]//button[text()="Button text"]';
const el = await page.waitForXPath(xp);
await el.click();