A principal resposta atual de tokland funciona apenas em nós de texto e não em nós com outros elementos dentro.
Resposta curta
Esta expressão XPath consultará um botão que contém o texto "Texto do botão":
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
await button.click();
}
Para respeitar também o <div class="elements">
entorno dos botões, use o seguinte código:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
Explicação
Para explicar por que usar o nó de texto ( text()
) é errado em alguns casos, vejamos um exemplo:
<div>
<button>Start End</button>
<button>Start <em>Middle</em> End</button>
</div>
Primeiro, vamos verificar os resultados ao usar contains(text(), 'Text')
:
//button[contains(text(), 'Start')]
retornará os dois nós (como esperado)
//button[contains(text(), 'End')]
irá retornar apenas um nó (o primeiro), pois text()
retorna uma lista com dois textos ( Start
e End
), mas contains
irá verificar apenas o primeiro
//button[contains(text(), 'Middle')]
voltará há resultados como text()
não inclui o texto de nós filho
Aqui estão as expressões XPath para contains(., 'Text')
, que funcionam no próprio elemento, incluindo seus nós filhos:
//button[contains(., 'Start')]
retornará os dois botões
//button[contains(., 'End')]
retornará novamente os dois botões
//button[contains(., 'Middle')]
retornará um (o último botão)
Portanto, na maioria dos casos, faz mais sentido usar o em .
vez de text()
em uma expressão XPath.