Топовой ответ на 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.