Seletores
O Protocolo WebDriver fornece várias estratégias de seleção para consultar um elemento. O WebdriverIO as simplifica para manter a seleção de elementos simples. Observe que, embora o comando para consultar elementos seja chamado de $
e $$
, eles não têm nada a ver com jQuery ou o Mecanismo de Seleção Sizzle.
Embora existam tantos seletores diferentes disponíveis, apenas alguns deles fornecem uma maneira resiliente de encontrar o elemento certo. Por exemplo, dado o seguinte botão:
<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-testid="submit"
>
Submit
</button>
Nós recomendamos e não recomendamos os seguintes seletores:
Seletor | Recomendado | Notas |
---|---|---|
$('button') | 🚨 Nunca | O pior - muito genérico, sem contexto. |
$('.btn.btn-large') | 🚨 Nunca | Ruim. Acoplado ao estilo. Altamente sujeito a mudanças. |
$('#main') | ⚠️ Raramente | Melhor. Mas ainda acoplado ao estilo ou ouvintes de eventos JS. |
$(() => document.queryElement('button')) | ⚠️ Raramente | Consulta eficaz, complexa de escrever. |
$('button[name="submission"]') | ⚠️ Raramente | Acoplado ao atributo name que tem semântica HTML. |
$('button[data-testid="submit"]') | ✅ Bom | Requer atributo adicional, não conectado a a11y. |
$('aria/Submit') ou $('button=Submit') | ✅ Sempre | Melhor. Assemelha-se a como o usuário interage com a página. É recomendável usar os arquivos de tradução do seu frontend para que seus testes nunca falhem quando as traduções forem atualizadas |
Seletor de Consulta CSS
Se não for indicado de outra forma, o WebdriverIO consultará elementos usando o padrão seletor CSS, por exemplo:
loading...
Texto de Link
Para obter um elemento âncora com um texto específico nele, consulte o texto começando com um sinal de igual (=
).
Por exemplo:
loading...
Você pode consultar este elemento chamando:
loading...
Texto Parcial de Link
Para encontrar um elemento âncora cujo texto visível corresponda parcialmente ao seu valor de pesquisa,
consulte-o usando *=
na frente da string de consulta (por exemplo, *=driver
).
Você também pode consultar o elemento do exemplo acima chamando:
loading...
Nota: Você não pode misturar várias estratégias de seletor em um único seletor. Use várias consultas de elementos encadeados para atingir o mesmo objetivo, por exemplo:
const elem = await $('header h1*=Welcome') // não funciona!!!
// use em vez disso
const elem = await $('header').$('*=driver')
Elemento com determinado texto
A mesma técnica pode ser aplicada aos elementos também. Além disso, também é possível fazer uma correspondência não sensível a maiúsculas e minúsculas usando .=
ou .*=
dentro da consulta.
Por exemplo, aqui está uma consulta para um título de nível 1 com o texto "Welcome to my Page":
loading...
Você pode consultar este elemento chamando:
loading...
Ou usando consulta de texto parcial:
loading...
O mesmo funciona para nomes de id
e class
:
loading...
Você pode consultar este elemento chamando:
loading...
Nota: Você não pode misturar várias estratégias de seletor em um único seletor. Use várias consultas de elementos encadeados para atingir o mesmo objetivo, por exemplo:
const elem = await $('header h1*=Welcome') // não funciona!!!
// use em vez disso
const elem = await $('header').$('h1*=Welcome')
Nome da Tag
Para consultar um elemento com um nome de tag específico, use <tag>
ou <tag />
.
loading...
Você pode consultar este elemento chamando:
loading...
Atributo Name
Para consultar elementos com um atributo de nome específico, você pode usar um seletor CSS3 normal ou a estratégia de nome fornecida pelo JSONWireProtocol passando algo como [name="some-name"] como parâmetro de seletor:
loading...
loading...
Nota: Esta estratégia de seletor está obsoleta e só funciona em navegadores antigos que são executados pelo protocolo JSONWireProtocol ou usando Appium.
xPath
Também é possível consultar elementos via xPath específico.
Um seletor xPath tem um formato como //body/div[6]/div[1]/span[1]
.
loading...
Você pode consultar o segundo parágrafo chamando:
loading...
Você pode usar xPath para também percorrer a árvore DOM para cima e para baixo:
loading...
Seletor de Nome de Acessibilidade
Consulta elementos pelo seu nome acessível. O nome acessível é o que é anunciado por um leitor de tela quando esse elemento recebe foco. O valor do nome acessível pode ser tanto conteúdo visual quanto alternativas de texto ocultas.
Você pode ler mais sobre este seletor em nosso post de blog de lançamento
Buscar por aria-label
loading...
loading...
Buscar por aria-labelledby
loading...
loading...
Buscar por conteúdo
loading...
loading...
Buscar por título
loading...
loading...
Buscar pela propriedade alt
loading...
loading...
ARIA - Atributo de Role
Para consultar elementos com base em funções ARIA, você pode especificar diretamente a função do elemento como [role=button]
como parâmetro do seletor:
loading...
loading...
Atributo ID
A estratégia de localização "id" não é suportada no protocolo WebDriver, deve-se usar estratégias de seletor CSS ou xPath para encontrar elementos usando ID.
No entanto, alguns drivers (por exemplo, Appium You.i Engine Driver) ainda podem suportar esse seletor.
As sintaxes de seletor atualmente suportadas para ID são:
//localizador css
const button = await $('#someid')
//localizador xpath
const button = await $('//*[@id="someid"]')
//estratégia de id
// Nota: funciona apenas no Appium ou frameworks similares que suportam a estratégia de localização "ID"
const button = await $('id=resource-id/iosname')
Função JS
Você também pode usar funções JavaScript para buscar elementos usando APIs nativas da web. É claro que você só pode fazer isso dentro de um contexto web (por exemplo, browser
, ou contexto web em dispositivos móveis).
Dada a seguinte estrutura HTML:
loading...
Você pode consultar o elemento irmão de #elem
da seguinte forma:
loading...
Seletores Profundos
A partir da versão v9
do WebdriverIO, não há necessidade deste seletor especial, pois o WebdriverIO automaticamente atravessa o Shadow DOM para você. É recomendado migrar deste seletor removendo o >>>
na frente dele.
Muitas aplicações frontend dependem fortemente de elementos com shadow DOM. É tecnicamente impossível consultar elementos dentro do shadow DOM sem soluções alternativas. Os comandos shadow$
e shadow$$
eram essas soluções alternativas que tinham suas limitações. Com o seletor profundo, agora você pode consultar todos os elementos dentro de qualquer shadow DOM usando o comando de consulta comum.
Supondo que temos uma aplicação com a seguinte estrutura:
Com este seletor, você pode consultar o elemento <button />
que está aninhado dentro de outro shadow DOM, por exemplo:
loading...
Seletores Móveis
Para teste móvel híbrido, é importante que o servidor de automação esteja no contexto correto antes de executar comandos. Para automatizar gestos, o driver idealmente deve ser definido para o contexto nativo. Mas para selecionar elementos do DOM, o driver precisará ser definido para o contexto da webview da plataforma. Somente então os métodos mencionados acima podem ser usados.
Para teste móvel nativo, não há mudança entre contextos, pois você deve usar estratégias móveis e usar a tecnologia de automação de dispositivo subjacente diretamente. Isso é especialmente útil quando um teste precisa de um controle refinado sobre como encontrar elementos.
Android UiAutomator
O framework UI Automator do Android fornece várias maneiras de encontrar elementos. Você pode usar a API UI Automator, em particular a classe UiSelector para localizar elementos. No Appium, você envia o código Java, como uma string, para o servidor, que o executa no ambiente da aplicação, retornando o elemento ou elementos.
const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()
Android DataMatcher e ViewMatcher (apenas Espresso)
A estratégia DataMatcher do Android fornece uma maneira de encontrar elementos por Data Matcher
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"]
})
await menuItem.click()
E de forma similar View Matcher
const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"],
"class": "androidx.test.espresso.matcher.ViewMatchers"
})
await menuItem.click()
Android View Tag (apenas Espresso)
A estratégia de tag de visualização fornece uma maneira conveniente de encontrar elementos por sua tag.
const elem = await $('-android viewtag:tag_identifier')
await elem.click()
iOS UIAutomation
Ao automatizar uma aplicação iOS, o framework UI Automation da Apple pode ser usado para encontrar elementos.
Esta API JavaScript possui métodos para acessar a visualização e tudo nela.
const selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
const button = await $(`ios=${selector}`)
await button.click()
Você também pode usar a pesquisa de predicados dentro do UI Automation iOS no Appium para refinar ainda mais a seleção de elementos. Veja aqui para detalhes.
Strings de predicado iOS XCUITest e cadeias de classes
Com iOS 10 e superior (usando o driver XCUITest
), você pode usar strings de predicado:
const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()
const selector = '**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton'
const button = await $(`-ios class chain:${selector}`)
await button.click()
ID de Acessibilidade
A estratégia de localização accessibility id
foi projetada para ler um identificador único para um elemento da UI. Isso tem o benefício de não mudar durante a localização ou qualquer outro processo que possa alterar o texto. Além disso, pode ser uma ajuda na criação de testes multiplataforma, se elementos que são funcionalmente os mesmos tiverem o mesmo id de acessibilidade.
- Para iOS, este é o
accessibility identifier
definido pela Apple aqui. - Para Android, o
accessibility id
mapeia para acontent-description
do elemento, conforme descrito aqui.
Para ambas as plataformas, obter um elemento (ou vários elementos) pelo seu accessibility id
geralmente é o melhor método. Também é a maneira preferida em relação à estratégia name
obsoleta.
const elem = await $('~my_accessibility_identifier')
await elem.click()
Nome da Classe
A estratégia class name
é uma string
que representa um elemento de UI na visualização atual.
- Para iOS, é o nome completo de uma classe UIAutomation, e começará com
UIA-
, comoUIATextField
para um campo de texto. Uma referência completa pode ser encontrada aqui. - Para Android, é o nome totalmente qualificado de uma UI Automator class, como
android.widget.EditText
para um campo de texto. Uma referência completa pode ser encontrada aqui. - Para Youi.tv, é o nome completo de uma classe Youi.tv, e começará com
CYI-
, comoCYIPushButtonView
para um elemento de botão de pressão. Uma referência completa pode ser encontrada na página GitHub do You.i Engine Driver
// Exemplo iOS
await $('UIATextField').click()
// Exemplo Android
await $('android.widget.DatePicker').click()
// Exemplo Youi.tv
await $('CYIPushButtonView').click()
Encadear Seletores
Se você quiser ser mais específico em sua consulta, pode encadear seletores até encontrar o elemento certo. Se você chamar element
antes do seu comando atual, o WebdriverIO inicia a consulta a partir desse elemento.
Por exemplo, se você tem uma estrutura DOM como:
<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>
E você deseja adicionar o produto B ao carrinho, seria difícil fazer isso usando apenas o seletor CSS.
Com o encadeamento de seletores, é muito mais fácil. Simplesmente reduza o elemento desejado passo a passo:
await $('.row .entry:nth-child(2)').$('button*=Add').click()
Seletor de Imagem do Appium
Usando a estratégia de localização -image
, é possível enviar ao Appium um arquivo de imagem representando um elemento que você deseja acessar.
Formatos de arquivo suportados jpg,png,gif,bmp,svg
A referência completa pode ser encontrada aqui
const elem = await $('./file/path/of/image/test.jpg')
await elem.click()
Nota: A forma como o Appium trabalha com este seletor é que ele internamente fará uma (app)screenshot e usará o seletor de imagem fornecido para verificar se o elemento pode ser encontrado nessa (app)screenshot.
Esteja ciente do fato de que o Appium pode redimensionar a (app)screenshot tirada para fazê-la corresponder ao tamanho CSS da sua tela (app) (isso acontecerá em iPhones, mas também em máquinas Mac com um display Retina porque o DPR é maior que 1). Isso resultará em não encontrar uma correspondência porque o seletor de imagem fornecido pode ter sido tirado da screenshot original. Você pode corrigir isso atualizando as configurações do Servidor Appium, veja os documentos do Appium para as configurações e este comentário para uma explicação detalhada.
Seletores React
O WebdriverIO fornece uma maneira de selecionar componentes React com base no nome do componente. Para fazer isso, você tem a escolha de dois comandos: react$
e react$$
.
Esses comandos permitem que você selecione componentes do DOM Virtual do React e retorne um único Elemento WebdriverIO ou uma matriz de elementos (dependendo de qual função é usada).
Nota: Os comandos react$
e react$$
são semelhantes em funcionalidade, exceto que react$$
retornará todas as instâncias correspondentes como uma matriz de elementos WebdriverIO, e react$
retornará a primeira instância encontrada.
Exemplo básico
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<div>
MyComponent
</div>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
No código acima, há uma instância simples de MyComponent
dentro da aplicação, que o React está renderizando dentro de um elemento HTML com id="root"
.
Com o comando browser.react$
, você pode selecionar uma instância de MyComponent
:
const myCmp = await browser.react$('MyComponent')
Agora que você tem o elemento WebdriverIO armazenado na variável myCmp
, você pode executar comandos de elemento contra ele.
Filtrando componentes
A biblioteca que o WebdriverIO usa internamente permite filtrar sua seleção por props e/ou estado do componente. Para isso, você precisa passar um segundo argumento para props e/ou um terceiro argumento para estado ao comando do navegador.
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent(props) {
return (
<div>
Hello { props.name || 'World' }!
</div>
)
}
function App() {
return (
<div>
<MyComponent name="WebdriverIO" />
<MyComponent />
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#root'))
Se você quiser selecionar a instância de MyComponent
que tem uma prop name
como WebdriverIO
, pode executar o comando assim:
const myCmp = await browser.react$('MyComponent', {
props: { name: 'WebdriverIO' }
})
Se você quisesse filtrar nossa seleção por estado, o comando browser
seria algo como:
const myCmp = await browser.react$('MyComponent', {
state: { myState: 'some value' }
})
Lidando com React.Fragment
Ao usar o comando react$
para selecionar fragmentos do React, o WebdriverIO retornará o primeiro filho desse componente como o nó do componente. Se você usar react$$
, receberá uma matriz contendo todos os nós HTML dentro dos fragmentos que correspondem ao seletor.
// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
function MyComponent() {
return (
<React.Fragment>
<div>
MyComponent
</div>
<div>
MyComponent
</div>
</React.Fragment>
)
}
function App() {
return (<MyComponent />)
}
ReactDOM.render(<App />, document.querySelector('#root'))
Dado o exemplo acima, é assim que os comandos funcionariam:
await browser.react$('MyComponent') // retorna o Elemento WebdriverIO para o primeiro <div />
await browser.react$$('MyComponent') // retorna os Elementos WebdriverIO para o array [<div />, <div />]
Nota: Se você tiver várias instâncias de MyComponent
e usar react$$
para selecionar esses componentes de fragmento, você receberá uma matriz unidimensional de todos os nós. Em outras palavras, se você tiver 3 instâncias de <MyComponent />
, você receberá uma matriz com seis elementos WebdriverIO.
Estratégias de Seletores Personalizados
Se seu aplicativo requer uma maneira específica de buscar elementos, você pode definir uma estratégia de seletor personalizada que pode usar com custom$
e custom$$
. Para isso, registre sua estratégia uma vez no início do teste, por exemplo, em um hook before
:
loading...
Dado o seguinte trecho HTML:
loading...
Em seguida, use-o chamando:
loading...
Nota: isso só funciona em um ambiente web no qual o comando execute
pode ser executado.