O que é Cypress?
Cypress é uma ferramenta de testes end-to-end que roda dentro do navegador junto com a sua aplicação. Essa escolha arquitetural proporciona uma experiência de desenvolvedor excepcionalmente boa: um runner interativo onde você acompanha a execução dos comandos, a capacidade de inspecionar o DOM em cada etapa e um debugger de “viagem no tempo” que reproduz cada ação.
É uma das ferramentas de teste de navegador mais populares e é especialmente querida por ser acessível. Os comandos são enfileirados automaticamente, as assertions tentam novamente até passarem e o runner deixa claro o que aconteceu quando um teste falha.
Escrevendo um teste
Os testes do Cypress utilizam uma API de comandos encadeáveis e uma estrutura describe/it.
// cypress/e2e/todos.cy.js
describe("todos", () => {
beforeEach(() => {
cy.visit("/todos");
});
it("adds a todo", () => {
cy.get('[data-cy="new-todo"]').type("Write tests");
cy.get('[data-cy="add"]').click();
cy.get('[data-cy="todo"]').should("have.length", 1);
cy.contains("Write tests").should("be.visible");
});
});
Os comandos do Cypress são enfileirados e executados em ordem, embora retornem imediatamente. É por isso que você encadeia .then ou utiliza aliases em vez de atribuir o resultado de um comando a uma variável.
Comandos e asserções
Os comandos principais abrangem navegação, consultas e interação:
cy.visit(url)abre uma página.cy.get(selector)realiza consultas via seletor CSS.cy.contains(text)encontra um elemento pelo seu texto..type(),.click(),.select(),.check()interagem com elementos..should()realiza asserções e tentativas de repetição (retries).
// assertions.cy.js
cy.get("form").should("be.visible");
cy.get('[data-cy="count"]').should("have.text", "3");
cy.get("button").should("be.disabled");
cy.get('[data-cy="row"]').should("have.length", 5);
Como o .should() tenta novamente até passar ou atingir o tempo limite (timeout), raramente você precisará aguardar explicitamente. Esta é a mesma abordagem baseada em retries que torna os testes do Playwright resilientes, aplicada a uma API encadeada.
Stubbing de rede com cy.intercept
cy.intercept é a maneira de tornar seus testes determinísticos. Ele pode fazer o stub de respostas, espionar o tráfego real, modificar requisições e controlar o timing.
// intercept.cy.js
cy.intercept("GET", "/api/users", {
statusCode: 500,
body: { message: "Server error" },
}).as("users");
cy.visit("/users");
cy.wait("@users");
cy.contains("Something went wrong").should("be.visible");
Usar um alias com cy.wait("@users") permite que você faça asserções na requisição e aguarde a resposta sem precisar adivinhar o tempo de execução. Fazer o stub de estados de erro dessa forma é muito mais confiável do que tentar provocá-los a partir de um backend real.
Comandos personalizados e fixtures
Fluxos repetitivos devem ser movidos para um comando personalizado, o que mantém os testes legíveis.
// cypress/support/commands.js
Cypress.Commands.add("login", (email, password) => {
cy.visit("/login");
cy.get('[data-cy="email"]').type(email);
cy.get('[data-cy="password"]').type(password);
cy.get('[data-cy="submit"]').click();
});
// usage
cy.login("[email protected]", "secret");
Fixtures carregam dados estáticos de cypress/fixtures, e cy.fixture("users.json").then(...) fornece entradas previsíveis para os testes. Combinadas com cy.intercept, as fixtures são a maneira padrão de testar sem um backend ativo.
Selecionando elementos
O Cypress trabalha com seletores CSS, então a tentação de vincular os testes à estilização é real. Evite isso. Prefira, nesta ordem:
- Consultas acessíveis via
@testing-library/cypress(findByRole,findByLabelText). cy.containspara texto visível.- Um atributo
data-cydedicado quando não houver uma identidade visível para o usuário.
Um atributo data-cy é explícito e estável, portanto os testes sobrevivem a redesigns. Seletores baseados em classes não sobrevivem.
Onde o Cypress se encaixa
O Cypress é a camada de end-to-end. Mantenha a pirâmide equilibrada: testes unitários rápidos com Vitest ou Jest, testes de componentes com Testing Library e um conjunto focado de jornadas end-to-end no Cypress ou Playwright. Empurre os casos de borda (edge cases) para as camadas mais baratas e reserve o e2e para os fluxos que obrigatoriamente devem funcionar de ponta a ponta.
Melhores práticas
- Faça o stub da rede com
cy.interceptpara garantir testes determinísticos. - Use
data-cyou queries acessíveis em vez de seletores de estilo. - Mantenha os testes independentes para que possam ser executados em paralelo.
- Encapsule fluxos repetitivos em comandos customizados.
- Faça o login através de um comando customizado ou chamada de API, em vez de usar a UI todas as vezes.
- Faça asserções em resultados visíveis para o usuário, não no estado interno.
- Execute em modo headless no CI e mantenha o runner interativo para depuração local.
Erros comuns
- Aguardar com
cy.wait(milliseconds)em vez de usar um alias de rede ou uma asserção. - Acoplar seletores a classes CSS e à estrutura do HTML.
- Compartilhar estado entre testes, causando falhas dependentes da ordem de execução.
- Tentar armazenar resultados de comandos em variáveis sem usar
.thenou aliases. - Testar tudo end-to-end em vez de testar na camada correta.
- Fazer login pela UI antes de cada teste, tornando a suíte de testes mais lenta.
Próximos passos
O Cypress é uma forma amigável e poderosa de testar jornadas reais de usuários. Compare-o com o Playwright para ter uma alternativa cross-browser, e construa as camadas inferiores com Vitest e Testing Library. Em seguida, adicione um comando de login personalizado e um fluxo crítico, e expanda sua suíte de testes a partir daí.