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