Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppeteer: search for inner text case insensitive

I'm trying to search inner text case insensitive using puppeteer.

I've read this: case insensitive xpath contains() possible?

For example I have this elements:

<div>
 <span>Test One</span>
 <span>Test Two</span>
 <span>Test Three</span>
</div>

I've tried this unsuccessfully:

const element = await page.$x("//span//text()[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')]");
like image 566
kurtko Avatar asked Jan 26 '23 13:01

kurtko


2 Answers

Your XPath expression is valid, but you are returning text() instead of the node itself. page.$x expects the XPath to return an element, therefore your code does not work. To return the node you need to query for the span element.

const element = await page.$x("//span[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')]");

Please note, that text() only works for text-only nodes. If you have mixed content (containing elements and text), you should use the string value (. instead of text()):

const element = await page.$x("//span[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')]");

To compare the expressions I put them below each other:

//span//text()[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')]
//span[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')
//span[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'two')]

The first one is the expression (given by you) for the text of the span node. The second one queries the node itself by using text(). The last one uses the string value to query the node.

like image 190
Thomas Dondorf Avatar answered Feb 12 '23 09:02

Thomas Dondorf


Not as pretty, but you can use page.evaluateHandle along with a regex to find the element:

const element = await page.evaluateHandle(() =>
    Array.from(document.querySelectorAll("div > span")).find(a => /test two/i.test(a.innerText))
);
like image 32
spb Avatar answered Feb 12 '23 09:02

spb