DEV Community

Danilo Camargo Ferreira Rocha
Danilo Camargo Ferreira Rocha

Posted on

Testes em aplicações React com VITE + VITEST

Por que testar aplicações?

Não é raro encontrar em uma equipe, ou projeto, uma certa resistência no uso de testes de software. Seja por diversos motivos, desde a ideia de que o cliente não irá ver de fato o seu resultado, prazo de entrega apertado ou falta de conhecimento do time.

Independente do motivo que você não trabalhou com testes até agora, por mais que pareça um trabalho redundante em um primeiro momento, garanto que a longo prazo evitará muitos problemas.

Com um conjunto de testes bem estipulados, a confiabilidade da equipe aumenta. Ajuda o time a não ter medo de quebrar o sistema na hora de refatorar ou criar novas features. Diminui a necessidade do QA testar manualmente alguns processos.

Os tipos de testes

Antes de iniciarmos esse projeto, é importante termos em mente quais os tipos de testes existentes:

1. Testes Estáticos: identifica erros de types e sintaxe do código, como o ESlint e o TSlint.
2. Testes Unitários: testa um pedaço do código, geralmente um componente de forma isolada.
3. Testes de Integração: testa a interação de alguns componentes para se certificar de que deveriam funcionar corretamente, como por exemplo em um formulário.
4. Testes End to End (E2E): Simula o fluxo de um usuário dentro do sistema do início ao fim, como por exemplo em um e-commerce, desde a escolha de um produto até o pedido final.

Nesse artigo iremos cobrir os testes unitários e te integração, ok?

Por que usar o VITE + VITEST?

O VITE é uma ferramenta de build rápida de compilar projetos react. Aliado ao VITEST, que contém uma estrutura de testes integradas ao VITE, diminui a complexidade de configurações.

Let's Start!

Link do projeto: https://github.com/dnokaneda/vitest-examples

Primeiro precisamos criar o nosso projeto, certo? Para isso, rode o comando:

yarn create vite
Enter fullscreen mode Exit fullscreen mode

Na sequencia, digite um nome de projeto da sua preferência (no nosso caso vitest-examples), selecione o framework react e a variante typescript.

A instalação será iniciada e uma pasta será criada com o nome do projeto. Acesse-a pelo prompt de comando e rode o comando abaixo:

yarn dev
Enter fullscreen mode Exit fullscreen mode

Em seu navegador você verá o seguinte resultado:

vite+react

Alterar o tema p/ dark

Nesse primeiro momento, vamos somente alterar o arquivo index.css para o tema dark, que deixará a tela um pouco mais agradável.

index.css

Não se preocupe na estilização agora, afinal, o objetivo aqui é realizar diversos exemplos de testes na plataforma.

Instalação de dependências

O VITEST é nativo do VITE, simplificando muito a parte de configuração. Evita que você utilize o babel ou configurações específicas ao utilizar outras libs de testes.

Vamos instalar todas as dependências que precisamos para iniciarmos os nossos testes. Segue o comando:

yarn add -D vitest @testing-library/react @testing-library/jest-dom jsdom
Enter fullscreen mode Exit fullscreen mode

Além do VITEST, utilizaremos a biblioteca do testing-libray, que contém diversas ferramentas de testes com compatibilidade para diversos frameworks, inclusive o react.

O JSDOM também será instalado justamente para fazer as vezes do browser. Os testes serão rodados via prompt de comando, portanto, o responsável por "simular" o projeto e interagir com ele será o JSDOM.

vite.config.ts

Após a instalação, vamos configurar de fato o ambiente de testes. Para isso, acesse o arquivo vite.config.ts e adicione os itens marcados na imagem abaixo:

vite.config.ts

package.json

Agora precisamos criar o comando test no arquivo package.json para rodarmos os testes de nossa aplicação.

package.json

O primeiro teste

Vamos começar com um teste simples: nos certificar que a aplicação está rodando. Para isso, criaremos um arquivo chamado App.test.tsx dentro da pasta src.

Segue o código que deveremos escrever:
App.test.tsx

Agora vamos à algumas explicações. Na linha 3 estamos importando 3 funções principais do vitest:

  • describe: é uma função que define um contexto para um grupo de testes que serão executados. Normalmente é criado um contexto para cada componente ou tela que será testado no projeto.

  • test: é a função de teste em si. Recebe um nome como parâmetro e define um conjunto de expectativas ao funcionamento do componente a ser testado.

  • expect: é a função que verifica a hipótese a ser testada do componente. Foi renderizado com sucesso? Existe um texto específico na tela?

Para executarmos nosso primeiro teste será preciso rodar o seguinte comando:

yarn test App.test.tsx
Enter fullscreen mode Exit fullscreen mode

O resultado será esse:
app.test.tsx

Afinal, o que aconteceu aqui?

Na linha 9 utilizamos o método render do testing-library, que irá "renderizar na memória" a página App, com o auxílio do JSDOM, para que testemos uma hipótese (linha 10): Existe um texto "Vite + React" no documento?

O método render possui um conjunto de funções que nos ajudarão a testar diversos aspectos do projeto, seja encontrar um texto, uma tag, uma classe css ou estilo. Veremos alguns exemplos adiante.

Componente button

Em um projeto react é comum termos diversos componentes com funções bem específicas, e é aqui que os testes unitários fazem bastante sentido. Queremos ter a certeza que cada componente está funcionando corretamente antes de subirmos para produção.

Um botão será um exemplo perfeito para esse cenário.
Segue o código de um botão básico em react:
Button.tsx

Teste unitário: componente button

Aqui iremos testar duas funções básicas do botão: renderizar na tela e disparar o evento de clique. Claro, há outras possibilidades, mas vamos começar devagar.

Um novo arquivo chamado Button.test.tsx será criado:
button.test.tsx

Entendendo o teste acima:

  • Linha 7: cria um conjunto de testes com o nome de "Button test";
  • Linha 8: função de teste de renderização do componente;
  • Linha 13: função de teste do disparo do evento de clique;
  • Linha 14: função genérica do VITEST que verificará se foi disparado ou não após o clique do botão;
  • Linha 16: getByTestId é a função que será usada para encontrar um elemento com testId específico no documento renderizado;
  • Linha 20: O método fireEvent irá disparar a função click no elemento com o textId "component-button".
  • Linha 21: O expect verificará se a função "handleClick" foi executada 1 única vez (toHaveBeenCalledTimes);

Novamente, segue o comando:

yarn test Button.test.tsx
Enter fullscreen mode Exit fullscreen mode

O resultado será esse:
button.test.tsx

Teste de Integração: App.tsx

Agora que já descobrimos que o botão está funcionando corretamente (de forma isolada, muito importante entendermos isso), nossa próxima etapa é testá-lo na página App.tsx.

Mas antes, precisaremos fazer alguns ajustes no projeto.

App.tsx

Como citado anteriormente, estamos aproveitando o código gerado pelo VITE, portanto não iremos perder tempo criando estilos próprios nesse momento. A única inclusão é na linha 44, ao adicionar uma margem à direita.

index.css

O motivo da margem? Vamos criar dois botões (linhas 24 e 24), uma para somar e outro para subtrair o valor de um contador. Eles ficarão alinhados horizontalmente na tela.

app.tsx

O código ficou assim:
app.tsx

O Problema

Existe um detalhe no código acima que queria explorar com vocês. Reparem que no arquivo App.tsx existem dois botões (linha 24 e 25). Cada um com uma função específica.

Se formos criar um teste de integração para testar a soma, por exemplo, o VITEST não conseguirá identificar o botão exato a ser usado, uma vez que ambos estarão com o mesmo data-testId.

Button.tsx

A solução é bem simples: passar o dataTestId por parâmetro para o componente (linha 8).

button.tsx

Dessa forma, caso tenhamos um valor no parâmetro dataTestId ele será utilizado, do contrário, será usado o data-testId padrão ("component-button").

App.tsx

Vamos atualizar o código do arquivo App.tsx com os ids específicos de cada botão (linhas 27 e 33). Dessa forma conseguiremos disparar um evento de clique em cada botão na hora dos testes.

Além disso, será necessário incluir um data-testid no valor do contador para monitorar se o teste foi realizado com sucesso (linha 22).

app.tsx

Testes de Integração: finalmente

Agora sim! Com todos os ajustes feitos, podemos criar o nosso teste de integração.

No arquivo App.test.tsx iremos criar dois novos testes, um para o botão soma (linha 13) e outro para a subtração (linha 20).

app.test.tsx

Entendendo o teste acima:

  • Linha 13: Renderiza a página App. Além disso, através da desestruturação da função render, obtemos o método getByTestId, que será usado para encontrar o botão específico do qual queremos testar;
  • Linha 16: Dispara o evento de clique no botão de soma. Só conseguimos identificar o botão exato, pois criamos um dataTestId próprio para cada botão na tela;
  • Linha 17: Testa a condição proposta: Ao clicar o botão de soma, espera-se que o valor vá de 0 para 1. Usando o método getByTestId("total-cliques") podemos ler o conteúdo exato do contador.;

Ao rodar o teste, temos o seguinte resultado:

yarn test App.test.tsx
Enter fullscreen mode Exit fullscreen mode

app.test.tsx

Refactore App.test.tsx

Perceba que criamos dois testes muito parecidos, um para o botão soma e outro para a subtração. Podemos uni-los em um único teste, conforme o exemplo abaixo:

app.test.tsx

Mas qual a vantagem? Bom, há um pequeno ganho no desempenho, pois a renderização da página é feita uma única vez para o testes dos botões, mas perde-se o rastreio de qual botão em si falhou, uma vez que os dois botões precisam funcionar para o teste ser bem sucedido.

Fica ao seu critério. Depende da complexidade da tela ou das funções de cada botão. Por isso é importante pensar exatamente o que cada teste vai realizar, garantindo assim a qualidade do seu código.

Testes de classes e estilos

Em projetos grandes, com uma equipe de UX/UI comprometidas a criar um design-system da aplicação, o front-end precisa garantir que os padrões visuais estipulados pelo time sejam atendidos.

index.css

Vamos criar um cenário: O botão primário e secundário possuem estilos próprios. Caso mude de programador, o teste irá garantir que o componente mantém o padrão visual do projeto. Se a cor do botão é azul, é azul! Certo?

index.css

No componente Button.tsx, vamos criar um novo parâmetro: secondary (linha 6 e 9). Em className criamos uma condição para verificar se o botão é primário (padrão) ou secundário (linha 12).

button.tsx

Vamos agora colocar o botão de subtrair como secundário.

app.tsx

Testes unitários: Estilos e Classes

Para garantir o style-guide do projeto, vamos criar os testes abaixo no arquivo Button.test.tsx:
button.test.tsx

Foram criados quatro novos testes: dois para o botão primário e dois para o secundário, sendo um deles um teste de classes e outro um teste de estilos.

Como exemplo, vamos entender o teste primário:

  • Linha 28: na função expect, utlizamos o método toHaveClass para identificar se a classe "button-primary" está sendo usada no componente. O parâmetro exact garante que a única classe a ser usada no botão é a "button-primary". Se preferir usar várias classes no componente e queira testar se a "button-primary" esteja entre elas, basta colocar o parâmetro exact como false.
  • Linha 36: O método toHaveStyle verificará se o estilo a ser testado ("backgroundColor") contém o valor correto ("#7dd3fc").

button.test.tsx

Conclusão

Nesse artigo foram demonstrados alguns testes básicos que podemos utilizar em nossos projetos de front-end. Testamos componentes e funções básicas. Aplicamos alguns conceitos de testes unitários e de integração, o que já é um grande começo. O real poder dos testes automatizados é no fluxo do sistema, simulando comportamentos do usuário e identificando possíveis erros.

Espero que esse artigo lhe incentive a iniciar o programa de testes de suas aplicações. Adoraria ler suas considerações e caso tenha alguma sugestão/melhoria, por favor, compartilhe comigo.

Grande abraço!

Top comments (0)