Como escrever testes unitários usando React Recoil
Abr 03, 2024
Foto de Ilo Frey no Pexels.
O React Recoil é uma biblioteca de gerenciamento de estado que fornece uma maneira de compartilhar estados entre componentes React. É uma ferramenta desenvolvido e mantida pela equipe do Facebook.
O Recoil tem como principios a simplicidade e a escalabilidade. Os átomos são a unidade básica de estado no Recoil. Eles são gerenciados por um estado global e podem ser lidos e escritos por qualquer componente React. Os seletores são funções puras que aceitam átomos como argumentos e retornam valores derivados.
É muito comum utilizar seletores para acessar o estado global e derivar novos valores mais complexos a partir dos átomos. E é justamente dessas derivações que é comum surgirem bugs 😩. Por isso, é muito importante escrever testes unitários para garantir que os seletores estão escritos de acordo com os requisitos.
Neste artigo, vamos aprender como escrever testes unitários para átomos e seletores do React Recoil.
Show me the code
Para o nosso exemplo prático vamos considerar uma aplicação de controle de placar de um jogo de futebol ⚽️. Vamos criar um átomo para armazenar o placar e um seletor para calcular o total de goals do jogo.
Primeiro, vamos criar o átomo para armazenar o placar do jogo. Sua interface contém um campo para goals do time da casa e um campo para goals do time visitante:
// scoreboard-state.ts
import { atom, selector } from "recoil";
interface ScoreBoard {
home: number;
away: number;
}
export const scoreBoardState = atom<ScoreBoard>({
key: "score-board",
default: { home: 0, away: 0 },
});
Agora, vamos criar o seletor para calcular o total de goals do jogo. O resultado é simplesmente a soma dos goals do time da casa e do time visitante:
// scoreboard-state.ts
// (...)
export const totalGoalsSelector = selector<number>({
key: "total-goals",
get: ({ get }) => {
const { home, away } = get(scoreBoardState);
return home + away;
},
});
Agora, vamos escrever os testes unitários para o átomo e o seletor. Para isso, vamos utilizar a biblioteca Jest.
Primeiro, vamos escrever o teste para o átomo. O teste deve garantir que o átomo foi criado corretamente e que o valor inicial é zero para ambos os times:
// scoreboard-state.spec.ts
import { snapshot_UNSTABLE } from "recoil";
import { scoreBoardState, totalGoalsSelector } from "./scoreboard-state";
describe("given a new scoreboard", () => {
it("home and away teams should have no goals yet", () => {
// Given
const snapshot = snapshot_UNSTABLE();
// When
const scoreBoard = snapshot.getLoadable(scoreBoardState).valueOrThrow();
// Then
const expectedScoreBoard = { home: 0, away: 0 };
expect(scoreBoard).toStrictEqual(expectedScoreBoard);
});
});
Seguindo a documentação do Recoil , podemos usar snapshot_UNSTABLE para ler o snapshot do estado atual do Recoil. Em seguida, usamos snapshot.getLoadable(scoreBoardState).valueOrThrow(); para obter o valor do átomo (que até então é o valor default porque não houve mutação de estados). Por fim, comparamos o valor do átomo com o valor esperado.
Agora, vamos escrever o teste para o seletor. O teste deve garantir que o seletor foi criado corretamente e que o total de goals é zero:
// scoreboard-state.spec.ts
describe("given a new scoreboard", () => {
it("total goals should be 0", () => {
// Given
const snapshot = snapshot_UNSTABLE();
// When
const goals = snapshot.getLoadable(totalGoalsSelector).valueOrThrow();
// Then
const expectedGoals = 0;
expect(goals).toBe(expectedGoals);
});
});
Para este caso, bem semelhante ao exemplo anterior, porém passamos o seletor no método snapshot.getLoadable e comparamos o valor retornado com o valor esperado. Bem simples, não? 😄
Para um caso de teste mais complexo, podemos simular uma mutação de estado e testar se o seletor está retornando o valor correto. Por exemplo, podemos testar se o seletor está somando corretamente os goals dos times:
// scoreboard-state.spec.ts
describe("given a scoreboard with home: 3, away: 2", () => {
it("total goals should be 5", () => {
// Given
const inProgressScoreBoard = { home: 3, away: 2 };
const snapshot = snapshot_UNSTABLE(({ set }) =>
set(scoreBoardState, inProgressScoreBoard)
);
// When
const goals = snapshot.getLoadable(totalGoalsSelector).valueOrThrow();
// Then
const expectedGoals = 5;
expect(goals).toBe(expectedGoals);
});
});
Para simular uma mutação de estado, passamos uma função para snapshot_UNSTABLE que recebe um argumento set e chama set(scoreBoardState, inProgressScoreBoard) para definir o valor do átomo. Em seguida, obtemos o valor do seletor e comparamos com o valor esperado.
E é isso! Agora você sabe como escrever testes unitários para átomos e seletores do React Recoil. Espero que este artigo tenha sido útil para você e que você evolua a qualidade de seu código escrevendo mais testes! 🚀