Testes de software são fundamentais para garantir que seus aplicativos funcionem conforme o esperado, especialmente quando você faz alterações. A detecção e a correção de erros no início do desenvolvimento são cruciais para manter um código resiliente e de alta qualidade.
Entre as muitas ferramentas e os muitos frameworks disponíveis para testes de JavaScript, o Jest é um dos mais populares. Um produto da Meta, o Jest apresenta amplos recursos de testes para aplicativos JavaScript e aqueles criados com frameworks JavaScript.
Vamos explorar o framework Jest, seus recursos, e a melhor forma de integrá-lo ao seu fluxo de trabalho de desenvolvimento.
O que é o Jest?
O Jest é um framework flexível e simples de usar. Além de seus recursos principais de testes de JavaScript, oferece configurações e plugins para dar suporte a testes de aplicativos baseados em Babel, webpack, Vite, Parcel, ou TypeScript.
O Jest foi amplamente adotado pelos desenvolvedores e conta com uma série de plugins criados e mantidos pela comunidade. Ele se destaca por sua facilidade de uso: os testes em JavaScript não exigem configurações ou plugins adicionais. Mas você também pode executar testes mais avançados — como testar frameworks JavaScript — usando algumas opções de configuração adicionais.
Como configurar o Jest para o seu projeto JavaScript
Vamos explorar como você pode configurar o Jest em um projeto JavaScript existente.
Pré-requisitos
Para seguir este tutorial, certifique-se de que você tem o seguinte:
- Node.js instalado.
- O npm (que já faz parte do Node.js) ou o Yarn instalado.
- O pacote npm do Jest instalado.
Instale o pacote Jest
- Se você ainda não tiver um projeto para acompanhar este tutorial, use este repositório como ponto de partida.
O branch starter-files
fornece uma base para criar o aplicativo à medida que você segue o tutorial. Consulte o branch main
para ver o código deste tutorial e verificar seu código.
- Para instalar o Jest com o npm, vá para o diretório do projeto em seu terminal e execute o seguinte comando:
npm install --save-dev jest
A opção --save-dev
informa ao npm para instalar o pacote em devDependencies
, que contém as dependências de que você precisa para o desenvolvimento.
Configure o Jest
Embora o Jest geralmente funcione sem configuração adicional, há duas maneiras de expandir o seu poder: no arquivo package.json e por meio de um arquivo de configuração do Jest.
Configure o Jest em package.json
Em seu arquivo package.json, adicione um objeto chamado jest
com propriedades tais como as mostradas abaixo:
{
…
"jest": {
"displayName": "Ecommerce",
"globals": {
"PROJECT_NAME": "Ecommerce TD"
},
"bail": 20,
"verbose": true
},
}
Durante o teste, o Jest procura esse objeto e aplica essas configurações. Você pode visualizar opções adicionais na página de configurações do Jest, mas as propriedades desse objeto incluem:
displayName
— O Jest adiciona o valor dessa propriedade como um rótulo nos resultados dos testes.globals
— Mantém um valor de objeto para definir variáveis globais disponíveis em seus ambientes de teste.bail
— Por padrão, o Jest executa todos os testes e exibe os erros nos resultados.bail
diz ao Jest para parar de executar após um número definido de falhas.verbose
— Quando definido comotrue
, isso mostra relatórios individuais de testes durante a execução do teste.
Configure o Jest com um arquivo de configuração
Você também pode configurar o Jest em um arquivo jest.config.js. O Jest também suporta as extensões .ts, .mjs, .cjs e .json. Ao executar testes, o Jest procura esses arquivos e aplica as configurações no arquivo que encontrar.
Por exemplo, considere este arquivo jest.config.js:
const config = {
displayName: "Ecommerce",
globals: {
"PROJECT_NAME": "Ecommerce TD"
},
bail: 20,
verbose: true
}
module.exports = config;
O código exporta um objeto de configuração do Jest com as mesmas propriedades do exemplo anterior.
Você também pode usar um arquivo personalizado que contenha um objeto de configuração serializável em JSON e passar o caminho do arquivo para a opção --config
ao executar seus testes.
Crie um arquivo de teste básico
Com o Jest configurado, crie seus arquivos de teste. O Jest analisa os arquivos de teste do seu projeto, executa-os e fornece os resultados. Os arquivos de teste geralmente seguem um formato como [nome].test.js ou [nome]-test.js. Esse padrão facilita a identificação dos arquivos de teste tanto para o Jest quanto para sua equipe.
Considere um arquivo string-format.js que tenha o seguinte código:
function truncate(
str,
count,
withEllipsis = true
) {
if (str.length < = count)
return str
const substring = str.substr(0, count)
if (!withEllipsis)
return substring
return substring + '...'
}
module.exports = { truncate }
A função truncate()
trunca as strings de caracteres em um determinado tamanho, com a opção de adicionar reticências.
Escreva o teste
- Crie um arquivo de teste chamado string-format.test.js.
- Para manter seus arquivos organizados, coloque string-format.test.js no mesmo diretório em que você tem o arquivo string-format.js ou em um diretório de teste específico. Independentemente de onde o arquivo de teste esteja localizado no projeto, o Jest o encontra e executa. Com o Jest, você pode testar seus aplicativos em vários cenários.
- Escreva um teste básico em string-format.test.js da seguinte forma:
const { truncate } = require('./string-format')
test('truncates a string correctly', () = > {
expect(truncate("I am going home", 6)).toBe('I am g...')
})
O caso de teste tem a descrição truncates a string correctly
. Esse código usa a função expect
fornecida pelo Jest, que testa se um valor corresponde ao resultado esperado.
O código passa truncate("I am going home", 6)
como um argumento para expect
. Esse código testa o valor retornado ao chamar truncate
com os argumentos "I am going home"
e 6
. A chamada expect
retorna um objeto de expectativa, que oferece acesso aos matches do Jest.
Ele também contém o matcher toBe
, que tem "I am g…"
como argumento. O matcher toBe
testa a igualdade entre os valores esperados e os reais.
Execute o teste
Para executar seus testes, defina o comando jest
.
- No arquivo package.json do seu projeto, adicione este script
test
:
"scripts": {
"test": "jest"
}
- Agora, execute
npm run test
,npm test
ounpm t
em seu terminal. Ele executa o Jest para o projeto.
Quando você executa os testes, este é o resultado:
- Em string-format.js, se você adicionar um ponto extra para quebrar o código e executar o teste, ele falhará:
Esse resultado sugere que você quebrou a função truncate
ou fez atualizações que exigem a atualização dos testes.
Como escrever testes com Jest
Sintaxe de teste do Jest
A sintaxe proprietária do Jest é simples de usar. O Jest expõe métodos e objetos globais ao seu projeto para a escrita de testes. Alguns de seus termos fundamentais são describe
, test
, expect
, e matchers.
describe
: Essa função agrupa testes relacionados em um arquivo.test
: Essa função executa o teste. É um sinônimo parait
. Ela contém asserções para os valores que você deseja testar.expect
: Essa função declara as asserções para vários valores. Ela fornece acesso a matchers para várias formas de asserções.- Matchers: Permitem que você faça uma asserção de um valor de várias maneiras. Você pode afirmar a igualdade de valor, a igualdade booleana e a igualdade contextual (por exemplo, se um array contém o valor).
Para usá-los, considere o exemplo a seguir:
- Substitua o teste no arquivo string-format.test.js pelo seguinte código:
describe("all string formats work as expected", () = > {
test("truncates a string correctly", () = > {
expect(
truncate("I am going home", 6)
).toBe("I am g...")
})
})
- Execute o código.
O resultado se parece com o seguinte:
A captura de tela mostra que o rótulo na função describe
cria um bloco. Embora o describe
seja opcional, agrupar os testes em um arquivo com mais contexto é útil.
Organize testes em suítes de testes
No Jest, um caso de teste consiste na função test
, a função expect
e um matcher. Uma coleção de casos de teste relacionados é uma suíte de testes. No exemplo anterior, string-format.test.js é uma suíte de testes que inclui um caso de teste para testar o arquivo string-format.js.
Suponha que você tenha mais arquivos em seu projeto, como file-operations.js, api-logger.js e number-format.js. Você pode criar suítes de testes para esses arquivos, como file-operations.test.js, api-logger.test.js e number-format.test.js.
Escreva asserções simples com os matchers do Jest
Exploramos um exemplo de uso do matcher toBe
. Asserções com outros matchers do Jest incluem:
toEqual
— Para testar a igualdade “detalhada” em instâncias de objetos.toBeTruthy
— Para testar se um valor é verdadeiro em um contexto booleano.toBeFalsy
— Para testar se um valor é falso em um contexto booleano.toContain
— Para testar se um array contém um valor.toThrow
— Para testar se uma função invocada gera um erro.stringContaining
— Para testar se uma string contém uma substring.
Vamos explorar exemplos usando alguns desses matchers.
Você pode, por exemplo, esperar que uma função ou código retorne um objeto com propriedades e valores específicos.
- Use o snippet de código abaixo para testar essa funcionalidade. Nesse caso, você deseja afirmar que o objeto retornado é igual a um objeto esperado.
expect({
name: "Joe",
age: 40
}).toBe({
name: "Joe",
age: 40
})
Este exemplo usa toBe
. O teste falha porque esse matcher não verifica a igualdade detalhada — ele verifica o valor, não todas as propriedades.
- Use o matcher
toEqual
para verificar a igualdade detalhada:
expect({
name: "Joe",
age: 40
}).toEqual({
name: "Joe",
age: 40
})
Este teste é bem-sucedido porque os dois objetos são “iguais”, o que significa que todas as suas propriedades são iguais.
- Experimente outro exemplo de matcher que testa se o array definido contém um elemento específico.
expect(["orange", "pear", "apple"]).toContain("mango")
Este teste falha porque toContain
afirma que o array ["orange", "pear", "apple"]
contém o valor esperado "mango"
, mas o array não contém.
- Use variáveis para o mesmo teste, como no código abaixo:
const fruits = ["orange", "pear", "apple"];
const expectedFruit = "mango";
expect(fruits).toContain(expectedFruit)
Teste código assíncrono
Até agora, testamos código síncrono — expressões que retornam um valor antes de o código executar a linha seguinte. Você também pode usar o Jest para código assíncrono com async
, await
, ou Promises.
Por exemplo, o arquivo apis.js tem uma função para fazer uma solicitação de API:
function getTodos() {
return fetch('https://jsonplaceholder.typicode.com/todos/1')
}
A função getTodos
envia uma solicitação GET
para https://jsonplaceholder.typicode.com/todos/1
.
- Crie um arquivo chamado apis.test.js com o seguinte código para testar a API falsa:
const { getTodos } = require('./apis')
test("gets a todo object with the right properties", () = > {
return getTodos()
.then((response) = > {
return response.json()
})
.then((data) = > {
expect(data).toHaveProperty('userId')
expect(data).toHaveProperty('id')
expect(data).toHaveProperty('title')
expect(data).toHaveProperty('completed')
expect(data).toHaveProperty('description')
})
})
Este caso de teste invoca a função getTodos
que obtém um objeto todo
. Quando resolve a Promise, usa o método .then
para obter o valor resolvido.
Nesse valor, o código retorna response.json()
, que é outra Promise que converte a resposta para o formato JSON. Outro método .then
obtém o objeto JSON que contém o expect
e matchers. O código afirma que o objeto JSON inclui cinco propriedades: userId
, id
, title
, completed
, e description
.
- Execute os testes:
Como mostra a captura de tela, o teste para getTodos()
falha. Ele espera a propriedade description
, mas a API não a retorna. Com essas informações, agora você pode pedir à equipe de gerenciamento de API da sua empresa que inclua essa propriedade se o aplicativo precisar dela ou que atualize os testes para corresponder à resposta da API.
- Remova a asserção da propriedade
description
e execute novamente os testes:
A captura de tela mostra que tudo passou no teste.
- Agora você pode tentar usar
async/await
em vez do tratamento Promise tradicional:
test("gets a todo object with the right properties", async () = > {
const response = await getTodos()
const data = await response.json()
expect(data).toHaveProperty("userId")
expect(data).toHaveProperty("id")
expect(data).toHaveProperty("title")
expect(data).toHaveProperty("completed")
})
A palavra-chave async
agora está antes da função. O código usa await
antes de getTodos()
e await
antes de response.json()
.
Recursos avançados do Jest
Funções e módulos mock
Você pode querer testar uma expressão com dependências externas ao escrever testes. Em alguns casos, especialmente em testes de unidade, seus testes devem ser isolados de efeitos externos. Nesse caso, você pode simular suas funções ou módulos com o Jest para controlar melhor seus testes.
- Por exemplo, considere um arquivo functions.js que contém o seguinte código:
function multipleCalls(count, callback) {
if (count < 0) return;
for (let counter = 1; counter <= count; counter++) {
callback()
}
}
A função multipleCalls
é executada com base no valor de count
. Ela depende da função callback — a dependência externa. Seu objetivo é saber se o multipleCalls
executa a dependência externa corretamente.
- Para simular a dependência externa e rastrear o estado da dependência em seu arquivo de teste, functions.test.js, use este código:
const { multipleCalls } = require('./functions')
test("functions are called multiple times correctly", () => {
const mockFunction = jest.fn()
multipleCalls(5, mockFunction)
expect(
mockFunction.mock.calls.length
).toBe(5)
})
Aqui, o método fn
do objeto jest
cria uma função mock. Em seguida, o código executa multipleCalls
passando 5
e a função mock como argumentos. Em seguida, ele afirma que mockFunction
é chamada cinco vezes. A propriedade mock
contém informações sobre como o código chama a função e os valores retornados.
- Quando você executa o teste, este é o resultado esperado:
Conforme demonstrado, o código chama a mockFunction
cinco vezes.
No código, a função mock imita uma dependência externa. Não importa qual é a dependência externa quando o aplicativo usa multipleCalls
na produção. Seu teste de unidade não se importa com o funcionamento da dependência externa. Apenas verifica se o multipleCalls
funciona conforme o esperado.
- Para simular módulos, use o método
mock
e passe um caminho de arquivo, que é o módulo:
const {
truncate,
} = require("./string-format")
jest.mock("./string-format.js")
Este código imita todas as funções que o string-format.js exporta e rastreia com que frequência ele as chama. O truncate
do módulo se torna uma função mock, o que faz com que a função perca sua lógica original. Você pode descobrir quantas vezes o truncate
é executado em seus testes na propriedade truncate.mock.calls.length
.
Se você tiver um erro ou seu código não funcionar, compare seu código com a implementação completa.
Teste componentes React com o Jest e a React Testing Library
Se você ainda não tiver um projeto para acompanhar este tutorial, pode usar este projeto de exemplo do React como ponto de partida. O branch starter-files
ajuda você a começar a compor o código à medida que segue o tutorial. Use o branch main
como referência para verificar seu código em relação ao código completo deste tutorial.
Você pode usar o Jest para testar frameworks JavaScript como o React. Quando você cria projetos React usando o Create React App, eles dão suporte à React Testing Library e o Jest por padrão. Se você criar um projeto React sem o Create React App, instale o Jest para testar o React com o Babel e a React Testing Library. Se você clonar o branch starter-app
, não precisa instalar dependências ou aplicar configurações.
- Se estiver usando o projeto de exemplo, use este comando para instalar as dependências necessárias:
npm install --save-dev babel-jest @babel/preset-env @babel/preset-react react-testing-library
Você também pode usar o Enzyme em vez da React Testing Library.
- Atualize as configurações do Babel em babel.config.js, ou crie este arquivo se ele não existir:
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};
- Considere o arquivo src/SubmitButton.js que tem o seguinte código:
import React, { useState } from 'react'
export default function SubmitButton(props) {
const {id, label, onSubmit} = props
const [isLoading, setisLoading] = useState(false)
const submit = () => {
setisLoading(true)
onSubmit()
}
return
Esse componente SubmitButton
recebe três propriedades:
id
— O identificador do botão.label
— O texto a ser renderizado no botão.onSubmit
— Qual função é acionada quando alguém clica no botão.
O código atribui a propriedade id
ao atributo data-testid
, que identifica um elemento para teste.
O componente também rastreia o estado isLoading
e o atualiza para true
quando alguém clica no botão.
- Crie o teste para esse componente. Insira o seguinte código em um arquivo SubmitButton.test.js:
import {fireEvent, render, screen} from "@testing-library/react"
import "@testing-library/jest-dom"
import SubmitButton from "./SubmitButton"
test("SubmitButton becomes disabled after click", () => {
const submitMock = jest.fn()
render(
<SubmitButton
id="submit-details"
label="Submit"
onSubmit={submitMock}
/ >
)
expect(screen.getByTestId("submit-details")).not.toBeDisabled()
fireEvent.submit(screen.getByTestId("submit-details"))
expect(screen.getByTestId("submit-details")).toBeDisabled()
})
O código acima renderiza o componente SubmitButton
e usa o método de consulta screen.getByTestId
para obter o node DOM pelo atributo data-testid
.
O primeiro expect
é getByTestId("submit-details")
e usa o modificador not
e o matcher toBeDisabled
(exposto a partir de react-testing-library
) para afirmar que o botão não está desativado. Use o modificador not
com cada matcher para afirmar o oposto do matcher.
Em seguida, o código dispara o evento submit
no componente e verifica que o botão está desativado. Você pode encontrar mais matchers personalizados na documentação da biblioteca de testes.
- Agora, execute os testes. Se você clonou o branch
starter-files
, certifique-se de ter todas as dependências do projeto instaladas executandonpm install
antes de iniciar os testes.
Execute relatórios de cobertura de código
O Jest também oferece relatórios de cobertura de código para mostrar quanto do seu projeto você está testando.
- Passe a opção
--coverage
para o Jest. Em seu script Jest em package.json (no projeto JavaScript), atualize o comando Jest com esta opção de cobertura:
"scripts": {
"test": "jest --coverage"
}
- Execute
npm run test
para testar seu código. Você obtém um relatório como o seguinte:
Esse relatório mostra que o Jest testou 100% das funções em SubmitButton.js e string-format.js. Ele também indica que o Jest não testou nenhuma declaração e linha em string-format.js. A cobertura do teste mostra que as linhas não cobertas em string-format.js são a 7 e a 12.
Na linha 7, return str
na função truncate
não é executada porque a condição if (str.length <= count)
retorna false
.
Na linha 12, também na função truncate
, a return substring
não é executada porque a condição if (!withEllipsis)
retorna false.
Integre o Jest ao seu fluxo de trabalho de desenvolvimento
Vejamos como você pode integrar esses testes para melhorar seu fluxo de trabalho de desenvolvimento.
Execute testes em watch mode
Em vez de executar testes manualmente, você pode executá-los automaticamente quando alterar seu código usando o watch mode.
- Para ativar o watch mode, atualize seu script de comando Jest em package.json (no projeto JavaScript) adicionando a opção
--watchAll
:
"scripts": {
"test": "jest --coverage --watchAll"
}
- Execute
npm run test
. Isso aciona o Jest em watch mode:
Os testes são executados sempre que você altera o projeto. Essa abordagem promove feedback contínuo à medida que você constrói seu aplicativo.
Configure hooks de pre-commit
Em ambientes Git, os hooks executam scripts sempre que ocorre um evento específico (como pull, push ou commit). Os hooks de pre-commit definem quais scripts são executados para o evento de pre-commit (que o código aciona antes de fazer um commit).
O commit só terá sucesso se o script não gerar um erro.
A execução do Jest antes do pre-commit garante que nenhum dos seus testes falhe antes do commit.
Você pode usar várias bibliotecas para configurar hooks do git em seu projeto, tal como a ghooks.
- Instale
ghooks
emdevDependencies
:
npm install ghooks --save-dev
- Adicione um objeto
configs
no nível superior do seu arquivo package.json (no projeto JavaScript). - Adicione um objeto
ghooks
emconfigs
.
- Adicione uma propriedade com uma chave de
pre-commit
e um valor dejest
.
{
…
"config": {
"ghooks": {
"pre-commit": "jest"
}
},
}
- Faça o commit do código. O código aciona o hook de pre-commit, que executa o Jest:
Resumo
Agora você sabe como integrar o Jest ao seu fluxo de trabalho de desenvolvimento para executá-lo automaticamente sempre que fizer uma alteração. Essa abordagem fornece feedback contínuo para que você possa corrigir rapidamente quaisquer problemas de código antes de liberar suas alterações para a produção.
Ao hospedar seu aplicativo com a Kinsta, você se beneficia de uma infraestrutura rápida e segura, implantando seus projetos na infraestrutura construída na rede de nível premium do Google Cloud Platform e máquinas C2. Você pode escolher entre os 37 centros de dados e uma CDN habilitada para HTTP/3 com 260+ PoPs.
Mantenha-se seguro com a tecnologia de contêineres isolados, dois firewalls robustos e proteção avançada contra DDoS com tecnologia Cloudflare. E você pode integrar aplicativos ou automatizar fluxos de trabalho com a API da Kinsta.
Configure o Jest e navegue pelos recursos da Kinsta hoje mesmo para aprimorar seus aplicativos JavaScript.
Deixe um comentário