Existe algum método (não encontrado na API) ou solução para clicar no elemento com texto?
Por exemplo, tenho html:
<div class="elements">
<button>Button text</button>
<a href=#>Href text</a>
<div>Div text</div>
</div>
E eu quero clicar no elemento no qual o texto está embrulhado (clique no botão dentro de .elementos), como:
Page.click('Button text', '.elements')
Respostas:
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), poistext()
retorna uma lista com dois textos (Start
eEnd
), mascontains
irá verificar apenas o primeiro//button[contains(text(), 'Middle')]
voltará há resultados comotext()
não inclui o texto de nós filhoAqui 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 detext()
em uma expressão XPath.fonte
//*[...]
lugar.Você pode usar um seletor XPath com page. $ X (expressão) :
Confira
clickByText
nesta essência um exemplo completo. Ele cuida do escape de aspas, o que é um pouco complicado com expressões XPath.fonte
//a[contains
por//*[contains
para selecionar qualquer elemento, não apenas uma
elemento anchor ( ).Você também pode usar
page.evaluate()
para clicar em elementos obtidosdocument.querySelectorAll()
que foram filtrados por conteúdo de texto:await page.evaluate(() => { [...document.querySelectorAll('.elements button')].find(element => element.textContent === 'Button text').click(); });
Como alternativa, você pode usar
page.evaluate()
para clicar em um elemento com base em seu conteúdo de texto usandodocument.evaluate()
e uma expressão XPath correspondente:await page.evaluate(() => { const xpath = '//*[@class="elements"]//button[contains(text(), "Button text")]'; const result = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null); result.iterateNext().click(); });
fonte
fez uma solução rápida para poder usar seletores css avançados como ": contém (texto)"
então, usando esta biblioteca, você pode apenas
fonte
Aqui está minha solução:
fonte
A solução é
fonte
Não há sintaxe de seletor css compatível para seletor de texto ou uma opção de combinador, minha solução para isso seria:
fonte
Há muitas respostas sugerindo,
contains
mas não vejo nenhuma motivação para essa imprecisão, dado o caso de uso de OP que, ao que tudo indica, é uma correspondência exata com uma string alvo de"Button text"
e um elemento<button>Button text</button>
.Prefiro usar o mais preciso
[text()="Button text"]
, que evita um falso positivo quando o botão é, digamos<button>Button text and more stuff</button>
:Isso antecipa o cenário oposto a essa resposta, que tenta ser o mais permissiva possível.
Muitas respostas também não atenderam ao
.elements
requisito da classe pai.fonte
Eu precisei:
await this.page.$eval(this.menuSelector, elem => elem.click());
fonte