Acesse o painel da sua conta

Não tem uma conta? Registrar

Entrar em contato

Visite também nosso site craftxp.com.br

  • img
  • img
  • img
  • img
  • img
  • img

Entre em contato

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

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 beforeEach para 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-cy sã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 com should('be.visible') ou use cy.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.

Craft XP
Craft XP