Топовой ответ на tokland работает только на текстовых узлах , а не на узлах с другими элементами внутри.
Короткий ответ
Это выражение XPath будет запрашивать кнопку, содержащую текст «Текст кнопки»:
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
await button.click();
}
Чтобы также уважать <div class="elements">
окружение кнопок, используйте следующий код:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
Объяснение
Чтобы объяснить, почему использование текстового узла ( text()
) в некоторых случаях неправильно, давайте рассмотрим пример:
<div>
<button>Start End</button>
<button>Start <em>Middle</em> End</button>
</div>
Для начала проверим результаты при использовании contains(text(), 'Text')
:
//button[contains(text(), 'Start')]
вернет оба двух узла (как и ожидалось)
//button[contains(text(), 'End')]
вернет только один узел (первый), так как text()
возвращает список с двумя текстами ( Start
и End
), но contains
проверит только первый
//button[contains(text(), 'Middle')]
не будет возвращать не результаты, text()
не включает в себя текст дочерних узлов
Вот выражения XPath для contains(., 'Text')
, которые работают с самим элементом, включая его дочерние узлы:
//button[contains(., 'Start')]
вернет обе две кнопки
//button[contains(., 'End')]
снова вернет обе две кнопки
//button[contains(., 'Middle')]
вернет один (последняя кнопка)
Поэтому в большинстве случаев имеет смысл использовать .
вместо text()
выражения XPath.