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() e normalize-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 (eixo child): /html/body/div.
  • // — busca em qualquer profundidade (eixo descendant): //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!