Se você trabalha com automação de testes web, já deve ter se deparado com XPath — no Selenium, no Playwright ou até no Cypress. Muita gente usa XPath copiado do DevTools ou de uma extensão, sem entender o que está por trás daquela string gigante. O resultado? Testes frágeis que quebram a cada mudança de layout, seletores ilegíveis e horas perdidas debugando algo que ninguém sabe explicar.
Neste guia, vou ensinar XPath do zero — da anatomia da expressão até eixos, predicados e funções — para você parar de decorar e começar a entender de verdade. E, no final, um gancho que vai acelerar seu dia a dia: nossa extensão para Chrome, o QA Overflow Picker.
O que é XPath
XPath (XML Path Language) é uma linguagem de consulta criada para navegar em documentos XML. Como o HTML é interpretado pelos navegadores como uma árvore de nós (o DOM), o XPath funciona perfeitamente para localizar qualquer elemento de uma página web.
Em vez de pensar em "elementos", o XPath enxerga a página como uma árvore de nós: elementos HTML (como <button>, <input>), atributos (como id, class, name) e textos. Você navega por essa árvore indicando um caminho, uma direção e uma condição.
Anatomia de uma Expressão XPath
Uma expressão XPath é composta por quatro blocos básicos:
- Nós: os elementos, atributos e textos da árvore DOM.
- Eixos (axes): a direção da navegação a partir do nó atual.
- Predicados: condições entre colchetes que filtram os nós.
- Funções: utilitários como
text(),contains()enormalize-space().
Sintaxe Básica: /, //, ., .. e @
Antes dos eixos avançados, domine os cinco símbolos que você vai usar 90% do tempo:
/— desce um nível na árvore (eixochild):/html/body/div.//— busca em qualquer profundidade (eixodescendant)://button..— o nó atual:./input...— o nó pai (parent)://input/...@— um atributo://input[@type='email'].
Exemplos práticos:
//button // todos os botões da página
//input[@type='email'] // input com atributo type = email
//div[@id='form-login'] // div com id form-login
//a[@class='btn btn-primary'] // link com essas classes exatas
Eixos (Axes): Navegando para Cima, para Baixo e para os Lados
O grande diferencial do XPath frente aos seletores CSS é a capacidade de navegar em todas as direções — para cima (pai e ancestrais), para baixo (filhos e descendentes) e para os lados (irmãos).
child::— filhos diretos (é o padrão)://div/child::input.descendant::— todos os descendentes (equivalente a//)://form/descendant::button.parent::— o nó pai (equivalente a..)://input/parent::div.ancestor::— todos os ancestrais, do pai até a raiz.following-sibling::— irmãos seguintes.preceding-sibling::— irmãos anteriores.attribute::— atributos (equivalente a@).self::— o próprio nó.
Exemplos reais de uso:
//label[text()='Email']/following-sibling::input
//span[@class='error']/ancestor::div[contains(@class, 'form-group')]
//input[@name='senha']/preceding-sibling::label
Predicados e Índices
Predicados (os colchetes) filtram a lista de nós retornada pelo caminho. São a "condição" da nossa expressão:
//ul/li[2] // segundo li de cada ul
//ul/li[last()] // último li de cada ul
//ul/li[position() > 1] // do segundo em diante
(//input[@type='text'])[2] // segundo input text de toda a página
Cuidado com um detalhe clássico: //div[2]/input é diferente de (//div/input)[2]. No primeiro, você pega a segunda div e, dentro dela, os inputs. No segundo, pega todos os inputs de todas as divs e seleciona o segundo da lista. Parênteses mudam tudo.
Funções Essenciais
text() e normalize-space()
text() retorna o texto direto do nó. O problema é que textos costumam ter espaços e quebras de linha — por isso normalize-space() é seu melhor amigo:
//button[text()='Enviar'] // frágil se houver espaços
//button[normalize-space()='Enviar'] // robusto contra espaços e quebras
contains() e starts-with()
Para buscas parciais, em atributos ou textos:
//button[contains(@class, 'btn-primary')]
//button[contains(@class, 'btn') and contains(@class, 'primary')]
//input[starts-with(@id, 'user_')]
//a[contains(text(), 'Esqueci minha senha')]
not()
Para negar uma condição — útil quando você quer evitar um nó específico:
//input[@type='text'][not(@disabled)]
//button[not(contains(@class, 'disabled'))]
XPath Absoluto vs Relativo
Esta é a diferença que separa testes que duram anos de testes que quebram na primeira mudança de layout:
- Absoluto: começa com
/(da raiz) e depende de toda a estrutura. Exemplo:/html/body/div[1]/div[3]/form/div[2]/input[1]. - Relativo: começa com
//e busca a partir de qualquer ponto da árvore. Exemplo://input[@name='email'].
Um XPath absoluto quebra se alguém inserir uma única div no layout. O relativo, ancorado em atributos estáveis, continua funcionando. Regra de ouro: se o XPath começa com /html, reescreva-o agora.
Melhores Práticas e Anti-Padrões
Teste sempre no DevTools
O console do Chrome aceita XPath direto com a função $x():
$x('//button[normalize-space()="Enviar"]')
O que fazer
- Prefira atributos estáveis:
id,name,data-testid. - Use
contains(@class, ...)para classes múltiplas — a ordem dos valores não é garantida. - Ancore em texto visível ao usuário com
normalize-space(). - Use eixos de vizinhança (siblings) para localizar campos associados a labels.
- Mantenha as expressões curtas e legíveis.
O que evitar
- XPath absoluto (
/html/body/...). - Índices de posição como seletor principal — uma nova seção na página quebra tudo.
- Classes de estilo (
btn-primary,mt-3) que o designer pode mudar a qualquer momento. - IDs gerados dinamicamente (
user_abc123) que mudam a cada reload.
Gancho: QA Overflow Picker
Criar XPath no DevTools é trabalhoso: você inspeciona, clica com o botão direito, copia e ainda precisa validar se o seletor é bom. Foi para resolver isso que desenvolvemos o QA Overflow Picker, a extensão para Chrome do QA Overflow.
Com um clique em qualquer elemento da página, ela gera na hora o XPath absoluto e o XPath relativo otimizado — além de CSS Selector, ID, Name, Class e todos os atributos — prontos para usar no Selenium, Playwright, Cypress, Puppeteer e Robot Framework.
Instale grátis na Chrome Web Store e leia o guia completo do QA Overflow Picker para entender a estratégia de escolha de seletores.
Mas atenção: a extensão gera, você decide. Agora que você entende XPath de verdade, vai saber exatamente quando o XPath relativo gerado é a melhor escolha — e quando um data-testid seria mais robusto.
Conclusão
XPath não é bicho de sete cabeças: é um caminho, uma direção e uma condição. Dominar a sintaxe básica, os eixos, os predicados e as funções essenciais vai destravar seletores robustos e tirar horas do seu dia de debug.
Pratique no DevTools com $x(), experimente o QA Overflow Picker e desenvolva sua intuição para saber quando cada tipo de seletor é a melhor aposta. Bons testes!