Como testar aplicações com React Testing Library e Jest
Tags: react, tutorial, jest, braziliandevs
Published: 2023-01-23 16:49:06

Como desenvolvedores de software, é fundamental reduzir as chances de falha de nosso programa executando testes com o usuário final em mente e testando sua aplicação da mesma forma que ele o usaria.

É impraticável esperar que os componentes de uma aplicação funcionem de forma confiável o tempo todo. Quando ocorre uma modificação ou ajuste em um pedaço de código existente, as coisas podem ou não quebrar, e é melhor presumir o pior. Além disso, se tivermos testes automatizados desenvolvidos para vários componentes em nossa aplicação, podemos perceber imediatamente quando uma alteração quebra algo em nossa aplicação - antes de liberarmos nosso código para produção.

> _Teste é o processo de avaliar um sistema ou seus componentes com a intenção de descobrir se ele satisfaz os requisitos especificados ou não. Em palavras simples, testar é executar um sistema para identificar quaisquer lacunas, erros ou requisitos ausentes contrários aos requisitos reais._

O que abordaremos nesse artigo:

- Resumo rápido
- Testes automatizados
- Por que você deve escrever testes?
- Tipos de testes automatizados
- Desenvolvimento Orientado a Testes (TDD)
- React Testing Library (RTL)
- Compreendendo um bloco de testes
- Mini projeto
- Conclusão

## Resumo rápido

Esse artigo explica o que é teste automatizado, por que escrever testes para aplicações é importante, as diferentes formas de teste automatizado, **Test Driven Development (TDD)**, **React Testing Library (RTL)** e construiremos um miniprojeto com uma abordagem TDD.

Esse artigo é adequado para aqueles que nunca escreveram uma única linha de código de teste antes; Embora para obter o máximo desta parte, você deve estar familiarizado com como configurar e navegar em um novo projeto React, bem como interagir com um gerenciador de pacotes. Também é necessário estar familiarizado com o **axios**.

## Testes Automatizados

Testes automatizados são trechos de código que executam seu código e verificam se a saída dessa execução de código atende a uma determinada expectativa. Se você escrever testes automatizados para sua aplicação, poderá detectar problemas rapidamente quando começar a trabalhar em seu código e um ou mais testes falharem.

O teste manual, por outro lado, é o que fazemos quando clicamos em nossa aplicação no navegador, avaliando diferentes recursos.

## Por que você deve escrever testes?

- AJuda a detectar bugs antecipadamente e permite refatorar seu código.
- Garante que sua aplicação satisfaça as especificações do projeto.
- Reduz o tempo de teste manual (quando um usuário real usa nossa aplicação para testar sua funcionalidade).
- Envio de código eficiente e de qualidade para a produção.
- Melhorar a manutenibilidade do código.

Muitas vezes, acredita-se que o teste seja um processo demorado; `escrevendo testes === mais código`. Por outro lado, todo desenvolvedor deve estar familiarizado com os fundamentos do teste. Além disso, quem entende seu código melhor do que você 🙃?

Escrever testes automatizados é metade do esforço do desenvolvedor para resolver o problema. Saber como testar seu código é um ótimo método para avançar como desenvolvedor, pois permite que você descubra coisas novas sobre seu código e aprimore suas habilidades de debugar seu código. 🚀.

---

## Tipos de testes automatizados

**1. Testes unitários**

Os testes unitários são a forma mais simples de testes automatizados, em que funções, métodos, componentes ou unidades individuais de uma aplicação são testados isoladamente para garantir que funcionem corretamente.

Por exemplo, em uma aplicação de tarefas, você pode escrever um teste de unidade para o componente de input, para confirmar que o usuário pode digitar nele e alterar seu valor.

**2. Teste de integração**

O teste de integração é um tipo de teste de software no qual várias unidades que trabalham juntas são testadas como um todo. Essa forma de teste é usada para garantir que duas ou mais unidades/módulos possam se comunicar efetivamente entre si.

Por exemplo , em uma aplicação de tarefas, onde existem três componentes principais: um elemento input onde uma nova tarefa é digitada, um botão para adicionar, quando clicado, adiciona a nova tarefa à lista de tarefas e um elemento div que renderiza a lista de tarefas. Como esses três componentes são agrupados logicamente, um teste de integração pode ser escrito para garantir que eles funcionem bem juntos.

**3. Teste de ponta a ponta (E2E)**

O teste de ponta a ponta é uma técnica de teste de software que exige que testemos toda a aplicação do início ao fim em um ambiente de produção. É executado em um ambiente simulado que emula o comportamento de um usuário. Ferramentas como Cypress, Selenium e Puppeteer podem ser usadas para testes E2E.

**4. Teste de aceitação**

O teste de aceitação é realizado pelo cliente/proprietário da empresa para garantir que a aplicação atenda a todos os requisitos.

**5. Teste de fumaça**

O teste de fumaça é usado para confirmar que as funcionalidades fundamentais do sistema em teste estão funcionando corretamente e em alto nível.

Outros testes de software não funcionais incluem testes de segurança, desempenho, usabilidade e compatibilidade.

---

## Desenvolvimento Orientado a Testes (TDD)

TDD é uma estratégia para descrever o comportamento do seu código antes de ser implementado. Tem o slogan 'Red-Green-Refactor'.

**Vermelho** - Um caso de teste automatizado para um recurso específico que (inicialmente) falha é gravado.

**Verde** - Escreva o código necessário para passar no teste.

**Refatorar** - refatore ou otimize seu código.

Além do TDD puro, existem outras opções a serem exploradas, principalmente no desenvolvimento front-end.

## React Testing Library (RTL)

o React Testing Library, é uma solução de teste leve para componentes React. Essa biblioteca é baseada no **DOM Testing Library** e é um subconjunto da família de pacotes `@testing-library`. Seu princípio de orientação é:

> _Quanto mais seus testes se assemelharem à forma como seu software é usado, mais confiança eles podem lhe dar._

Isso implica que o RTL nos permite testar o comportamento de nossos componentes React da perspectiva dos usuários de nossa aplicação, em vez dos detalhes de implementação do componente. O uso de RTL torna suas aplicações mais acessíveis e ajuda você a aproximar seus testes de como um usuário usaria seus componentes, dando a você mais confiança de que sua aplicação funcionará quando um usuário real o usar.

Frameworks de teste populares dentro da comunidade React são **Enzyme** e **Jest**.

RTL é uma biblioteca e não é específica para uma estrutura de teste, embora Jest seja a escolha recomendada, de acordo com a documentação oficial da RTL. Como resultado, iremos combiná-lo com o Jest nesse artigo.

## Compreendendo um bloco de teste

Não se preocupe com a configuração porque todo novo projeto React inicializado com `create-react-app`, RTL e Jest já estão configurados. Se você estiver usando a configuração personalizada do React, use o seguinte comando para instalá-la:

```
npm install --save-dev @testing-library/react
```

Inicie uma nova aplicação React com o bloco de código abaixo:

```
npx create-react-app my-app
```

Depois que um projeto React é inicializado com `create-react-app`, um teste de amostra para o arquivo `App.js` é pré-configurado em um arquivo App.test.js:

![Imagem de código](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcxcfogxkn2ja6n0vyla.png)

Vamos detalhar a estrutura desse teste:

```jsx
// React testing methods are imported
import { render, screen } from '@testing-library/react'; 

import App from './App'; // Component to be tested

// Test block for the component
test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

```

```jsx
// Os testes são escritos no método test/it fornecido pelo Jest
// Um método de teste leva em dois parâmetros:
// Uma descrição do teste e uma função com lógica para testar

test("", () => {});
// OR
it("", () => {});

```

Não importa se você usa o método `test` ou `it`, no entanto, prefiro o método test.

```jsx
test('renders learn react link', () => {
  render(<App />); // renders the component into the DOM 
  const linkElement = screen.getByText(/learn react/i); // gets element that has the text 'learn react'
  expect(linkElement).toBeInTheDocument(); // asserts that the element found is rendered 
});

```

- O componente a ser testado é renderizado no DOM.
- Em seguida, o DOM é consultado pelo elemento `link` com o testo "Aprenda React" usando o objeto `screen` importado do RTL, que possui várias consultas, no nosso caso a consulta `getByText` é usada para selecionar o elemento `link`.

> _Lembre-se de como getElementById de outros métodos de seleção de DOM Javascript funcionam? Sim!, o RTL possui consultas que podem ser usadas para selecionar elementos do componente a ser testado. Confira uma lista de todas as [consultas](https://testing-library.com/docs/react-testing-library/cheatsheet/#queries)._

Na última linha de código, usando uma asserção fornecida pelo Jest, testamos se o elemento link é renderizado no DOM.

```jsx
expect(linkElement).toBeInTheDocument();
```

Finalmente, para executar nosso teste, execute `npm run test` ou `yarn test` e pressione `a`. Todos os testes no projeto serão executados no modo de observação. Jest executará arquivos que terminam com `.spec.js` ou `.test.js` automaticamente.


![Imagem de testes passando](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jslgzc78sgiyjayf2yiu.png)

Como você notou, nosso teste passou, agora vamos fazê-lo falhar 😈. No arquivo `App.js`, altere o texto do elemento `a` para 'Hello World'.

Você deve ver o teste falhar com essa mensagem de erro:

> _TestingLibraryElementError: Unable to find an element with the text: /learn react/i. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible._


![Imagem de código falhando](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drlxwiaczjqmr7p3ezxl.png)

Isso ocorre porque, no DOM, não há elemento com o texto 'Aprender React'. Se você adicionar um novo elemento com o texto 'Aprender React', o teste passará novamente. Adivinha? você implementou seu primeiro teste unitário!

À medida que progredirmos, criaremos um mini-projeto de Solicitação de amizade, mas, primeiro, gostaria de destacar os vários métodos que a RTL forneceu para selecionarmos elementos do DOM, bem como alguns métodos de asserção do Jest.

## Query Selectors

No exemplo inicial, utilizamos o método `getByText` do RTL, que é um dos métodos de consulta disponíveis. Depois que um elemento é selecionado, podemos fazer várias afirmações ou imitar as interações do usuário para interagir com ele.

Se você ainda não adivinhou, o método `getByText` seleciona um elemento com base no texto dentro do elemento, independentemente de ser uma `div`, `h1`, `p`, ou um `h4` contanto que encontre um elemento que tenha o texto fornecido, ele seleciona esse elemento.

```jsx
getByText("learn react")

```

Para selecionar elementos DOM, o RTL inclui uma variedade de métodos de consulta. Cada um dos métodos de consulta se enquadra em um dos seguintes grupos :

- Elementos únicos: `getBy...`, `findBy...`, `queryBy...`
- Múltiplos elementos: `getAllBy...`, `findAllBy...`, `queryAllBy...`


![Tabela de query selectors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgmb6gc63c0xiap8ukak.png)

A tabela acima é da documentação oficial da RTL e mostra uma visão geral do que as várias categorias retornam.

## Jest matchers

Ao desenvolver testes, geralmente é necessário confirmar se os valores atendem a requisitos específicos. O `expect` inclui uma variedade de "matchers" que permitem validar coisas diferentes. Mais correspondências personalizadas estão incluídas em um pacote separado chamado `jest-dom` por RTL.

Dê uma olhada no arquivo `package.json`, você notará que `jest-dom` já está instalado como uma dependência.

```jsx
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",

```

Em nosso teste inicial, utilizamos o matcher `toBeInTheDocument` para determinar se o `linkElement` estava ou não no DOM.

```jsx
expect(linkElement).toBeInTheDocument();

```

Alguns exemplos:

```jsx
// toBe
test("Test that name is John", () => {
  const name = "John";
  expect(name).toBe("John");
});

// toEqual
test("Two plus Two equals Four", () => {
  const result = 2 + 2;
  expect(result).toEqual(4);
});

//toContain
test("Vowels", () => {
  const vowels = ["a", "e", "i", "o", "u"];
  expect(vowels).toContain("e");
  //  .not
  expect(vowels).not.toContain("z");
});

```

Saiba mais sobre os matchers do Jest clicando [aqui](https://jestjs.io/docs/expect). Correspondências `jest-dom` personalizadas podem ser encontradas [aqui](https://github.com/testing-library/jest-dom).

## Mini projeto

Para esta seção, criaríamos um aplicativo de solicitação de amizade simples, os dados do usuário serão extraídos desse [link](randomuser.me/api/?results=5)

Vamos descrever as especificações da nossa aplicação:

- Enquanto espera por uma resposta da API, exiba um indicador de carregamento escrito Loading....
- Exibir solicitações de amizade na tela assim que a chamada da API retornar com um status de 200.
- Os usuários devem poder recusar solicitações de amizade.
- Se não houver mais solicitações, um botão de atualização ao clicar, chama a API para buscar novos dados.

Seguindo uma abordagem TDD, escreveríamos o teste antes de construir nosso componente. Crie um novo arquivo `src/components/Requests/Requests.test.js`.

```jsx
//   src/components/Requests/Requests.test.js 

import axios from "axios";
import {
  render,
  screen,
  waitForElementToBeRemoved,
  fireEvent
} from "@testing-library/react";
import Requests from "./Requests";

describe("Requests page", () => {
 test("Renders Requests component",  async () => {
    render(<Requests />);

    await Promise.all([
      waitForElementToBeRemoved(() => screen.queryByText(/Loading.../i)),
    ]);
    expect(axios.get).toHaveBeenCalledTimes(1);

  });
});

```

Nosso bloco de teste está incluído em uma função `describe`; isso é usado para testes de escopo.

Primeiro, o componente `<Requests />` é renderizado; tenha em mente que o objetivo é desenvolver testes que imitem como o software é usado. Antes que os dados sejam buscados, o usuário fica sabendo que está carregando, por causa do indicador de carregamento que aparece `Loading...` na tela. E depois que a solicitação da API retorna com status 200, o indicador de carregamento não aparece mais na tela.

Portanto, utilizamos o método assíncrono `waitForElementToBeRemove` denvolvido em um método `Promise.all` para esperar que Loading... desapareça da tela. 
 Em seguida, verificamos se a chamada `axios.get` foi executada apenas uma vez.

## Mockando com Jest

Jest nos permite mockar/imitar o comportamento de funções em nossa aplicação; `jest.fn()` é usado para criar uma função simulada.

Em vez de solicitar dados de nossa API no arquivo de teste, criaremos uma função simulada que retorna dados fictícios semelhantes aos dados retornados da API.

Isso é importante porque estamos testando nossa aplicação React e, se nosso teste enviar uma solicitação para a API real, também estamos testando a API; se a API falhar, nosso teste falhará. Como resultado, diminuindo a confiança em nossa aplicação.

Crie um novo arquivo `src/__mocks__/axios.js`. Como estamos simulando `axios`, o nome do arquivo deve ser `axios.js`, e os arquivos fictícios são armazenados na pasta `__mocks__`, que é colocada na pasta `src`.

```jsx
// src/__mocks__/axios.js
import { mockData } from "../mockData";

const customAxios = {
    get: jest.fn().mockResolvedValue(mockData),
  };

export default customAxios

```

Importamos `mockData` e o incluímos para ser retornado quando fizermos a chamada da API em nosso teste. A estrutura de seus dados simulados deve ser semelhante à estrutura dos dados retornados de sua API.

```jsx
// src/mockData.js

export const mockData = {
  data: {
    results: [
      {
        name: { first: "Alison", last: "Carlson" },
        email: "alison.carlson@example.com",
        login: {
          uuid: "56f8e0af-50bb-483b-ba30",
        },
        picture: {
          medium: "https://randomuser.me/api/portraits/med/women/25.jpg",
        },
      },
      {
        name: { first: "Frederik", last: "Larsen" },
        email: "frederik.larsen@example.com",
        login: {
          uuid: "162b6088-870a-4b12-bcbf",
        },
        picture: {
          medium: "https://randomuser.me/api/portraits/med/men/27.jpg",
        },
      },
    ],
  },
};

// Single Mock Data
export const singleMockData = {
  name: { first: "Alison", last: "Carlson" },
  email: "alison.carlson@example.com",
  login: {
    uuid: "56f8e0af-50bb-483b-ba30",
  },
  picture: {
    medium: "https://randomuser.me/api/portraits/med/women/25.jpg",
  },
};

```

Execute o teste com `npm run test` ou `yarn test`.

Quando executamos nosso teste, o Jest identifica a pasta `__mocks__` e utiliza as personalizações de `axios` que definimos, em vez do axios da pasta `node_modules`. As chamadas do axios retornam uma promise que resolve os dados que queremos, então seguimos o exemplo e retornamos uma promise contendo os dados que queremos (dados fictícios no arquivo `src/mockData.js`).

Neste ponto, nosso teste está falhando porque não construímos nossos componentes, então vá para s`rc/components/Requests/Requests.js` e cole o bloco de código abaixo:

```jsx
// src/components/Requests/Requests.js

import React, { useState, useEffect } from "react";
import Request from "../Request/Request";
import axios from "axios";

const Requests = () => {
  const [loading, setLoading] = useState(true);
  const [friendRequests, setFriendRequests] = useState([]);

  useEffect(() => {
    fetchFriendRequests();
  }, []);

  const fetchFriendRequests = async () => {
    try {
      const { data } = await axios.get("https://randomuser.me/api/?results=5");
      setFriendRequests(data.results);
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

  if (loading) {
    return (
      <div className="loading">
        <h1>loading...</h1>
      </div>
    );
  }

  return (
    <section>
      <div className="title">
        <h2>friend requests</h2>
        <div className="underline"></div>
      </div>
      <div>
        {friendRequests.map((request, index) => {
          const { login } = request;
          return <Request index={index} key={login.uuid} {...request} />;
        })}
      </div>
    </section>
  );
};

export default Requests;

```

Criamos uma função `fetchFriendRequests` que busca os dados da API e chamamos a função dentro de um bloco `useEffect`. Quando a API retorna, o estado é atualizado e o carregamento é definido como false.

Como não criamos o componente `Request.js`, nosso teste ainda falhará, então navegue até `src/components/Request/Request.js` e cole o bloco de código abaixo:

```jsx
// src/components/Request/Request.js

import React from "react";

const Request = ({ name, email, login, picture, index, id }) => {
  return (
    <div className="single-request" >
      <div className="single-request-main">
        <div>
          <img src={picture.medium} alt={name.first} />
        </div>
        <div>
          <p>
            <strong>Name</strong>: {name.first + " " + name.last}{" "}
          </p>
          <p>
            <strong>Username</strong>: {login.username}{" "}
          </p>
          <p>
            <strong>Email</strong>: {email}{" "}
          </p>
        </div>
      </div>
    </div>
  );
};

export default Request;

```

O teste passou!

![Imagem dos testes passando](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qztfj4q4bornrxn6yisk.png)

E nosso projeto também está ficando bom em localhost:3000 😎


![Imagem do projeto](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z6gw9zgouxdqyela2usr.png)

Vamos adicionar um novo teste em nosso bloco `describe` para afirmar que o primeiro índice dos dados está no DOM:

```jsx
describe("Requests page", () => {

  test("Renders Requests component", async () => {
    render(<Requests />);

    await Promise.all([
      waitForElementToBeRemoved(() => screen.queryByText(/Loading.../i)),
    ]);
    expect(axios.get).toHaveBeenCalledTimes(1);
  });

  // new test block
  test("finds first index of Request in the DOM", async () => {
    render(<Requests />);

    const firstRequest = await screen.findByTestId(/request-0/i);

    expect(firstRequest).toBeInTheDocument();
  })
});

```

Observe que o bloco `test` recebeu uma função assíncrona? isso é necessário para que possamos usar `await` dentro da função.

O componente `<Requests />` é renderizado, em seguida, encontramos o elemento `firstRequest` por seu `test-id`. Nosso teste falhará porque nenhum elemento tem `request-0` como `test-id`.

### O que é um test-id?

Test-id é um atributo exclusivo que você pode atribuir a um elemento. Por exemplo:

```
<div data-testId="unique-attribute">Hello World</div>

```

Vá para `src/components/Request/Request.js` e dê ao div pai um `test-id` exclusivo.

```jsx
//   src/components/Request/Request.js

<div className="single-request" data-testid={`request-${index}`}>

```

Vale a pena notar que usamos especificamente `findByTestId` e isso ocorre porque, ao contrário de `getBy...` e `queryBy...`, `findBy...` retorna uma promise que resolve quando um elemento é encontrado que corresponda à consulta fornecida.

O que significa que se tivéssemos usado `getByTestId` ou `queryByTestId`, nosso teste teria falhado:


![Imagem de código](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8gslt7tc18co8pb4zxo0.png)

Mas como não o fizemos, o teste passou!

### Botão Recusar

Em seguida, adicionamos um botão que, ao ser clicado, recusa um pedido de amizade e o remove da tela. Crie um novo arquivo de teste `src/components/Request/Request.test.js` e cole o código abaixo:

```jsx
// src/components/Request/Request.test.js

import { render, screen, fireEvent } from "@testing-library/react";
import Request from "./Request";
import { singleMockData } from "../../mockData";

const mockedFn = jest.fn();

describe("Single Request component", () => {
  test("decline button to unmount component", () => {
    const { unmount } = render(
      <Request
        index={0}
        key={0}
        {...singleMockData}
        removefriendRequest={mockedFn}
      />
    );

    const declineButton = screen.getByText(/decline/i);
    fireEvent.click(declineButton);
    unmount();

  });
});

```

Começamos renderizando o componente, mas como precisaremos da função `unmount` posteriormente, desestruturamos a partir do método render. `<Request />` leva um monte de props, então nós fornecemos as props necessárias; para a propriedade `removefriendRequest`, passamos uma função fictícia que retorna `undefined`.

Por fim, localizamos o elemento de botão no DOM usando `getByText` e acionamos um evento click usando o método `fireEvent`. Depois que o evento click é acionado, desmontamos `<Request />` usando `unmount()`.

Em seguida, vamos atualizar `<Requests />` adicionando a função `removefriendRequest` e passando-a como um prop para `<Request />`. Fique atento aos comentários no bloco de código abaixo:

```jsx
// src/components/Requests/Requests.js

import React, { useState, useEffect } from "react";
import Request from "../Request/Request";
import axios from "axios";

const Requests = () => {
  const [loading, setLoading] = useState(true);
  const [friendRequests, setFriendRequests] = useState([]);

  useEffect(() => {
    fetchFriendRequests();
  }, []);

  const fetchFriendRequests = async () => {
    try {
      const { data } = await axios.get("https://randomuser.me/api/?results=5");
      setFriendRequests(data.results);
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };
    //  Remove Friend Request Function
    const removefriendRequest = (id) => {
    const newfriendRequests = friendRequests.filter(
      (friendRequest) => friendRequest.id !== id
    );
    setFriendRequests(newfriendRequests);
  };

  if (loading) {
    return (
      <div className="loading">
        <h1>loading...</h1>
      </div>
    );
  }

  return (
    <section>
      <div className="title">
        <h2>friend requests</h2>
        <div className="underline"></div>
      </div>
      <div>
        {friendRequests.map((request, index) => {
          const { login } = request;
          return (
            <Request
              index={index}
              key={login.uuid}
              {...request}
              removefriendRequest={removefriendRequest}   /*{Add as prop}*/
            />
          );
        })}
      </div>
    </section>
  );
};

export default Requests;

```

Todos os testes passaram!


![Imagem em que mostra que os testes passaram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9vxkkbwe0fh1wzbu3lvv.png)

A aplicação parece boa e o botão de recusar funciona conforme o esperado.

### Botão Atualizar

Por fim, adicionamos um botão de atualização que carrega novas solicitações de amizade quando o usuário recusou todas as solicitações de amizade. Acesse `src/components/Requests/Requests.test.js` e adicione o novo bloco de teste abaixo ao bloco describe:

```jsx
test("Refresh Button loads new friend requests", async () => {
    // declare empty value
    const value = {
      data: {
        results: [],
      },
    };

    // mock axios.get to return an empty array
    axios.get.mockResolvedValueOnce(value);

    render(<Requests />);
    await Promise.all([
      waitForElementToBeRemoved(() => screen.queryByText(/Loading.../i)),
    ]);

    const refreshButton = screen.getByText(/refresh/i);

    fireEvent.click(refreshButton);

    expect(screen.getByText(/friend requests/i)).toBeInTheDocument();
  });

```

Quando não há mais solicitações de amizade, isso significa que o estado `friendRequests` no componente `<Requests />` é um array vazio; então a primeira coisa que fazemos no bloco de teste acima é simular `axios.get` para retornar um array vazio. Em seguida, renderizamos nosso componente e esperamos que `Loading...` seja removido do DOM.

Por fim, o `refreshButton` é consultado no DOM, um evento de clique é acionado e, em seguida, esperamos que as solicitações de texto de amizade estejam no DOM.

No momento, nosso teste está falhando, então vamos atualizar o componente `<Requests />`. Fique atento aos comentários abaixo:

```jsx
import React, { useState, useEffect } from "react";
import Request from "../Request/Request";
import axios from "axios";

const Requests = () => {
  const [loading, setLoading] = useState(true);
  const [friendRequests, setFriendRequests] = useState([]);

  useEffect(() => {
    fetchFriendRequests();
  }, []);

  const fetchFriendRequests = async () => {
    try {
      const { data } = await axios.get("https://randomuser.me/api/?results=5");
      setFriendRequests(data.results);
      setLoading(false);
    } catch (error) {
      console.log(error);
    }
  };

  const removefriendRequest = (id) => {
    const newfriendRequests = friendRequests.filter(
      (friendRequest) => friendRequest.id !== id
    );
    setFriendRequests(newfriendRequests);
  };

  if (loading) {
    return (
      <div className="loading">
        <h1>loading...</h1>
      </div>
    );
  }

  // Condition for when friendRequests is an empty array
  if (friendRequests.length === 0) {
    return (
      <main>
        <div className="title">
          <h2>no Requests</h2>
          <button className="btn" onClick={() => fetchFriendRequests()}>
            refresh
          </button>
        </div>
      </main>
    );
  }

  return (
    <section>
      <div className="title">
        <h2>friend requests</h2>
        <div className="underline"></div>
      </div>
      <div>
        {friendRequests.map((request, index) => {
          const { login } = request;
          return (
            <Request
              index={index}
              key={login.uuid}
              {...request}
              removefriendRequest={removefriendRequest}
            />
          );
        })}
      </div>
    </section>
  );
};

export default Requests;

```

Agora que atualizamos o componente, espera-se que o teste passe, mas não passou. Temos um erro "não envolvido no ato".

![Imagem dos teste falhando](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mn17ip88pc5vbm3pzwst.png)

Encontramos esse erro porque `fireEvent.click(refreshButton)` acionou uma chamada assíncrona. Você pode encontrar esse erro por vários outros motivos ao escrever testes.

Para resolver nosso erro atual, use `waitFor` para aguardar a conclusão completa da atualização do componente. O `waitFor` é uma API da biblioteca de testes do React, que permite esperar que as asserções agrupadas passem dentro de uma janela de tempo limite específica.

Vamos atualizar `src/components/Requests/Requests.test.js`.

Importe waitFor de `@testing-library/react`:

```jsx
// src/components/Requests/Requests.test.js

import {
  render,
  screen,
  fireEvent,
  waitFor, // import waitFor
  waitForElementToBeRemoved,
} from "@testing-library/react";

```

Atualize o teste do botão de atualização com o bloco de código abaixo:

```jsx
  // Refresh button Test
  test("Refresh Button loads new friend requests", async () => {
    const value = {
      data: {
        results: [],
      },
    };
    axios.get.mockResolvedValueOnce(value);

    render(<Requests />);
    await Promise.all([
      waitForElementToBeRemoved(() => screen.queryByText(/Loading.../i)),
    ]);

    const refreshButton = screen.getByText(/refresh/i);

    fireEvent.click(refreshButton);

    // Wrap assertion within waitFor
    await waitFor(() => {
      expect(screen.getByText(/friend requests/i)).toBeInTheDocument();
    });
  });

```

Você pode realizar um teste manual verificando como o projeto é executado no navegador.

Além disso, verifique se em seu arquivo package.json você configurou isso:

```jsx
  "jest": {
    "resetMocks": false 
  },

```

## Conclusão

A importância dos testes de aplicações, especialmente para aplicações grandes, não podem ser exagerados. Escrever testes automatizados é essencial para desenvolver aplicações de alta qualidade. É simples começar a testar aplicações React e aumentar a qualidade do código com a documentação de testes do CRA, React Testing Library e Jest. 

Obrigado por ler!