La respuesta principal actual de tokland solo funciona en nodos de texto y no en nodos con otros elementos en su interior.
Respuesta corta
Esta expresión XPath consultará un botón que contiene el texto "Texto del botón":
const [button] = await page.$x("//button[contains(., 'Button text')]");
if (button) {
await button.click();
}
Para respetar también el <div class="elements">entorno de los botones, utilice el siguiente código:
const [button] = await page.$x("//div[@class='elements']/button[contains(., 'Button text')]");
Explicación
Para explicar por qué el uso del nodo de texto ( text()) es incorrecto en algunos casos, veamos un ejemplo:
<div>
<button>Start End</button>
<button>Start <em>Middle</em> End</button>
</div>
Primero, verifiquemos los resultados al usar contains(text(), 'Text'):
//button[contains(text(), 'Start')]devolverá ambos dos nodos (como se esperaba)
//button[contains(text(), 'End')]solo devolverá un nodo (el primero) como text()devuelve una lista con dos textos ( Starty End), pero containssolo comprobará el primero
//button[contains(text(), 'Middle')] volverá no hay resultados que text()no incluye el texto de los nodos secundarios
Aquí están las expresiones XPath para contains(., 'Text'), que funcionan en el propio elemento, incluidos sus nodos secundarios:
//button[contains(., 'Start')]devolverá los dos botones
//button[contains(., 'End')]volverá a devolver ambos dos botones
//button[contains(., 'Middle')] devolverá uno (el último botón)
Entonces, en la mayoría de los casos, tiene más sentido usar el en .lugar de text()en una expresión XPath.