React e Context API: testes de unidade

React e Context API: testes de unidade
Vinicios Neves
Vinicios Neves

Compartilhe

Salve, salve! Tudo bem com você?

Hoje estou aqui pra falar sobre a Context API e como podemos criar testes unitários, para garantir que tudo funcione corretamente em uma aplicação React. Para ilustrar, vamos usar como exemplo uma lista de tarefas (ToDo list).

Antes de começarmos, é importante lembrar que a Context API é uma opção mais avançada do que o padrão de passagem de props em React, então é recomendado só usá-la se você precisar compartilhar dados em uma escala mais ampla ou se passar props manualmente estiver ficando muito complexo. Normalmente precisamos pensar em soluções desse tipo quando enfrentamos o já conhecido e famoso prop drilling.

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

Primeiro, vamos criar o nosso Provider de contexto. O Provider irá fornecer os dados para os componentes que estiverem "subscritos" a ele. Alguma coisa nessa linha:

import React, { useState } from "react";

export const TodoContext = React.createContext();

export function TodoProvider(props) {
  const [todos, setTodos] = useState([]);

  function addTodo(todo) {
    setTodos([...todos, todo]);
  }

  function deleteTodo(index) {
    setTodos(todos.filter((todo, i) => i !== index));
  }

  return (
    <TodoContext.Provider
      value={{
        todos,
        addTodo,
        deleteTodo,
      }}
    >
      {props.children}
    </TodoContext.Provider>
  );
}

No exemplo acima, criamos um Provider que armazena uma lista de tarefas (todos) e duas funções para adicionar e remover tarefas da lista.

Agora que temos o nosso Provider, vamos criar os nossos testes unitários. Para isso, vamos usar o pacote "react-testing-library".

O primeiro teste será para verificar se a função "addTodo" está adicionando corretamente uma tarefa à lista. Tipo assim:

import { render, fireEvent, wait } from "react-testing-library";
import { TodoProvider, TodoContext } from "./TodoProvider";

test("adiciona uma tarefa à lista", async () => {
  const { getByTestId, getByText } = render(
    <TodoProvider>
      <TodoContext.Consumer>
        {({ addTodo }) => (
          <button data-testid="add-button" onClick={() => addTodo("nova tarefa")}>
            Adicionar tarefa
          </button>
        )}
      </TodoContext.Consumer>
    </TodoProvider>
  );
  fireEvent.click(getByTestId("add-button"));
  await wait(() => expect(getByText("nova tarefa")).toBeInTheDocument());
});

No exemplo acima, estamos renderizando o Provider e o Consumer dentro de um wrapper e, em seguida, clicando no botão "Adicionar tarefa". Depois, estamos usando a função "wait" do "react-testing-library" para garantir que o elemento com o texto "nova tarefa" esteja sendo exibido antes de verificarmos se ele está no documento.

O segundo teste será para verificar se a função "deleteTodo" está removendo corretamente uma tarefa da lista. Aqui está como podemos fazer isso:

import { render, fireEvent, wait } from "react-testing-library";
import { TodoProvider, TodoContext } from "./TodoProvider";

test("remove uma tarefa da lista", async () => {
  const { getByTestId, queryByText } = render(
    <TodoProvider>
      <TodoContext.Consumer>
        {({ todos, deleteTodo }) =>
          todos.map((todo, index) => (
            <div key={todo}>
              <span>{todo}</span>
              <button data-testid="delete-button" onClick={() => deleteTodo(index)}>
                Remover
              </button>
            </div>
          ))
        }
      </TodoContext.Consumer>
    </TodoProvider>
  );
  fireEvent.click(getByTestId("delete-button"));
  await wait(() => expect(queryByText("tarefa 1")).toBeNull());
});

No exemplo acima, estamos renderizando o Provider e o Consumer dentro de um wrapper e, em seguida, clicando no botão "Remover". Depois, estamos usando a função "wait" do "react-testing-library" para garantir que o elemento com o texto "tarefa 1" não esteja sendo exibido antes de verificarmos se ele é nulo.

Agora que já vimos como criar testes unitários para a Context API, vamos falar sobre os benefícios de fazer testes unitários em uma aplicação.

Testes unitários nos ajudam a garantir que o código da nossa aplicação esteja funcionando corretamente, mesmo quando fazemos alterações futuras. Isso nos permite ter mais confiança no código que estamos escrevendo e nos dá a segurança de saber que as alterações que estamos fazendo não estão quebrando o funcionamento de outras partes da aplicação.

Além disso, testes unitários nos ajudam a escrever código mais limpo e mais fácil de manter. Isso porque, ao escrever testes, somos forçados a pensar em como dividir nosso código em partes menores e mais fáceis de testar, o que nos ajuda a evitar a criação de funções muito longas e complexas.

O pacote "react-testing-library" é uma ótima opção para fazer testes em aplicações React, pois ele nos permite testar o comportamento do usuário, como clicar em botões e preencher formulários, de maneira mais fácil e intuitiva. Além disso, ele nos ajuda a escrever testes mais robustos, pois não se prende a detalhes de implementação, o que nos permite alterar o código sem precisar alterar os testes.

Quer saber mais sobre como a Context API funciona? Ou é no mundo dos testes que você quer mergulhar? Aqui na Alura temos algumas opções, dá uma olhada:

Espero que este post tenha ajudado a entender como usar e testar a Context API em uma aplicação React. Não esqueça de sempre testar o seu código para garantir que ele esteja funcionando corretamente e para torná-lo mais fácil de manter no futuro.

Até a próxima 🖖!

Vinicios Neves
Vinicios Neves

Vinicios Neves, Tech Lead e Educador, mistura código e didática há mais de uma década. Especialista em TypeScript, lidera equipes full-stack em Lisboa e inspira futuros desenvolvedores na FIAP e Alura. Com um pé no código e outro no ensino, ele prova que a verdadeira engenharia de software vai além das linhas de código. Além de, claro, ser senior em falar que depende.

Veja outros artigos sobre Front-end