Elevando a Qualidade: Guia Prático de Testes em Cypress para Componentes e E2E em Aplicações React
Tags: react, cypress, javascript, português
Published: 2024-01-12 01:42:20

Os testes desempenham um papel fundamental no desenvolvimento de aplicações, garantindo a estabilidade, confiabilidade e qualidade do código. Neste artigo, vamos explorar a importância dos testes de componentes e os end-to-end (E2E) usando Cypress em aplicações React.

## Um pouco sobre Cypress

O Cypress é uma poderosa ferramenta de automação de testes end-to-end (E2E) projetada para facilitar o processo de teste em aplicações web. Com um foco especial na simplicidade de uso e eficácia, o Cypress ganhou popularidade entre desenvolvedores e equipes de QA devido às suas características distintivas. Seu design intuitivo e capacidades abrangentes tornam-no uma peça fundamental no processo de garantia de qualidade para aplicações web modernas.

**Principais Características:**

1. **Integração Simples:** A instalação do Cypress é direta, e a integração com projetos existentes é fácil
2. **Testes em Tempo Real:** Ao contrário de muitas ferramentas de automação, o Cypress executa testes em tempo real enquanto interage com a aplicação, fornecendo feedback instantâneo e facilitando a depuração.
3. **Comandos Simples e Intuitivos:** A sintaxe dos comandos Cypress é clara e intuitiva. Operações comuns, como clicar em elementos, preencher formulários e verificar resultados, são expressas de maneira concisa.
4. **Execução em Navegadores Reais:** O Cypress executa testes diretamente em navegadores reais, o que significa que os desenvolvedores podem confiar na precisão dos resultados e na consistência com a experiência do usuário real.
5. **Conceito de "Subjects" e Encadeamento de Comandos (chains of commands):** O Cypress gerencia um conceito de "subject" que permite o encadeamento natural de comandos, simplificando a construção de testes complexos.
6. **Ampla Gama de Assertivas (Assertions):** A capacidade de verificar o estado do DOM e dos elementos usando assertivas robustas simplifica a validação de resultados esperados.
7. **Visual Regression Testing Integrado:** O Cypress pode integrar facilmente testes de regressão visual, comparando capturas de tela para identificar alterações visuais não intencionais.
8. **API Mocking e Testes de API:** A capacidade de simular chamadas de API e realizar testes de integração com facilidade contribui para uma cobertura de teste mais abrangente.
9. **Timeouts Configuráveis:** O Cypress gerencia timeouts automaticamente, mas oferece controle configurável para adaptar a execução dos testes conforme necessário.
10. **Comunidade Ativa e Suporte Contínuo:** O Cypress possui uma comunidade ativa, com suporte constante e atualizações frequentes, garantindo que a ferramenta permaneça relevante e eficiente.

## Definindo algumas bases

Segue aqui alguns pontos importantes para utilizar o cypress com maestria.

Esse e vários outros pontos podemos encontrar na própria documentação do cypress:

### **1. Como o Cypress consulta o DOM:**

O Cypress possui comandos específicos para interagir com elementos no DOM. Veja um exemplo de como você pode usar o comando **`cy.get`** para consultar e interagir com um elemento:

```jsx
// Consulta e interação com um botão usando seu seletor
cy.get('button').click();

// Consulta e interação com um input usando um atributo específico
cy.get('[data-cy=username-input]').type('nome de usuário');
```

### **2. Como o Cypress gerencia subjects e chains of commands:**

O Cypress mantém uma referência ao elemento alvo como um "subject". Cada comando retorna um novo "subject", permitindo a encadeamento de comandos. Veja um exemplo:

```jsx
// Cada comando retorna um novo "subject"
cy.get('ul')
  .find('li')   // O subject agora é a lista de itens dentro da ul
  .first()      // O subject agora é o primeiro item da lista
  .click();     // Clicando no primeiro item

```

### **3. Como as assertivas (assertions) funcionam:**

As assertivas no Cypress são usadas para verificar se o estado do DOM ou de outros elementos é como esperado. Exemplo:

```jsx
cy.get('.status-message').should('be.visible'); // Verifica se o elemento está visível

cy.get('input[name="username"]').should('have.value', 'nome de usuário'); // Verifica o valor do input

```

### **4. Como os timeouts são aplicados aos comandos:**

O Cypress gerencia timeouts automaticamente, mas você pode personalizá-los conforme necessário. Exemplo:

```jsx
// Configuração de um timeout específico para um comando
cy.get('elemento').click({ timeout: 10000 }); // Timeout de 10 segundos para o clique
```

Esses exemplos demonstram como os conceitos fundamentais do Cypress são aplicados no contexto de consultas ao DOM, manipulação de "subjects", execução de assertivas e controle de timeouts. O Cypress é uma ferramenta poderosa que oferece controle detalhado sobre interações com o DOM e facilita a criação de testes E2E robustos.

## Conceitos que irão parecer por aqui

### **Subjects:**

No contexto do Cypress, "subjects" referem-se aos elementos HTML ou objetos que são o foco de uma cadeia de comandos. Cada comando no Cypress gera um novo "subject", e os comandos subsequentes são executados em cima desse "subject". Isso cria uma forma natural de encadear comandos, simplificando a escrita de testes e a interação com o DOM. Por exemplo:

```jsx
cy.get('button')   // "get" retorna um novo "subject" representando o botão
  .click()        // "click" é executado no "subject" do botão
  .should('be.visible');  // "should" é executado no "subject" após o clique

```

### **Chains of Commands:**

As "chains of commands" (cadeias de comandos) referem-se à sequência de comandos encadeados que são executados em Cypress. Cada comando gera um novo "subject" que é passado para o próximo comando na cadeia. Isso cria uma forma clara e concisa de expressar interações e verificações em testes E2E. Exemplo:

```jsx
cy.get('.menu')
  .should('be.visible')
  .contains('Item de Menu')
  .click()
  .should('have.class', 'ativo');
```

### **Assertions:**

As assertivas em Cypress são usadas para verificar se o estado de um "subject" ou de um elemento DOM corresponde às expectativas definidas no teste. Elas ajudam a garantir que a aplicação está se comportando conforme o esperado. Um exemplo comum usando a assertiva **`should`**:

```jsx
cy.get('.elemento').should('be.visible');
```

Neste exemplo, a assertiva verifica se o elemento com a classe ".elemento" está visível.

### **Visual Regression Testing Integrado:**

O Visual Regression Testing é uma técnica que compara imagens ou capturas de tela da aplicação em diferentes momentos para detectar alterações visuais inesperadas. O Cypress oferece integração nativa com esse tipo de teste, permitindo comparar automaticamente capturas de tela durante a execução do teste. Isso ajuda a identificar alterações visuais que podem ocorrer inadvertidamente ao longo do desenvolvimento.

```jsx
cy.visit('/pagina');
cy.matchImageSnapshot();  // Compara a página atual com uma referência anterior
```

esse exemplo é bem simplório, veja a documentação do cypress para aprofundar no assunto. https://docs.cypress.io/guides/tooling/visual-testing

### **API Mocking:**

API Mocking refere-se à capacidade de simular chamadas de API durante os testes. Isso permite isolar o frontend do backend, garantindo que os testes se concentrem apenas no comportamento do frontend. O comando **`cy.intercept`** é comumente utilizado para definir respostas simuladas para solicitações de API. Exemplo:

```jsx
cy.intercept('GET', '/api/dados', { fixture: 'dados.json' }).as('getDados');
cy.visit('/dashboard');
cy.wait('@getDados').its('response.statusCode').should('eq', 200);
```

Neste exemplo, a chamada de API é interceptada e substituída por uma resposta simulada, garantindo que os testes não dependam da disponibilidade do backend real durante a execução.

## Testes de Componentes em React:

Os testes de componentes em React visam verificar se os componentes individuais funcionam conforme o esperado. Isso pode incluir testes de renderização, manipulação de estados, interações do usuário e muito mais. A biblioteca de testes mais comum para React é o **Jest**, frequentemente combinado com **React Testing Library** para testes centrados no usuário.

Exemplo de teste de renderização com Jest:

```jsx
import { render, screen } from '@testing-library/react';
import Component from './Component';

test('renderiza o componente corretamente', () => {
  render(<Component />);
  const elemento = screen.getByText(/texto do component/i);
  expect(elemento).toBeInTheDocument();
});

```

### Exemplo com Cypress

```jsx
import React from "react";
import ErrorMessage from "./ErrorMessage";

function ErrorMessage({ message }) {
  return <div className="error-message">{message}</div>;
}

describe("<ErrorMessage />", () => {
  it("renders", () => {
		// instancia do componente
    cy.mount(<ErrorMessage message="Mensagem de erro" />);
		// validação se a div com a class error-message contém a mensagem "Mensagem de erro"
    cy.get(".error-message").should(`have.text`, "Mensagem de erro");

		// ... Outros possíveis testes
  });
});
```

Para rodar o teste basta executar o seguinte comando:

```bash
$ yarn cypress run --component
```

ou ainda via interface

```bash
$ yarn cypress open
```

## Testes E2E com Cypress:

Os testes E2E simulam interações do usuário em uma aplicação completa. O **Cypress** é uma ferramenta poderosa para isso, permitindo simular cliques, preenchimento de formulários, navegação entre páginas e mais, enquanto monitora visualmente o comportamento da aplicação.

Exemplo de teste E2E com Cypress:

```jsx
describe('Teste E2E em React com Cypress', () => {
  it('Deve fazer login corretamente', () => {
    cy.visit('/login');
    cy.get('input[name="username"]').type('usuario');
    cy.get('input[name="password"]').type('senha');
    cy.get('button[type="submit"]').click();
    cy.url().should('include', '/dashboard');
// ...
// podemos continuar esse teste fazendo diversas outras assertations em /dashboard para garantir o o bom funionanmento do workflow
  });
});
```

## Outros exemplos de testes

Vamos explorar exemplos específicos para testes mais avançados em Cypress, abordando pontos como API Mocking, Visual Regression Testing e Testes em Diferentes Dispositivos e Resoluções.

### **Exemplo 1: API Mocking**

Suponha que você tenha um componente React que faz uma solicitação a uma API para recuperar dados. Aqui está um exemplo de como você pode usar o Cypress para simular essa chamada de API:

```jsx
// cypress/integration/apiMocking.spec.js
describe('Teste E2E com API Mocking', () => {
  it('Deve simular a resposta da API', () => {
    cy.intercept('GET', '/api/data', { fixture: 'data.json' }).as('getData');
    cy.visit('/dashboard');
    cy.wait('@getData').its('response.statusCode').should('eq', 200);
    cy.get('.data-item').should('have.length', 5);
  });
});
```

Neste exemplo, o **`cy.intercept`** é usado para interceptar a chamada de API e fornecer uma resposta simulada a partir de um arquivo de fixture.

### **Exemplo 2: Visual Regression Testing**

O Cypress suporta visual regression testing usando a biblioteca **`cypress-plugin-snapshots`**. Aqui está um exemplo básico:

```jsx
// cypress/integration/visualRegression.spec.js
describe('Teste de Regressão Visual', () => {
  it('Deve garantir a consistência visual', () => {
    cy.visit('/dashboard');
    cy.matchImageSnapshot();
  });
});
```

No exemplo acima, **`cy.matchImageSnapshot()`** tira um print da página e a compara com uma referência anterior, alertando sobre qualquer diferença visual.

### **Exemplo 3: Testes em Diferentes Dispositivos e Resoluções**

Cypress permite a simulação de diferentes dispositivos e resoluções. Veja um exemplo:

```jsx
// cypress/integration/responsiveTesting.spec.js
describe('Teste de Responsividade', () => {
  it('Deve garantir layout responsivo', () => {
    cy.viewport('iphone-6');
    cy.get('.mobile-menu').should('be.visible');

    cy.viewport('macbook-15');
    cy.get('.desktop-menu').should('be.visible');
  });
});
```

No exemplo acima, **`cy.viewport`** é usado para simular diferentes tamanhos de tela e garantir que os elementos responsivos estejam visíveis conforme o esperado.

Estes são exemplos básicos, e a complexidade pode aumentar com a necessidade do seu projeto. Lembre-se de ajustar conforme necessário para atender aos requisitos específicos da sua aplicação.

## Benefícios de Testes Abordados

Os principais benefícios dos testes incluem Garantia de Qualidade, Detecção Precoce de Problemas e Facilidade de Manutenção. A Garantia de Qualidade é assegurada através dos testes de componentes que verificam a funcionalidade individual de partes da aplicação. A Detecção Precoce de Problemas é obtida através dos testes E2E que identificam falhas em fluxos reais de usuário, permitindo a identificação e correção de problemas antes do lançamento. Por último, a Facilidade de Manutenção é conseguida por meio de testes automatizados que diminuem a necessidade de testes manuais repetitivos, permitindo uma maior precisão e eficiência.

A **Garantia de Qualidade** é um dos principais benefícios de realizar testes. Especificamente, os testes de componentes ajudam a assegurar que as partes individuais da aplicação funcionem corretamente. Isso é vital porque cada componente de uma aplicação é como um tijolo na construção de uma casa - se um tijolo é fraco ou defeituoso, pode comprometer a estrutura inteira. Portanto, garantir que cada componente funcione corretamente contribui para a construção de um produto final mais robusto e de alta qualidade, o que, por sua vez, traduz-se em uma melhor experiência para o usuário.

Outro benefício importante é a **Detecção Precoce de Problemas**. Aqui, os testes E2E desempenham um papel crucial. E2E, ou End-to-End, refere-se a testes que verificam o fluxo de uma aplicação, desde o início até o final. Estes testes identificam falhas em fluxos de usuário reais, permitindo que os desenvolvedores detectem e corrijam problemas antes do lançamento. Isso é extremamente valioso porque, sem esses testes, problemas podem passar despercebidos até o lançamento do produto, quando são mais difíceis e custosos de corrigir. A detecção precoce de problemas, portanto, evita problemas futuros e melhora a experiência do usuário.

Por último, mas não menos importante, os testes automatizados proporcionam **Facilidade de Manutenção**. Eles reduzem a necessidade de testes manuais repetitivos, o que não só economiza tempo, mas também garante uma maior precisão dos testes. Isso ocorre porque os testes manuais são propensos a erros humanos, enquanto os testes automatizados realizam as mesmas operações da mesma maneira todas as vezes. Além disso, os testes automatizados podem ser executados a qualquer momento, o que significa que os desenvolvedores podem verificar a qualidade do código constantemente, tornando a manutenção do código mais eficiente.

## Conclusão

Investir em testes de componentes e E2E para aplicações React é crucial para o sucesso do desenvolvimento. O uso de ferramentas como Jest para testes de componentes e Cypress para testes E2E pode melhorar significativamente a qualidade e confiabilidade das aplicações, proporcionando uma experiência consistente para os usuários finais.

Este artigo oferece apenas uma visão geral, mas a prática constante e a adaptação às necessidades específicas do projeto são essenciais para garantir a eficácia dos testes em sua aplicação React.

### Referências

[Visual Testing | Cypress Documentation](https://docs.cypress.io/guides/tooling/visual-testing)

[Introduction to Cypress | Cypress Documentation](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress)

[React Component Testing | Cypress Documentation](https://docs.cypress.io/guides/component-testing/react/overview)

[Repositório de pesquisa | GitHub](https://github.com/williamMDsilva/cypress-tests-e2e-component)