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, ViteParcel, 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

  1. 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.

  1. 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 como true, 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

  1. Crie um arquivo de teste chamado string-format.test.js.
  2. 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.
  3. 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.

  1. No arquivo package.json do seu projeto, adicione este script test:
"scripts": {
  "test": "jest"
}
  1. Agora, execute npm run test, npm test ou npm t em seu terminal. Ele executa o Jest para o projeto.

Quando você executa os testes, este é o resultado:

Resultado bem-sucedido do teste Jest para string-format.test.js.
Resultado bem-sucedido do teste Jest para string-format.test.js.

Os resultados mostram uma suíte de testes (o arquivo string-format.test.js), um teste executado com sucesso ("truncates a string correctly") e o displayName (Ecommerce) que você definiu na configuração.

  1. Em string-format.js, se você adicionar um ponto extra para quebrar o código e executar o teste, ele falhará:
Falha no resultado do teste Jest para uma função truncate quebrada.
Falha no resultado do teste Jest para uma função truncate quebrada.

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 para it. 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:

  1. 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...")
  })
})
  1. Execute o código.

O resultado se parece com o seguinte:

Resultado bem-sucedido do teste Jest mostrando o rótulo describe.
Resultado bem-sucedido do teste Jest mostrando o rótulo describe.

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.

  1. 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.

  1. 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.

  1. 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.

  1. 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.

  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.

  1. Execute os testes:
Resultado do teste Jest mostrando um teste com falha para código assíncrono.
Resultado do teste Jest mostrando um teste com falha para código assíncrono.

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.

  1. Remova a asserção da propriedade description e execute novamente os testes:
Resultado do teste Jest mostrando um teste bem-sucedido para código assíncrono.
Resultado do teste Jest mostrando um teste bem-sucedido para código assíncrono.

A captura de tela mostra que tudo passou no teste.

  1. 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.

  1. 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.

  1. 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.

  1. Quando você executa o teste, este é o resultado esperado:
Resultado bem-sucedido do teste Jest com uma função mock.
Resultado bem-sucedido do teste Jest com uma função mock.

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.

  1. 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.

  1. 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.

  1. 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'}],
  ],
};
  1. 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.

  1. 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.

  1. Agora, execute os testes. Se você clonou o branch starter-files, certifique-se de ter todas as dependências do projeto instaladas executando npm install antes de iniciar os testes.

Resultado de teste Jest mostrando que um componente react passou no teste.
Resultado de teste Jest mostrando que um componente react passou no teste.

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.

  1. 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"
}
  1. Execute npm run test para testar seu código. Você obtém um relatório como o seguinte:
Relatório de cobertura do Jest bem-sucedido para cada suíte de testes.
Relatório de cobertura do Jest bem-sucedido para cada suíte de testes.

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.

  1. 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"
}
  1. Execute npm run test. Isso aciona o Jest em watch mode:
Executando o Jest em watch mode.
Executando 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.

  1. Instale ghooks em devDependencies:
npm install ghooks --save-dev
  1. Adicione um objeto configs no nível superior do seu arquivo package.json (no projeto JavaScript).
  2. Adicione um objeto ghooks em configs.
  1. Adicione uma propriedade com uma chave de pre-commit e um valor de jest.
{
  …
  "config": {
    "ghooks": {
      "pre-commit": "jest"
    }
  },
}
  1. Faça o commit do código. O código aciona o hook de pre-commit, que executa o Jest:

Executando o Jest durante o pre-commit usando ghooks.
Executando o Jest durante o pre-commit usando ghooks.

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.

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.