Топової відповідь на 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.