Um guia prático para testar aplicativos React com Jest
Publicados: 2022-03-10Neste artigo, apresentarei uma ferramenta de teste do React chamada Jest, juntamente com a popular biblioteca Enzyme, projetada para testar componentes do React. Vou apresentar a você as técnicas de teste do Jest, incluindo: execução de testes, teste de componentes React, teste de snapshot e simulação. Se você é novo em testes e quer saber como começar, você achará este tutorial útil porque começaremos com uma introdução aos testes. No final, você estará funcionando, testando aplicativos React usando Jest e Enzyme. Você deve estar familiarizado com o React para seguir este tutorial.
Uma breve introdução ao teste
O teste é uma revisão linha por linha de como seu código será executado. Um conjunto de testes para um aplicativo compreende vários bits de código para verificar se um aplicativo está sendo executado com êxito e sem erros. O teste também é útil quando são feitas atualizações no código. Depois de atualizar um trecho de código, você pode executar um teste para garantir que a atualização não interrompa a funcionalidade já existente no aplicativo.
Por que testar?
É bom entender por que estamos fazendo algo antes de fazê-lo. Então, por que testar e qual é o seu propósito?
- O primeiro objetivo do teste é evitar a regressão. A regressão é o reaparecimento de um bug que havia sido corrigido anteriormente. Faz com que um recurso pare de funcionar como pretendido após a ocorrência de um determinado evento.
- O teste garante a funcionalidade de componentes complexos e aplicativos modulares.
- O teste é necessário para o desempenho eficaz de um aplicativo ou produto de software.
O teste torna um aplicativo mais robusto e menos propenso a erros. É uma maneira de verificar se seu código faz o que você deseja e se seu aplicativo funciona conforme o esperado para seus usuários.
Vamos examinar os tipos de testes e o que eles fazem.
Teste de unidade
Nesse tipo de teste, unidades ou componentes individuais do software são testados. Uma unidade pode ser uma função, método, procedimento, módulo ou objeto individual. Um teste de unidade isola uma seção de código e verifica sua correção, a fim de validar que cada unidade do código do software funciona conforme o esperado.
No teste de unidade, procedimentos ou funções individuais são testados para garantir que estejam funcionando corretamente e todos os componentes são testados individualmente. Por exemplo, testar uma função ou se uma instrução ou loop em um programa está funcionando corretamente cairia no escopo do teste de unidade.
Teste de Componente
O teste de componentes verifica a funcionalidade de uma parte individual de um aplicativo. Os testes são realizados em cada componente isoladamente de outros componentes. Geralmente, os aplicativos React são compostos de vários componentes, portanto, o teste de componentes lida com o teste desses componentes individualmente.
Por exemplo, considere um site que possui diferentes páginas da Web com muitos componentes. Cada componente terá seus próprios subcomponentes. Testar cada módulo sem considerar a integração com outros componentes é chamado de teste de componentes.
Testes como esse no React requerem ferramentas mais sofisticadas. Então, precisaríamos do Jest e, às vezes, de ferramentas mais sofisticadas, como o Enzyme, que discutiremos brevemente mais adiante.
Teste de instantâneo
Um teste de instantâneo garante que a interface do usuário (UI) de um aplicativo da Web não seja alterada inesperadamente. Ele captura o código de um componente em um momento no tempo, para que possamos comparar o componente em um estado com qualquer outro estado possível.
Aprenderemos sobre o teste de instantâneos em uma seção posterior.
Vantagens e desvantagens do teste
O teste é ótimo e deve ser feito, mas tem vantagens e desvantagens.
Vantagens
- Impede a regressão inesperada.
- Ele permite que o desenvolvedor se concentre na tarefa atual, em vez de se preocupar com o passado.
- Ele permite a construção modular de um aplicativo que, de outra forma, seria muito complexo para construir.
- Reduz a necessidade de verificação manual.
Desvantagens
- Você precisa escrever mais código, bem como depurar e manter.
- Falhas de teste não críticas podem fazer com que o aplicativo seja rejeitado em termos de integração contínua.
Introdução ao Jess
Jest é uma estrutura de teste JavaScript deliciosa com foco na simplicidade. Pode ser instalado com npm ou Yarn. Jest se encaixa em uma categoria mais ampla de utilitários conhecidos como executores de teste. Funciona muito bem para aplicativos React, mas também funciona muito bem fora dos aplicativos React.
Enzyme é uma biblioteca usada para testar aplicativos React. Ele foi projetado para testar componentes e possibilita escrever asserções que simulam ações que confirmam se a interface do usuário está funcionando corretamente.
Jest e Enzyme se complementam tão bem, então neste artigo usaremos ambos.
Processo de execução de um teste com Jest
Nesta seção, estaremos instalando o Jest e escrevendo testes. Se você é novo no React, recomendo usar o Create React App, porque ele está pronto para uso e vem com o Jest.
npm init react-app my-app
Precisamos instalar o Enzyme **** e enzyme-adapter-react-16
com react-test-renderer
(o número deve ser baseado na versão do React que você está usando).
npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer
Agora que criamos nosso projeto com Jest e Enzyme, precisamos criar um arquivo setupTest.js
na pasta src
do projeto. O arquivo deve ficar assim:
import { configure } from "enzyme"; import Adapter from "enzyme-adapter-react-16"; configure({ adapter: new Adapter() });
Isso importa o Enzyme e configura o adaptador para executar nossos testes.
Antes de continuar, vamos aprender algumas noções básicas. Algumas coisas importantes são muito usadas neste artigo, e você precisará entendê-las.
-
it
outest
Você passaria uma função para esse método e o executor de testes executaria essa função como um bloco de testes. -
describe
Este método opcional é para agrupar qualquer númeroit
ou de instruções detest
. -
expect
Esta é a condição que o teste precisa passar. Ele compara o parâmetro recebido com o matcher. Também lhe dá acesso a vários matchers que permitem validar coisas diferentes. Você pode ler mais sobre isso na documentação. -
mount
Este método renderiza o DOM completo, incluindo os componentes filho do componente pai, no qual estamos executando os testes. -
shallow
Isso renderiza apenas os componentes individuais que estamos testando. Ele não renderiza componentes filho. Isso nos permite testar componentes isoladamente.
Criando um arquivo de teste
Como Jest sabe o que é um arquivo de teste e o que não é? A primeira regra é que qualquer arquivo encontrado em qualquer diretório com o nome __test__
seja considerado um teste. Se você colocar um arquivo JavaScript em uma dessas pastas, o Jest tentará executá-lo quando você chamar o Jest, para melhor ou para pior. A segunda regra é que o Jest reconhecerá qualquer arquivo com o sufixo .spec.js
ou .test.js
. Ele irá pesquisar os nomes de todas as pastas e todos os arquivos em todo o seu repositório.
Vamos criar nosso primeiro teste, para um mini-aplicativo React criado para este tutorial. Você pode cloná-lo no GitHub. Execute npm install
para instalar todos os pacotes e, em seguida, npm start
para iniciar o aplicativo. Verifique o arquivo README.md
para obter mais informações.
Vamos abrir App.test.js
para escrever nosso primeiro teste. Primeiro, verifique se nosso componente de aplicativo é renderizado corretamente e se especificamos uma saída:
it("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const welcome = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(welcome)).toEqual(true); });
No teste acima, o primeiro teste, com shallow
, verifica se nosso componente de aplicativo é renderizado corretamente sem travar. Lembre-se de que o método shallow
renderiza apenas um único componente, sem componentes filhos.
O segundo teste verifica se especificamos uma saída de tag h1
de “Exibir conta de usuário ativa” em nosso componente de aplicativo, com um correspondente Jest de toEqual
.
Agora, execute o teste:
npm run test /* OR */ npm test
A saída no seu terminal deve ficar assim:
PASS src/App.test.js √ renders without crashing (34ms) √ renders Account header (13ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 11.239s, estimated 16s Ran all test suites related to changed files. Watch Usage: Press w to show more.
Como você pode ver, nosso teste passou. Isso mostra que temos um conjunto de testes chamado App.test.js
, com dois testes bem-sucedidos quando o Jest foi executado. Falaremos sobre o teste de instantâneo mais tarde, e você também verá um exemplo de teste com falha.
Ignorando ou isolando um teste
Ignorar ou isolar um teste significa que quando o Jest é executado, um teste marcado específico não é executado.
it.skip("renders without crashing", () => { shallow(<App />); }); it("renders Account header", () => { const wrapper = shallow(<App />); const header = <h1>Display Active Users Account Details</h1>; expect(wrapper.contains(header)).toEqual(true); });
Nosso primeiro teste será ignorado porque usamos o método skip
para isolar o teste. Portanto, ele não será executado ou fará alterações em nosso teste quando o Jest for executado. Apenas o segundo será executado. Você também pode usar it.only()
.
É um pouco frustrante fazer alterações em um arquivo de teste e depois executar manualmente npm test
novamente. O Jest tem um bom recurso chamado watch mode, que observa as alterações de arquivo e executa os testes de acordo. Para executar o Jest no modo de observação, você pode executar npm test -- --watch
ou jest --watch
. Eu também recomendaria deixar o Jest rodando na janela do terminal pelo resto deste tutorial.
Função de simulação
Um mock é uma duplicata convincente de um objeto ou módulo sem nenhum funcionamento interno real. Pode ter um pouco de funcionalidade, mas comparado com a coisa real, é uma simulação. Ele pode ser criado automaticamente pelo Jest ou manualmente.
Por que devemos zombar? A simulação reduz o número de dependências — ou seja, o número de arquivos relacionados que precisam ser carregados e analisados quando um teste é executado. Portanto, usar muitos mocks faz com que os testes sejam executados mais rapidamente.
As funções simuladas também são conhecidas como “espiões”, porque permitem espionar o comportamento de uma função que é chamada diretamente por algum outro código, em vez de apenas testar a saída.
Existem duas maneiras de simular uma função: criando uma função simulada para usá-la no código de teste ou escrevendo uma simulação manual para substituir uma dependência de módulo.
Os mocks manuais **** são usados para stub a funcionalidade com dados mock. Por exemplo, em vez de acessar um recurso remoto, como um site ou um banco de dados, você pode criar uma simulação manual que permita usar dados falsos.
Usaremos uma função simulada na próxima seção.
Testando componentes do React
A seção combinará todo o conhecimento que adquirimos até agora para entender como testar os componentes do React. O teste envolve certificar-se de que a saída de um componente não mudou inesperadamente para outra coisa. Construir componentes da maneira correta é, de longe, a maneira mais eficaz de garantir testes bem-sucedidos.
Uma coisa que podemos fazer é testar as props dos componentes — especificamente, testando se as props de um componente estão sendo passadas para outro. Jest e a API Enzyme nos permitem criar uma função simulada para simular se as props estão sendo passadas entre os componentes.
Temos que passar as props user-account do componente App
principal para o componente Account
. Precisamos fornecer os detalhes da conta de usuário à Account
para renderizar a conta ativa dos usuários. É aqui que o mocking é útil, permitindo que testemos nossos componentes com dados falsos.
Vamos criar uma simulação para os adereços do user
:
const user = { name: "Adeneye David", email: "[email protected]", username: "Dave", };
Criamos uma função de simulação manual em nosso arquivo de teste e a envolvemos nos componentes. Digamos que estamos testando um grande banco de dados de usuários. Não é aconselhável acessar o banco de dados diretamente de nosso arquivo de teste. Em vez disso, criamos uma função simulada, que nos permite usar dados falsos para testar nosso componente.
describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); });
describe(" ", () => { it("accepts user account props", () => { const wrapper = mount(<Account user={user} />); expect(wrapper.props().user).toEqual(user); }); it("contains users account email", () => { const wrapper = mount(<Account user={user} />); const value = wrapper.find("p").text(); expect(value).toEqual("[email protected]"); }); });
Temos dois testes acima e usamos uma camada de describe
, que pega o componente que está sendo testado. Ao especificar as props e os valores que esperamos que sejam aprovados pelo teste, podemos prosseguir.
No primeiro teste, verificamos se os adereços que passamos para o componente montado são iguais aos adereços simulados que criamos acima.
Para o segundo teste, passamos as props do usuário para o componente Account
montado. Em seguida, verificamos se podemos encontrar o elemento <p>
que corresponde ao que temos no componente Account
. Quando executarmos o conjunto de testes, você verá que o teste é executado com sucesso.
Também podemos testar o estado do nosso componente. Vamos verificar se o estado da mensagem de erro é igual a null:
it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); });
it("renders correctly with no error message", () => { const wrapper = mount( ); expect(wrapper.state("error")).toEqual(null); });
Neste teste, verificamos se o estado do nosso componente error é igual a null, usando um matcher toEqual()
. Se houver uma mensagem de erro em nosso aplicativo, o teste falhará quando executado.
Na próxima seção, veremos como testar componentes React com teste de snapshot, outra técnica incrível.
Teste de instantâneo
O teste de instantâneo captura o código de um componente em um momento, para compará-lo a um arquivo de instantâneo de referência armazenado junto com o teste. Ele é usado para acompanhar as alterações na interface do usuário de um aplicativo.
A representação de código real de um instantâneo é um arquivo JSON, e esse JSON contém um registro da aparência do componente quando o instantâneo foi criado. Durante um teste, o Jest compara o conteúdo desse arquivo JSON com a saída do componente durante o teste. Se eles corresponderem, o teste será aprovado; se não, o teste falha.
Para converter um wrapper Enzyme para um formato compatível com o teste de instantâneo do Jest, precisamos instalar enzyme-to-json
:
npm install --save-dev enzyme-to-json
Vamos criar nosso teste de instantâneo. Quando o executamos pela primeira vez, o snapshot do código desse componente será composto e salvo em uma nova pasta __snapshots__
no diretório src
.
it("renders correctly", () => { const tree = shallow(<App />); expect(toJson(tree)).toMatchSnapshot(); });
Quando o teste acima for executado com sucesso, o componente de interface do usuário atual será comparado ao existente.
Agora, vamos executar o teste:
npm run test
Quando o conjunto de testes for executado, um novo instantâneo será gerado e salvo na pasta __snapshots__
. Quando executamos um teste posteriormente, o Jest verificará se os componentes correspondem ao instantâneo.
Conforme explicado na seção anterior, esse método shallow
do pacote Enzyme é usado para renderizar um único componente e nada mais. Ele não renderiza componentes filho. Em vez disso, nos dá uma boa maneira de isolar o código e obter melhores informações ao depurar. Outro método, chamado mount
, é usado para renderizar o DOM completo, incluindo os componentes filho do componente pai, no qual estamos executando os testes.
Também podemos atualizar nosso snapshot, vamos fazer algumas alterações em nosso componente para que nosso teste falhe, o que acontecerá porque o componente não corresponde mais ao que temos no arquivo de snapshot. Para fazer isso, vamos alterar a tag <h3>
em nosso componente de <h3> Loading...</h3>
para <h3>Fetching Users...</h3>
. Quando o teste for executado, é isso que obteremos no terminal:
FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received
7 | it("renderiza corretamente", () => { 8 | const wrapper = raso( FAIL src/App.test.js (30.696s) × renders correctly (44ms) ● renders correctly expect(received).toMatchSnapshot() Snapshot name: `renders correctly 1 - Snapshot + Received
Exibir detalhes da conta de usuários ativos
- Carregando... + Buscando usuários...
); > 9 | expect(toJson(wrapper)).toMatchSnapshot(); | ^ 10 | }); 11 | 12 | /* it("renderiza sem travar", () => { em Objeto. (src/App.test.js:9:27) › 1 instantâneo falhou. Resumo do instantâneo › 1 snapshot falhou em 1 suíte de teste. Inspecione suas alterações de código ou pressione `u` para atualizá-las. Conjuntos de teste: 1 falhou, 1 total Testes: 1 falhou, 1 total Instantâneos: 1 falhou, 1 total Tempo: 92.274s Executou todos os conjuntos de testes relacionados aos arquivos alterados. Uso do relógio: Pressione w para mostrar mais.
Se quisermos que nosso teste passe, mudaríamos o teste para seu estado anterior ou atualizaríamos o arquivo de instantâneo. Na linha de comando, o Jest fornece instruções sobre como atualizar o instantâneo. Primeiro, pressione w
na linha de comando para mostrar mais e, em seguida, pressione u
para atualizar o instantâneo.
› Press u to update failing snapshots.
Quando pressionamos u
para atualizar o instantâneo, o teste será aprovado.
Conclusão
Espero que você tenha gostado de trabalhar com este tutorial. Aprendemos algumas técnicas de teste Jest usando a biblioteca de testes Enzyme. Também apresentei a você o processo de execução de um teste, teste de componentes React, simulação e teste de instantâneo. Se você tiver alguma dúvida, pode deixá-la na seção de comentários abaixo, e ficarei feliz em responder a todas e resolver qualquer problema com você.
Recursos e leitura adicional
- Documentação Jest
- Documentação da enzima
- “Como Testar Componentes do React: O Guia Completo”, Mohammad Iqbal, freeCodeCamp
- “Testing React With Jest and Enzyme”, Dominic Fraser, CodeClan