Cypress e Testes End-to-End: Automação de Testes Front-end Moderna

Por que Testes End-to-End São Essenciais?
Em aplicações web modernas, garantir que cada funcionalidade funciona corretamente do ponto de vista do usuário é um desafio que cresce com a complexidade do projeto. Testes unitários verificam peças isoladas, testes de integração validam a comunicação entre componentes, mas apenas os testes end-to-end (E2E) simulam o fluxo completo que o usuário percorre — cliques, navegações, formulários e interações com a interface real.
O Cypress emergiu como a ferramenta preferida para testes E2E por oferecer uma experiência de desenvolvimento superior: execução no navegador real, recarregamento automático, debugging com ferramentas do desenvolvedor e uma API limpa e intuitiva que torna os testes fáceis de escrever e manter.
Instalação e Primeiro Teste
A instalação do Cypress é simples e pode ser feita em projetos novos ou existentes:
# Instalação via npm
npm install cypress --save-dev
# Ou via yarn
yarn add cypress --dev
# Abrir o Cypress pela primeira vez
npx cypress open
Na primeira execução, o Cypress cria automaticamente a estrutura de pastas recomendada:
cypress/
e2e/ # Seus testes E2E
fixtures/ # Dados mockados (JSON, imagens)
support/ # Comandos customizados e configurações globais
commands.js
e2e.js
cypress.config.js # Configuração principal
Vamos criar nosso primeiro teste. Crie o arquivo cypress/e2e/login.cy.js:
describe('Página de Login', () => {
beforeEach(() => {
cy.visit('https://meuapp.com/login')
})
it('deve exibir o formulário de login', () => {
cy.get('h1').should('contain', 'Entrar')
cy.get('input[name="email"]').should('be.visible')
cy.get('input[name="senha"]').should('be.visible')
cy.get('button[type="submit"]').should('contain', 'Acessar')
})
it('deve fazer login com sucesso', () => {
cy.get('input[name="email"]').type('usuario@exemplo.com')
cy.get('input[name="senha"]').type('senha123')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
cy.contains('Bem-vindo').should('be.visible')
})
it('deve exibir erro com credenciais inválidas', () => {
cy.get('input[name="email"]').type('invalido@exemplo.com')
cy.get('input[name="senha"]').type('senha_errada')
cy.get('button[type="submit"]').click()
cy.contains('Credenciais inválidas').should('be.visible')
})
})
Seletores: A Base de Testes Confiáveis
A qualidade dos seus testes depende diretamente da qualidade dos seletores que você utiliza. Evite seletores frágeis e prefira abordagens robustas:
O Que Evitar
- Seletores CSS genéricos:
cy.get('div > button')— quebra com qualquer mudança na estrutura do DOM. - Seletores por classe dinâmica: Classes geradas por CSS-in-JS (Styled Components, Tailwind) mudam a cada build.
- Seletores por texto visível:
cy.contains('Salvar')— frágeis para localização/i18n.
A Melhor Prática: data-* Attributes
A abordagem recomendada pela própria equipe do Cypress é usar atributos data-cy nos elementos do seu HTML:
<!-- No seu componente React/Vue/Angular -->
<button data-cy="submit-login" type="submit">
Acessar
</button>
<input data-cy="input-email" name="email" type="email" />
<!-- No teste Cypress -->
cy.get('[data-cy="input-email"]').type('usuario@exemplo.com')
cy.get('[data-cy="submit-login"]').click()
Atributos data-cy são exclusivamente para testes — não afetam estilo, não mudam com refatorações e tornam os testes extremamente resilientes.
Interceptando Requisições de API
Um dos recursos mais poderosos do Cypress é a capacidade de interceptar e simular requisições de rede com cy.intercept():
describe('Listagem de Usuários', () => {
it('deve exibir a lista de usuários carregada da API', () => {
// Intercepta a requisição e fornece dados mockados
cy.intercept('GET', '/api/usuarios', {
statusCode: 200,
body: [
{ id: 1, nome: 'Ana Silva', email: 'ana@exemplo.com' },
{ id: 2, nome: 'Carlos Souza', email: 'carlos@exemplo.com' },
],
}).as('getUsuarios')
cy.visit('/usuarios')
cy.wait('@getUsuarios')
cy.get('[data-cy="usuario-item"]').should('have.length', 2)
cy.contains('Ana Silva').should('be.visible')
})
it('deve exibir mensagem de erro quando a API falha', () => {
cy.intercept('GET', '/api/usuarios', {
statusCode: 500,
body: { message: 'Erro interno do servidor' },
}).as('getUsuariosError')
cy.visit('/usuarios')
cy.wait('@getUsuariosError')
cy.contains('Erro ao carregar').should('be.visible')
})
})
Isso permite testar todos os estados da UI — loading, sucesso, erro, vazio — sem depender de um servidor real ou dados de verdade.
Comandos Customizados e Reutilização
Conforme seus testes crescem, a reutilização de código se torna essencial. O Cypress permite criar comandos customizados no arquivo cypress/support/commands.js:
// cypress/support/commands.js
Cypress.Commands.add('login', (email, senha) => {
cy.intercept('POST', '/api/auth/login', {
statusCode: 200,
body: { token: 'fake-jwt-token', usuario: { nome: 'Teste' } },
}).as('loginRequest')
cy.get('[data-cy="input-email"]').type(email || 'teste@exemplo.com')
cy.get('[data-cy="input-senha"]').type(senha || 'senha123')
cy.get('[data-cy="submit-login"]').click()
cy.wait('@loginRequest')
})
// Agora nos testes
beforeEach(() => {
cy.login('admin@exemplo.com', 'admin123')
})
it('deve acessar a página de configurações', () => {
cy.visit('/configuracoes')
cy.contains('Configurações da Conta').should('be.visible')
})
Gravando Vídeos e Screenshots
Um dos maiores benefícios do Cypress é a capacidade de gravar vídeos e tirar screenshots automaticamente durante a execução dos testes, especialmente em CI/CD. Isso transforma o debugging de falhas:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'https://meuapp.com',
video: true,
screenshotOnRunFailure: true,
trashAssetsBeforeRuns: true,
viewportWidth: 1280,
viewportHeight: 720,
defaultCommandTimeout: 10000,
},
})
Quando um teste falha no CI, você recebe automaticamente um vídeo do momento exato da falha e um screenshot — eliminando a necessidade de reproduzir bugs manualmente.
Integração com CI/CD
O Cypress se integra perfeitamente com as principais plataformas de CI/CD. Veja um exemplo com GitHub Actions:
# .github/workflows/cypress.yml
name: Testes E2E
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Instalar dependências
run: npm ci
- name: Rodar testes Cypress
uses: cypress-io/github-action@v6
with:
build: npm run build
start: npm start
wait-on: 'http://localhost:3000'
Boas Práticas Essenciais
- Teste o comportamento, não a implementação: Não verifique classes CSS, estilos ou detalhes internos do componente. Teste o que o usuário vê e faz.
- Mantenha testes independentes: Cada teste deve poder rodar sozinho, sem depender do estado deixado por testes anteriores. Use
beforeEachpara configurar o estado inicial. - Use cy.intercept para isolar o front-end: Testes E2E não precisam testar o back-end — simule as respostas da API e foque na interface.
- Prefira cy.get sobre cy.contains: Seletores por atributo
data-cysão muito mais estáveis que busca por texto visível. - Não use cy.wait com tempos fixos: Em vez de
cy.wait(3000), espere por elementos específicos comshould('be.visible')ou usecy.wait('@alias')para requisições. - Organize testes por funcionalidade: Um arquivo de teste por funcionalidade (login.cy.js, checkout.cy.js), com describe blocks aninhados para cenários específicos.
Cypress vs Alternativas
Como o Cypress se compara a outras ferramentas?
- Cypress vs Playwright: Cypress tem melhor DX (debugging, time travel, recarregamento automático). Playwright oferece suporte a mais navegadores (incluindo Safari) e melhor performance em testes paralelos. Ambos são excelentes — a escolha depende do ecossistema do seu projeto.
- Cypress vs Selenium: Selenium é mais antigo e suporta mais linguagens (Java, Python, C#), mas é significativamente mais lento e tem uma API menos intuitiva. Cypress é a escolha moderna para equipes JavaScript/TypeScript.
- Cypress vs Testing Library: Testing Library é uma biblioteca de utilitários, não um framework E2E. Na verdade, elas se complementam — você pode usar Testing Library dentro do Cypress.
Conclusão
Testes end-to-end com Cypress não são apenas uma ferramenta — são uma mudança de mentalidade no desenvolvimento web. Quando você escreve testes do ponto de vista do usuário, descobre bugs que testes unitários jamais encontrariam, documenta o comportamento esperado do sistema e ganha confiança para refatorar sem medo.
Comece pequeno: teste o fluxo crítico da sua aplicação (login, cadastro, busca, checkout). Depois expanda gradualmente. A confiança que os testes E2E trazem para as entregas vale cada minuto investido — e com Cypress, essa confiança vem com uma experiência de desenvolvimento que é um prazer usar.







