Escrevendo testes automatizados com React e TypeScript

Escrevendo testes automatizados com React e TypeScript

Imagine que após um dia muito cansativo, você quer relaxar e assistir um filme de comédia no seu streaming preferido.

Geralmente, para filtrar apenas produções desse gênero utilizamos a barra de pesquisa, digitamos por "Comédia" e ao efetuar a busca, esperamos que a pesquisa retorne apenas os títulos correspondentes a essa categoria.

Contudo, suponha que, por alguma razão, produções de diferentes gêneros sejam incluídas junto aos resultados dos filmes de comédia.

Temos um problema, pois precisaríamos separar manualmente o resultado de uma filtragem automática.

Para evitar essa situação e assegurar que o filtro exiba apenas as produções do gênero, podemos implementar testes de software para garantir a precisão dos resultados.

Neste artigo, escreveremos testes em React com TypeScript para funcionalidades de um projeto de lista de filmes, e exploraremos:

  • A importância dos testes no desenvolvimento de softwares;
  • Quais são as principais bibliotecas e frameworks para realizar os testes;
  • Como estruturar os testes para um componente.

Por que testar?

Assim como os testes ajudam a garantir que os filtros de busca de um streaming atuem da forma como foram programados, eles também são importância para:

  • Garantir a qualidade do código durante o desenvolvimento;
  • Encontrar e resolver bugs com maior rapidez e facilidade;
  • Realizar refatorações no código com mais confiança;
  • Atuar como documentação das funções aplicadas e resultados esperados.

Há vários tipos de teste e se você quiser conferir mais sobre eles, recomendo a leitura do artigo Tipos de testes: quais os principais e por que utilizá-los?, que explica os tipos mais utilizados atualmente: testes unitários, de integração e ponta a ponta (E2E), além de explorar as diferenças entre testes manuais e automatizados.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

Etapas de um teste

A testagem possui três passos: organizar, agir e afirmar (Arrange, Act e Assert ou AAA).

Na etapa de organização, buscamos os elementos; a ação é o momento em que alguma coisa acontece, como o clique de um botão e na afirmação ou declaração estabelecemos uma hipótese sob o estado da aplicação, que pode resultar em sucesso ou fracasso.

Desenvolvimento Orientado a Testes

Ao desenvolver o projeto da lista de filmes, podemos adotar uma estratégia de testes muito popular, conhecida como Desenvolvimento Orientado a testes (TDD), em que os testes são elaborados antes do código da funcionalidade, com isso temos maior qualidade e eficiência na criação dos elementos do projeto, já que escrevemos o código para que ele passe no teste proposto.

O processo do TDD inclui três fases encadeadas em um ciclo:

1 - Criamos um teste que falha;

2 - Desenvolvemos um código para passar no teste;

3 - Refatoramos o código para eliminar as redundâncias.

Círculo dividido em três partes iguais, com as três fases do Desenvolvimento Dirigido por testes e setas apontando para a fase seguinte em um sentido horário.

Bibliotecas e Frameworks para testes

Em React há dois recursos muito interessantes para escrever testes de forma fácil e intuitiva, são eles o React Testing Library (RTL) e o Jest.

Eles possuem um conjunto de funções e propriedades muito amplo e, por isso, utilizaremos ambos para testar todas as funcionalidades do projeto da lista de filmes.

React Testing Library

Essa biblioteca, busca e interage com os elementos presentes em cada componente, de modo a simular as interações das pessoas usuárias, ou seja, conseguimos: verificar a presença de um texto na tela, reproduzir um evento de click e buscar por elementos com funções determinadas, por exemplo, podemos buscar por uma tag <button>, que possui por padrão a função button.

Dessa forma, há um estímulo para o uso de tags HTML semânticas, o que auxilia pessoas que utilizam recursos assistivos como leitores de tela. Com isso, aumentamos a acessibilidade da aplicação.

Jest

Este framework de testes em JavaScript, atua como um ambiente onde os testes são executados.

Por ser um executor baseado em Node, os testes rodam em um ambiente Node, ou seja, os testes são executados no terminal e não no navegador, por isso o Jest possui uma maior velocidade de interação evitando instabilidade.

Dentre as facilidades que o Jest proporciona, conseguimos usar um ambiente de testes sem a necessidade de configurações extras, organizar a estrutura dos testes e simplificar simulações de objetos, funções, módulos e temporizadores fora do escopo do teste.

O que precisamos para começar a realizar os testes?

Após definir a estratégia e os recursos para nosso projeto de lista de filmes, daremos início ao desenvolvimento da nossa aplicação em React e TypeScript, optando pelo uso do Vite.

Para uma compreensão abrangente das configurações iniciais, recomendo o artigo Utilizando o Vite para criar uma aplicação React com TypeScript, que detalha os comandos a serem seguidos e detalha informações sobre os arquivos e diretórios criados.

Em seguida, vamos abrir o terminal na pasta do projeto e instalar o Jest e os tipos utilizados pelo TypeScript:

npm i --save-dev jest @types/jest 

Para utilizar o interpretador do Jest com o comando npm run test é necessário configurar o arquivo "package.json" inserindo o script:

"test":"jest"
Tela do VS Code com a aba Explorer com o projeto lista de filmes aberta na lateral esquerda. Ao centro da tela o arquivo package.json aberto com as instalações padrões e a adição do script para usar o executor jest ao iniciar o comando npm run test.

Ainda no arquivo "package.json", mas ao final do código vamos definir o ambiente de teste em que os testes serão executados através do testEnvironmente especificar uma lista de scripts executados após o ambiente de teste ser configurado por meio do setupFilesAfterEnv.

  "jest": {
    "testEnvironment": "jest-environment-jsdom",
    "setupFilesAfterEnv": [
      "<rootDir>/setup-tests.js"
    ]
  }
Tela do VS Code com a aba Explorer com o projeto lista de filmes aberta na lateral esquerda. Ao centro da tela o arquivo package.json aberto com as instalações padrões e a adição das configurações do ambiente de teste e lista de scripts do jest.

Como definimos o setupFilesAfterEnv precisamos criar o arquivo na raiz do projeto com a importação dos scripts.

Portanto, nomeamos um arquivo como "setup-tests.js" e adicionamos a linha de código:

import "@testing-library/jest-dom"
Tela do VS Code com a aba Explorer com o projeto lista de filmes aberta na lateral esquerda. Ao centro da tela o arquivo setup-tests.js aberto com a importação da *lib* jest-dom do React Testing Library.

Para interagir com os elementos na página, vamos instalar no terminal as libs do React Testing Library:

npm i --save-dev @testing-library/jest-dom @testing-library/react @testing-library/user-event

Agora precisamos instalar no terminal o Babel para converter todas as informações dos testes. Portanto, voltaremos ao terminal e digitaremos o seguinte código:

npm i --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript babel-jest identity-obj-proxy jest-environment-jsdom

Agora vamos criar um novo arquivo na raiz do projeto chamado ".babelrc" para garantir que o código funcione em diferentes navegadores, mantendo a versão mais recente sempre que possível.

Dessa forma precisamos adicionar o seguinte trecho de código:

{
    "presets": [
      [
        //Usa as funcionalidades recentes do JavaScript
        "@babel/preset-env",
        {
          //Convete o código apenas se necessário
          "targets": {
            "esmodules": true
          }
        }
      ],
      [
        //Habilita o suporte ao React
        "@babel/preset-react",
        {
          //Permite importar automaticamente os métodos necessários
          "runtime": "automatic"
        }
      ],
      //Permite suporte ao TypeScript e converte esse código em JavaScript
      "@babel/preset-typescript"
    ]
  }
Tela do VS Code com a aba Explorer com o projeto lista de filmes aberta na lateral esquerda. Ao centro da tela o arquivo babelrc aberto com um trecho de código para converter as informações de React, Jest e TypeScript.

Por fim, para garantir que todos os tipos funcionem corretamente, podemos abrir o arquivo "tsconfig.json" e adicionar o seguinte código:

 "types": ["node", "jest", "@testing-library/jest-dom"]

O código completo no arquivo "tsconfig.json" ficaria assim:

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "types": ["node", "jest", "@testing-library/jest-dom"],

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

Após finalizar as configurações de ambiente, podemos iniciar os testes da lista de filmes!

Testes da Lista de Filmes

Testar se o botão está desabilitado e se os elementos estão na página

Inicialmente começaremos pelos testes e funcionalidades do formulário. Por isso, organizaremos as pastas dos componentes dentro de "src" da seguinte forma:

src
  |__ componentes
          |__Formulario
               |__Formulario.tsx
               |__Formulario.test.tsx

A extensão .test é utilizada para identificar e organizar os arquivos de teste. Dessa forma, ao rodar o comando npm run test o Jest busca pelos arquivos com esta extensão e executa os testes.

No arquivo "Formulario.test.tsx" vamos escrever o primeiro teste, responsável por verificar a presença dos inputs na página e se o botão está desabilitado.

import { render } from "@testing-library/react"
import { Formulario } from "./Formulario"

test('se os campos estiverem vazios, o botão deve estar desabilitado', () => {

    //ARRANGE - organiza os elementos em variáveis

    //Importa as funções e renderiza o componente Formulario
    const { getByPlaceholderText, getByRole } = render(<Formulario/>)

    //Busca os inputs pelo texto no placeholder
    const inputNome = getByPlaceholderText('Insira o nome do filme') 
    const inputAnoDeLancamento = getByPlaceholderText('Digite o ano de lançamento')

    //Buscao botão pela função
    const botaoAdicionar = getByRole('button');

    //ASSERT - cria hipóteses para serem testadas   

    //Verifica se os elementos estão na página
    expect(inputNome).toBeInTheDocument() 
    expect(inputAnoDeLancamento).toBeInTheDocument()

    //Verifica se o botão está desabilitado
    expect(botaoAdicionar).toBeDisabled()
})

Este código é um exemplo de como escrevemos testes usando o RTL e o Jest. Utilizamos a função testque recebe dois parâmetros, um texto sobre o que será testado e uma arrow function com as instruções do teste.

Ao utilizar o comando npm run test no terminal integrado do VS Code, recebemos algumas informações como mostrado na imagem:

Linha de comando mostrando o resultado do primeiro teste com as informações: Test Suites, Tests, Snapshots e Time. O teste retorna um resultado que falha.

Detalhando cada uma, temos:

  • Test Suites: que indica a quantidade de arquivos de teste. Podem estar com status de aprovados (cor verde e mensagem passes) ou reprovados (cor vermelha e mensagem failed).
  • Tests: mostram a quantidade de testes aprovados (cor verde e mensagem passes) ou reprovados (cor vermelha e mensagem failed).
  • Snapshots: responsáveis pelo registro de um momento no código que pode ser usado para comparar com outras versões futuras.
  • Time: mostra o tempo decorrido para realizar o teste.

Como adotamos a metodologia TDD, onde os testes são escritos antes das funcionalidades, o teste retorna um status de reprovado.

E ao nos depararmos com um teste que não foi bem-sucedido, podemos confirmar o problema que ocorreu através da mensagem de erro que aparece acima do resultado do teste.

Linha de comando com uma mensagem de erro indicando o motivo pelo fracasso de um teste.

Para o teste passar, precisamos criar as funcionalidades necessárias nos componentes "App.tsx" e no "Formulario.tsx".

No "App.tsx adicionamos o código:

import { Formulario } from "./componentes/Formulario/Formulario"

//Interface para validar os tipos dos inputs
export interface Filme {
  nome: string,
  anoDeLancamento: string
}

export default function App(){
  return(
    <div>
      {/* Renderização do formulario */}
    <Formulario/>
    </div>
  )
}

Enquanto no Formulário precisamos escrever o seguinte código:

import { useState } from "react";
import { Filme } from "../../App";

export const Formulario = () => {

    //Uso do hook useState para alterar o estado da aplicação
    const [filme, setFilme] = useState<Filme>({ nome: '', anoDeLancamento: '' })

    //Variável aplicada ao botão para verificar se está desabilitado ou habilitado
    const podeAdicionar = filme.nome && filme.anoDeLancamento;

    return (
        <form>
            <input
                type="text"
                placeholder="Insira o nome do filme"
                required
            />
            <input
                type="text"
                placeholder="Digite o ano de lançamento"
                required
            />
            <button
                disabled={!podeAdicionar}
                type="submit"
            >
                Adicionar
            </button>
        </form>
    )
}

Ao executar o teste novamente, temos um resultado bem-sucedido!

Linha de comando com um teste no formulário sendo aprovado.
GIF de duas mulheres brancas comemorando felizes e batendo palmas.

Testar se o botão está habilitado quando os campos estão preenchidos

Agora, vamos verificar se o botão está habilitado quando os campos estão preenchidos.

Como escreveremos mais de um teste dentro do arquivo "Formulario.test.tsx", podemos adotar a estratégia de agrupar esses testes com o describe, que assim como o test, recebe dois parâmetros, um texto e uma arrow function.

import { render } from "@testing-library/react"
import { Formulario } from "./Formulario"
import userEvent from "@testing-library/user-event"

describe('no formulário', ()=>{
    test('se os campos estiverem vazios, o botão deve estar desabilitado', () => {
    //...Código omitido
    })    

    test('se os inputs estiverem vazios, o botão deve estar habilitado', async () => {
        const { getByPlaceholderText, getByRole } = render(<Formulario/>)

        //ARRANGE - organiza os elementos em variáveis
        const inputNome = getByPlaceholderText('Insira o nome do filme')
        const inputAnoDeLancamento = getByPlaceholderText('Digite o ano de lançamento')
        const botaoAdicionar = getByRole('button');

        //ACT - simula a execução de ações

        //Simula de forma assíncrona a inserção de text dentro do input
        await userEvent.type(inputNome, 'Interestelar')
        await userEvent.type(inputAnoDeLancamento, '2014')

        //Simula de forma assíncrona o evento de click
        await userEvent.click(botaoAdicionar)

        //ASSERT - cria hipóteses para serem testadas

        //Verifica se o botão está habilitado
        expect(botaoAdicionar).toBeEnabled()
    })
})

Ao rodar os testes, um deve passar e o outro falhar.

Linha de comando. Na parte superior está o agrupamento dos dois testes devido ao uso do describe. No meio está a mensagem de erro indicando o motivo da falha no teste. Na parte inferior temos a quantidade de testes aprovados ou reprovados.

Na imagem acima, podemos identificar a organização dos testes ao usar o describe.

Para o teste ser aprovado, adicionaremos as propriedadesvalue e onChange nos inputs.

            <input
                type="text"
                placeholder="Insira o nome do filme"
                value={filme.nome}
                onChange={evento => setFilme({ ...filme, nome: evento.target.value })}
                required
            />
            <input
                type="text"
                placeholder="Digite o ano de lançamento"
                value={filme.anoDeLancamento}
                onChange={evento => setFilme({ ...filme, anoDeLancamento: evento.target.value })}
                required
            />
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro o arquivo Formulario.tsx está aberto com o código as propriedades value e onChange dos inputs em evidência.

E com isso temos os dois testes funcionando!

Linha de comando com dois testes no formulário sendo aprovados.

Testar a adição do filme na lista

Para adicionar um filme na lista precisamos adicionar uma nova pasta dentro de componentes chamada "ListaDeFilmes" com os arquivos "ListaDeFilmes.test.tsx" e "ListaDeFilmes.tsx". A organização das pastas deve ficar assim:

src
  |__ componentes
          |__Formulario
               |__Formulario.tsx
               |__Formulario.test.tsx
          |__ListaDeFilmes
               |__ListaDeFilmes.tsx
               |__ListaDeFilmes.test.tsx

Aplicamos o seguinte teste no arquivo "ListaDeFilmes.test.tsx":

import { render } from "@testing-library/react"
import { ListaDeFilmes } from "./ListaDeFilmes"

describe('na lista', ()=>{
    test('o item deve estar presente', ()=>{

        //Simulamos a inserção de um objeto dentro da lista e armazenamos em uma variável
        const filmes = [{ nome: 'Interestelar', anoDeLancamento: '2014' }];
        const {getByText} = render(<ListaDeFilmes filmes={filmes}/>)

        //ARRANGE - organiza os elementos em variáveis

        //Busca o elemento pelo texto
        const filmeNaLista = getByText('Interestelar(2014)')

        //ASSERT - cria hipóteses para serem testadas

        //Verifica se os elementos estão na página
        expect(filmeNaLista).toBeInTheDocument()
    })
})

Inicialmente o teste falha, mas os demais testes no componente Formulario continuam passando.

Linha de comando. Dois arquivos são testados com três testes sendo executados, dois são aprovados e um é reprovado.

Esta funcionalidade precisa ser construída em três componentes diferentes: "App.tsx", "Formulario.tsx" e "ListaDeFilmes.tsx".

No "App.tsx" vamos construir a função adicionarFilme() para inserir os filmes na lista.

 //Uso do hook useState para alterar o estado da lista
  const [filmes, setFilmes] = useState<Filme[]>([])

  //Função que adiciona filmes à lista
  function adicionarFilme(filme: Filme) {
    setFilmes([...filmes, filme])
  }

Essa função precisa ser enviada para o formulário via props para que ao clicar no botão "Adicionar" ela seja acionada.

  <Formulario aoSubmeter={adicionarFilme} />

Como teremos que criar um componente para armazenar a lista, já faremos a adição dele no App, passando via props a variável [filmes,setFilmes] que criamos com useState.

 <ListaDeFilmes filmes={filmes}/>
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro o arquivo App.tsx está aberto com o código para alterar o estado da lista usando o useState, a função para adicionar um filme e a renderização do formulário com a props em destaque.

No "Formulario.tsx" vamos precisar fazer algumas alterações em virtude da props recebida de "App.tsx".

Recebemos a props via interface:

interface FormularioProps{
    aoSubmeter: (filme: Filme) => void
}

Adicionamos a props como parâmetro na função armazenada na variável Formulario:

export const Formulario = ({ aoSubmeter } : FormularioProps)

Escrevemos uma função para processar os dados capturados pelo formulário e adicionar à lista de filmes:

    function adicionarFilme(evento: React.FormEvent<HTMLFormElement>) {
        evento.preventDefault()
        aoSubmeter(filme)
    }

Adicionamos na tag <form> a função na propriedade onSubmit para ser executada quando o botão com type submit for clicado.

 <form onSubmit={adicionarFilme}>
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro o arquivo Formulario.tsx está aberto com os códigos referentes a adição da props em destaque.

Como o Formulario recebe uma props com uma função, precisamos alterar os testes em "Formulario.test.tsx", caso contrário, receberemos um erro sinalizando que aoSubmeter não é uma função.

Para isso, vamos mockar uma função com o jest, ou seja, simulamos no arquivo de teste a função que está presente no componente.

 const mockAoSubmeter = jest.fn();

No momento de renderizar o componente para fazer o teste devemos mencionar que aoSubmeter recebe a simulação de uma função.

render(<Formulario aoSubmeter={mockAoSubmeter}/>)
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro o arquivo Formulario.test.tsx está aberto com os códigos referentes aos testes e a adição de uma simulação da função aoSubmeter.

Na "Lista.tsx", vamos criar o componente do início:

import { Filme } from "../../App";

//Recebe a lista de filmes via props em uma interface
interface ListaDeFilmesProps {
    filmes: Filme[];
  }

export const ListaDeFilmes = ({filmes}:ListaDeFilmesProps) =>{
    return(
        //Usa o map para percorrer a lista e inserir os itens dentro dela.
        <ul>
        {filmes.map((f, index) => (
          <li key={index} data-testid="lista">{`${f.nome}(${f.anoDeLancamento})`}</li>
        ))}
      </ul>
    )
}

Após as alterações e adições, o teste é aprovado.

Linha de comando. Dois arquivos são testados com três testes sendo aprovados.

Teste para evitar dados duplicados

Os filmes já estão sendo inseridos na tela, mas queremos evitar que itens duplicados sejam adicionados e para isso podemos criar um novo teste.

Então, criaremos o arquivo "App.test.tsx" no mesmo nível do arquivo "App.tsx" e escreveremos o seguinte código:

import {render} from "@testing-library/react"
import App from "./App"
import userEvent from "@testing-library/user-event"

describe('na tela', ()=>{   

    test('uma mensagem de erro deve aparecer na tela se a pessoa usuária tentar inserir um filme repetido', async () => {
        const {getByPlaceholderText, getByRole, getByText} = render(<App/>)

        //ARRANGE - organiza os elementos em variáveis

        ////Busca os inputs pelo texto no placeholder e pela função
        const inputNome = getByPlaceholderText('Insira o nome do filme')
        const inputAnoDeLancamento = getByPlaceholderText('Digite o ano de lançamento')
        const botaoAdicionar = getByRole('button')

        //ACT - simula a execução de ações

        //Simula a inserção de um filme duas vezes
        await userEvent.type(inputNome, 'Interestelar')
        await userEvent.type(inputAnoDeLancamento, '2014')
        await userEvent.click(botaoAdicionar)
        await userEvent.clear(inputNome);
        await userEvent.clear(inputAnoDeLancamento);
        await userEvent.type(inputNome, 'Interestelar')
        await userEvent.type(inputAnoDeLancamento, '2014')
        await userEvent.click(botaoAdicionar)

        //Busca pela mensagem de erro após a tentativa de inserção duplicada
        const mensagemDeErro = getByText('Não é possível adicionar, pois o filme já está na lista!')

       //ASSERT - cria hipóteses para serem testadas

       //Verifica se a mensagem está na tela
        expect(mensagemDeErro).toBeInTheDocument()
    })
})

O teste acima como previsto deve falhar!

Linha de comando. Três arquivos são testados com quatro testes sendo executados, três são aprovados e um é reprovado.

Para o teste funcionar, devemos criar uma variável com useState para alterar o estado da mensagem de erro.

 const [erroFilmeDuplicado, setErroFilmeDuplicado] = useState<string>('');

Adicionamos uma condição para que a mensagem de erro seja exibida se tiver dois filmes com o mesmo nome.

    if (filmes.some(f => f.nome === filme.nome)) {
      setErroFilmeDuplicado('Não é possível adicionar, pois o filme já está na lista!')
    }

Renderizamos a mensagem de erro na tela.

{erroFilmeDuplicado&&<p>{erroFilmeDuplicado}</p>}
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro, o arquivo App.tsx está aberto com a variável que altera o estado da mensagem do erro, a condição para verificar se há filmes com nomes duplicados e a renderização da mensagem na tela em destaque.

Com essas mudanças o teste deve passar!

Linha de comando. Três arquivos são testados com quatro testes sendo aprovados.

Teste para verificar se a mensagem desaparece após determinado tempo

A mensagem de erro está sendo exibida, mas queremos que ela desapareça após um tempo determinado, para isso podemos executar o seguinte teste em "App.test.tsx:

      test('verifica se a mensagem de erro some após um tempo ao adicionar um filme duplicado', () => {

        //Simula um temporizador
        jest.useFakeTimers()

        const {getByPlaceholderText, getByRole, queryByRole} = render(<App/>)

        //Busca os elementos pelo placeholder e pela função
        const inputNome = getByPlaceholderText('Insira o nome do filme')
        const inputAnoDeLancamento = getByPlaceholderText('Digite o ano de lançamento')
        const botaoAdicionar = getByRole('button')

        //Diferente do userEvent ele simula interações do usuário de forma síncrona
        fireEvent.change(inputNome, {target:{value:'Interestelar'}})
        fireEvent.change(inputAnoDeLancamento, {target:{value:'2014'}})
        fireEvent.click(botaoAdicionar)
        fireEvent.change(inputNome, {target:{value:'Interestelar'}})
        fireEvent.change(inputAnoDeLancamento, {target:{value:'2014'}})
        fireEvent.click(botaoAdicionar)

        //Busca pela mensagem de erro pela função alert e espera que ela esteja na página
        let mensagemDeErro = queryByRole('alert')
        expect(mensagemDeErro).toBeInTheDocument()

        //Executa todos os temporizadores
        act(() => {
            jest.runAllTimers()
        });

        //Busca novamente as mensagens de erro e espera que ela não esteja mais na página
        mensagemDeErro = queryByRole('alert')
        expect(mensagemDeErro).not.toBeInTheDocument()
    })

O teste inicialmente falha, pois espera que a mensagem de erro não esteja mais na página após um tempo.

Linha de comando. Três arquivos são testados com cinco testes sendo executados, quatro são aprovados e um é reprovado.

Para o teste ser aprovado, precisamos usar o setTimeout para definir um tempo para a mensagem aparecer na tela.

      setTimeout(() => setErroFilmeDuplicado(''), 3000);
      return

Esse código deve ser adicionado dentro da função adicionarFilme() no arquivo "App.tsx".

Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro, o arquivo App.tsx está aberto com a adição do setTimeout na função adicionarFilme.

Também precisamos adicionar uma propriedade de role na tag <p>que recebe a mensagem de erro com a função alert, pois vamos buscar por esse elemento no teste.

<p role='alert'>{erroFilmeDuplicado}</p>
Tela do VS Code. Na lateral esquerda a aba Explorer está aberta com os arquivos e pastas do projeto. No centro, o arquivo App.tsx está aberto com a adição da propriedade role na tag que recebe a mensagem de erro.

Com isso o último teste é executado com sucesso!

Linha de comando. Três arquivos são testados com cinco testes sendo aprovados.

Com todos os testes aprovados, é só utilizar o comando npm run dev para ver o resultado.

Gif com a aplicação rodando no navegador Chrome. É possível identificar no início do vídeo que o botão está desabilitado e fica disponível para clique ao adicionar elementos nos campos de input. Também há uma mensagem de erro que aparece ao tentar adicionar filmes repetidos e desaparece após três segundos.

Agora use sua criatividade para personalizar o projeto aplicando estilos aos componentes ou criando suas próprias listas.

Conclusão

Foi incrível compartilhar com você essa jornada pelo maravilhoso universo dos testes. Juntos(as), desvendamos a importância de testar as funcionalidades que queremos desenvolver, para garantir a qualidade do nosso código.

Durante nosso percurso, mergulhamos no estudo de duas ferramentas indispensáveis para a elaboração de testes eficazes: o React Testing Library e o Jest.

Aprendemos não apenas a configurá-las em um ambiente de desenvolvimento React com TypeScript utilizando o Vite, mas também a maximizar o seu potencial em testes eficientes.

Adotamos a metodologia do Desenvolvimento Orientado por Testes (TDD), uma prática amplamente valorizada no mundo do desenvolvimento de software, que prioriza a escrita de testes antes mesmo do código que será testado.

Esta abordagem nos permitiu compreender profundamente o ciclo de desenvolvimento sob a ótica do TDD, enfatizando a importância de uma base sólida de testes para o sucesso do projeto.

Por fim, colocamos em prática esses conhecimentos no desenvolvimento de um projeto incrível, que nos permitiu entender o impacto direto dessas práticas na qualidade e na confiabilidade das aplicações.

Além disso, convido você a conhecer mais profundamente nossos conteúdos sobre o tema:

Referências

  • Site do npm (inglês, gratuito, documentação)

    Site que oferece a documentação do npm, ferramenta popular e bastante utilizada no desenvolvimento de muitas empresas.

  • Vite (inglês, gratuito, documentação)

    Documentação do Vite com informações de instalação para iniciar projetos utilizando bibliotecas e frameworks do mundo Front-End.

  • Utilizando o Vite para criar uma aplicação React com TypeScript (português, gratuito, artigo)

    Artigo da Alura que mostra como criar uma aplicação React com TypeScript utilizando a ferramenta Vite.

  • React Testing Library (inglês, gratuito, documentação)

    Documentação do React Testing Library que traz informações de intalação, funções e propriedades para relizar testes em diferentes frameworks e bibliotecas Front-end.

  • Jest (português, gratuito, documentação)

    Documentação do Jest com informações de instalação e configuração deste ambiente de execução de testes.

  • Dicas para desenvolver testes unitários e de integração no Front-end (português, gratuito, artigo)

    Artigo da Alura com dicas para desenvolver e utilizar testes unitários e de integração no Front-end.

  • Tipos de testes: quais os principais e por que utilizá-los? (português, gratuito, artigo)

    Artigo da Alura para conhecer os tipos de testes mais utilizados atualmente.

RODRIGO SILVA HARDER
RODRIGO SILVA HARDER

Graduado em Design Gráfico, Técnico em Química e Licenciatura em química, Rodrigo é apaixonado por ensinar e aprender e busca se aventurar em diferentes linguagens de programação. Faço parte da escola semente e atuo como monitor no time de Fórum Ops.

Veja outros artigos sobre Front-end