Como começar a testar seus aplicativos do React usando a Biblioteca de testes do React e o Jest


O teste é frequentemente visto como um processo tedioso. É um código extra que você precisa escrever e, em alguns casos, para ser honesto, não é necessário. Mas todo desenvolvedor deve conhecer pelo menos o básico dos testes. Aumenta a confiança nos produtos que eles constroem e, para a maioria das empresas, é um requisito.

No mundo React, existe uma biblioteca incrível chamada react-testing-library o que ajuda a testar seus aplicativos do React com mais eficiência. Você usa com Jest.

Neste artigo, veremos as 8 etapas simples que você pode executar para começar a testar seus React Apps como um chefe.

Pré-requisitos

Este tutorial pressupõe que você tenha pelo menos um entendimento básico do React. Vou me concentrar apenas na parte do teste.

E para acompanhar, você deve clonar o projeto executando em seu terminal:

  git clone https://github.com/ibrahima92/prep-react-testing-library-guide

Em seguida, execute:

  yarn

Ou, se você usa o NPM:

npm install

E é isso! Agora vamos mergulhar em alguns princípios.

Fundamentos

Algumas coisas importantes serão muito usadas neste artigo, e a compreensão do papel delas pode ajudá-lo com sua compreensão.

it or test: descreve o teste em si. Toma como parâmetros o nome do teste e uma função que mantém os testes.

expect: a condição que o teste precisa passar. Ele comparará o parâmetro recebido com um correspondente.

a matcher: uma função aplicada à condição esperada.

render: o método usado para renderizar um determinado componente.

import React from 'react'
import {render} from '@testing-library/react'
import App from './App'
 
 it('should take a snapshot', () => {
    const { asFragment } = render()
    
    expect(asFragment()).toMatchSnapshot()
   })
});

Como você pode ver, descrevemos o teste com itentão use render para exibir o componente App e esperar que asFragment() partidas toMatchSnapshot() (o correspondente fornecido por brincadeira)

A propósito, o render O método retorna vários métodos que podemos usar para testar nossos recursos. Também usamos a desestruturação para obter o método.

Dito isto, vamos seguir em frente e aprender mais sobre a Biblioteca de testes de reação na próxima seção.

O que é a Biblioteca de testes do React?

A React Testing Library é um pacote muito leve, criado por Kent C. Dodds. É um substituto para Enzima e fornece funções utilitárias leves em cima de react-dom e react-dom/test-utils.

A React Testing Library é uma biblioteca de testes do DOM, o que significa que, em vez de lidar com instâncias de componentes do React renderizados, ele lida com elementos do DOM e como eles se comportam na frente de usuários reais.

É uma ótima biblioteca, é (relativamente) fácil de começar a usar e incentiva boas práticas de teste. Nota – você também pode usá-lo sem o Jest.

“Quanto mais os testes se assemelham à maneira como o software é usado, mais confiança eles podem oferecer”.

Então, vamos começar a usá-lo na próxima seção. A propósito, você não precisa instalar nenhum pacote, pois create-react-app vem com a biblioteca e suas dependências.

1. Como criar um instantâneo de teste

Um instantâneo, como o nome sugere, permite salvar o instantâneo de um determinado componente. Isso ajuda muito quando você atualiza ou faz alguma refatoração e deseja obter ou comparar as alterações.

Agora, vamos tirar uma foto do App.js Arquivo.

import React from 'react'
import {render, cleanup} from '@testing-library/react'
import App from './App'

 afterEach(cleanup)
 
 it('should take a snapshot', () => {
    const { asFragment } = render()
    
    expect(asFragment()).toMatchSnapshot()
   })
});

Para tirar um instantâneo, primeiro precisamos importar render e cleanup. Esses dois métodos serão usados ​​muito neste artigo.

render, como você pode imaginar, ajuda a renderizar um componente React. E cleanup é passado como um parâmetro para afterEach limpar tudo após cada teste para evitar vazamentos de memória.

Em seguida, podemos renderizar o componente App com render e voltar asFragment como um valor retornado do método E, finalmente, verifique se o fragmento do componente App corresponde ao instantâneo.

Agora, para executar o teste, abra seu terminal e navegue até a raiz do projeto e execute o seguinte comando:

  yarn test

Ou, se você usar o npm:

  npm test

Como resultado, ele criará uma nova pasta __snapshots__ e um arquivo App.test.js.snap no src que ficará assim:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Take a snapshot should take a snapshot 1`] = `

  

Testing

`;

E se você fizer outra alteração no App.js, o teste falhará, porque o instantâneo não corresponderá mais à condição. Para passar, basta pressionar u para atualizá-lo. E você terá o instantâneo atualizado em App.test.js.snap.

Agora, vamos seguir em frente e começar a testar nossos elementos.

2. Testando elementos DOM

Para testar nossos elementos DOM, primeiro precisamos examinar o TestElements.js Arquivo.

import React from 'react'

const TestElements = () => {
 const [counter, setCounter] = React.useState(0)
  
 return (
  <>
    

{ counter }

) } export default TestElements

Aqui, a única coisa que você precisa reter é data-testid. Será usado para selecionar esses elementos do arquivo de teste. Agora, vamos escrever o teste de unidade:

Teste se o contador é igual a 0:

TestElements.test.js

import React from 'react';
import { render, cleanup } from '@testing-library/react';
import TestElements from './TestElements'

afterEach(cleanup);

  it('should equal to 0', () => {
    const { getByTestId } = render(); 
    expect(getByTestId('counter')).toHaveTextContent(0)
   });

Como você pode ver, a sintaxe é bastante semelhante ao teste anterior. A única diferença é que usamos getByTestId para selecionar os elementos necessários (lembre-se do data-testid) e verifique se passou no teste. Em outras palavras, verificamos se o conteúdo do texto

{ counter }

é igual a 0.

Teste se os botões estão ativados ou desativados:

TestElements.test.js (adicione o seguinte bloco de código ao arquivo)

   it('should be enabled', () => {
    const { getByTestId } = render();
    expect(getByTestId('button-up')).not.toHaveAttribute('disabled')
  });

  it('should be disabled', () => {
    const { getByTestId } = render(); 
    expect(getByTestId('button-down')).toBeDisabled()
  });

Aqui, como sempre, usamos getByTestId para selecionar elementos e verificar o primeiro teste se o botão tiver um disabled atributo. E para o segundo, se o botão estiver desativado ou não.

E se você salvar o arquivo ou executar novamente no seu terminal yarn test, o teste será aprovado.

Parabéns! Seu primeiro teste passou!

Parabéns

Agora, vamos aprender como testar um evento na próxima seção.

3. Eventos de Teste

Antes de escrever nossos testes de unidade, vamos verificar primeiro o que TestEvents.js parece.

import React from 'react'

const TestEvents = () => {
  const [counter, setCounter] = React.useState(0)
  
return (
  <>
    

{ counter }

) } export default TestEvents

Agora, vamos escrever os testes.

Teste se o contador aumenta e diminui corretamente quando clicamos nos botões:

TestEvents.test.js

import React from 'react';
import { render, cleanup, fireEvent } from '@testing-library/react';
import TestEvents from './TestEvents'

  afterEach(cleanup);
  
  it('increments counter', () => {
    const { getByTestId } = render(); 
    
    fireEvent.click(getByTestId('button-up'))

    expect(getByTestId('counter')).toHaveTextContent('1')
  });

  it('decrements counter', () => {
    const { getByTestId } = render(); 
    
    fireEvent.click(getByTestId('button-down'))

    expect(getByTestId('counter')).toHaveTextContent('-1')
  });

Como você pode ver, esses dois testes são muito semelhantes, exceto o conteúdo de texto esperado.

O primeiro teste dispara um evento de clique com fireEvent.click() para verificar se o contador aumenta para 1 quando o botão é clicado.

E o segundo verifica se o contador diminui para -1 quando o botão é clicado.

fireEvent possui vários métodos que você pode usar para testar eventos, fique à vontade para mergulhar na documentação para saber mais.

Agora que sabemos como testar eventos, vamos seguir em frente e aprender na próxima seção como lidar com ações assíncronas.

4. Testando ações assíncronas

Uma ação assíncrona é algo que pode levar algum tempo para ser concluído. Pode ser uma solicitação HTTP, um timer e assim por diante.

Agora, vamos verificar o TestAsync.js Arquivo.

import React from 'react'

const TestAsync = () => {
  const [counter, setCounter] = React.useState(0)

  const delayCount = () => (
    setTimeout(() => {
      setCounter(counter + 1)
    }, 500)
  )
  
return (
  <>
    

{ counter }

) } export default TestAsync

Aqui, usamos setTimeout() para atrasar o evento de incremento em 0,5s.

Teste se o contador é incrementado após 0,5s:

TestAsync.test.js

import React from 'react';
import { render, cleanup, fireEvent, waitForElement } from '@testing-library/react';
import TestAsync from './TestAsync'

afterEach(cleanup);
  
  it('increments counter after 0.5s', async () => {
    const { getByTestId, getByText } = render(); 

    fireEvent.click(getByTestId('button-up'))

    const counter = await waitForElement(() => getByText('1')) 

    expect(counter).toHaveTextContent('1')
  });

Para testar o evento de incremento, primeiro precisamos usar async / waitit para manipular a ação porque, como eu disse anteriormente, leva tempo para concluir.

Em seguida, usamos um novo método auxiliar getByText(). Isso é semelhante a getByTestId(), exceto aquilo getByText() seleciona o conteúdo do texto em vez de id ou data-testid.

Agora, depois de clicar no botão, esperamos que o contador seja incrementado com waitForElement(() => getByText('1')). E uma vez que o contador tenha aumentado para 1, agora podemos passar para a condição e verificar se o contador é efetivamente igual a 1.

Dito isto, agora vamos para casos de teste mais complexos.

Você está pronto?

pronto

5. Teste de reação ao Redux

Se você é novo no React Redux, Este artigo pode ajudá-lo. Caso contrário, vamos verificar o que o TestRedux.js parece.

import React from 'react'
import { connect } from 'react-redux'

const TestRedux = ({counter, dispatch}) => {

 const increment = () => dispatch({ type: 'INCREMENT' })
 const decrement = () => dispatch({ type: 'DECREMENT' })
  
 return (
  <>
    

{ counter }

) } export default connect(state => ({ counter: state.count }))(TestRedux)

E para o redutor:

export const initialState = {
    count: 0,
  }
  
  export function reducer(state = initialState, action) {
    switch (action.type) {
      case 'INCREMENT':
        return {
          count: state.count + 1,
        }
      case 'DECREMENT':
        return {
          count: state.count - 1,
        }
      default:
        return state
    }
  }

Como você pode ver, não há nada sofisticado – é apenas um Contra-Componente básico tratado pelo React Redux.

Agora, vamos escrever os testes de unidade.

Teste se o estado inicial é igual a 0:

TestRedux.test.js

import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { render, cleanup, fireEvent } from '@testing-library/react';
import { initialState, reducer } from '../store/reducer'
import TestRedux from './TestRedux'

const renderWithRedux = (
  component,
  { initialState, store = createStore(reducer, initialState) } = {}
) => {
  return {
    ...render({component}),
    store,
  }
}

 afterEach(cleanup);

it('checks initial state is equal to 0', () => {
    const { getByTestId } = renderWithRedux()
    expect(getByTestId('counter')).toHaveTextContent('0')
  })

Precisamos importar algumas coisas para testar o React Redux. E aqui, criamos nossa própria função auxiliar renderWithRedux() para renderizar o componente, pois ele será usado várias vezes.

renderWithRedux() recebe como parâmetros o componente a ser renderizado, o estado inicial e o armazenamento. Se não houver armazenamento, ele criará um novo e, se não receber um estado inicial ou armazenamento, retornará um objeto vazio.

Em seguida, usamos render() para renderizar o componente e passar a loja para o provedor.

Dito isto, agora podemos passar o componente TestRedux para renderWithRedux() para testar se o contador é igual a 0.

Teste se o contador incrementa e diminui corretamente:

TestRedux.test.js (adicione o seguinte bloco de código ao arquivo)

it('increments the counter through redux', () => {
  const { getByTestId } = renderWithRedux(, 
    {initialState: {count: 5}
})
  fireEvent.click(getByTestId('button-up'))
  expect(getByTestId('counter')).toHaveTextContent('6')
})

it('decrements the counter through redux', () => {
  const { getByTestId} = renderWithRedux(, {
    initialState: { count: 100 },
  })
  fireEvent.click(getByTestId('button-down'))
  expect(getByTestId('counter')).toHaveTextContent('99')
})

Para testar os eventos de incremento e decremento, passamos um estado inicial como um segundo argumento para renderWithRedux(). Agora, podemos clicar nos botões e testar se o resultado esperado corresponde à condição ou não.

Agora, vamos para a próxima seção e apresentamos o React Context.

React Router e Axios virão a seguir – você ainda está comigo?

claro

6. Teste do contexto de reação

Se você é novo no React Context, confira Este artigo primeiro. Caso contrário, vamos verificar o TextContext.js Arquivo.

import React from "react"

export const CounterContext = React.createContext()

const CounterProvider = () => {
  const [counter, setCounter] = React.useState(0)
  const increment = () => setCounter(counter + 1)
  const decrement = () => setCounter(counter - 1)

  return (
    
      
    
  )
}

export const Counter = () => {  
    const { counter, increment, decrement } = React.useContext(CounterContext)   
    return (
     <>
       

{ counter }

) } export default CounterProvider

Agora, o estado do contador é gerenciado por meio do React Context. Vamos escrever o teste de unidade para verificar se ele se comporta conforme o esperado.

Teste se o estado inicial é igual a 0:

TextContext.test.js

import React from 'react'
import { render, cleanup,  fireEvent } from '@testing-library/react'
import CounterProvider, { CounterContext, Counter } from './TestContext'

const renderWithContext = (
  component) => {
  return {
    ...render(
        
            {component}
        )
  }
}

afterEach(cleanup);

it('checks if initial state is equal to 0', () => {
    const { getByTestId } = renderWithContext()
    expect(getByTestId('counter')).toHaveTextContent('0')
})

Como na seção anterior com React Redux, aqui usamos a mesma abordagem, criando uma função auxiliar renderWithContext() para renderizar o componente. Mas desta vez, ele recebe apenas o componente como parâmetro. E para criar um novo contexto, passamos CounterContext para o provedor.

Agora, podemos testar se o contador é inicialmente igual a 0 ou não.

Teste se o contador incrementa e diminui corretamente:

TextContext.test.js (adicione o seguinte bloco de código ao arquivo)

  it('increments the counter', () => {
    const { getByTestId } = renderWithContext()

    fireEvent.click(getByTestId('button-up'))
    expect(getByTestId('counter')).toHaveTextContent('1')
  })

  it('decrements the counter', () => {
    const { getByTestId} = renderWithContext()

    fireEvent.click(getByTestId('button-down'))
    expect(getByTestId('counter')).toHaveTextContent('-1')
  })

Como você pode ver, aqui acionamos um evento click para testar se o contador aumenta corretamente para 1 e diminui para -1.

Dito isto, agora podemos passar para a próxima seção e apresentar o React Router.

7. Teste do React Router

Se você quiser mergulhar no React Router, Este artigo pode ajudá-lo. Caso contrário, vamos verificar o TestRouter.js Arquivo.

import React from 'react'
import { Link, Route, Switch,  useParams } from 'react-router-dom'

const About = () => 

About page

const Home = () =>

Home page

const Contact = () => { const { name } = useParams() return

{name}

} const TestRouter = () => { const name = 'John Doe' return ( <> ) } export default TestRouter

Aqui, temos alguns componentes para renderizar ao navegar na página inicial.

Agora, vamos escrever os testes:

import React from 'react'
import { Router } from 'react-router-dom'
import { render, fireEvent } from '@testing-library/react'
import { createMemoryHistory } from 'history'
import TestRouter from './TestRouter'


const renderWithRouter = (component) => {
    const history = createMemoryHistory()
    return { 
    ...render (
    
        {component}
    
    )
  }
}

it('should render the home page', () => {

  const { container, getByTestId } = renderWithRouter() 
  const navbar = getByTestId('navbar')
  const link = getByTestId('home-link')

  expect(container.innerHTML).toMatch('Home page')
  expect(navbar).toContainElement(link)
})

Para testar o React Router, primeiro precisamos ter um histórico de navegação. Por isso usamos createMemoryHistory() bem como o nome sugerido para criar um histórico de navegação.

Em seguida, usamos nossa função auxiliar renderWithRouter() para renderizar o componente e passar history ao Router componente. Com isso, agora podemos testar se a página carregada no início é a Home page ou não. E se a barra de navegação estiver carregada com os links esperados.

Teste se ele navega para outras páginas com os parâmetros quando clicamos nos links:

TestRouter.test.js (adicione o seguinte bloco de código ao arquivo)

it('should navigate to the about page', ()=> {
  const { container, getByTestId } = renderWithRouter() 

  fireEvent.click(getByTestId('about-link'))

  expect(container.innerHTML).toMatch('About page')
})

it('should navigate to the contact page with the params', ()=> {
  const { container, getByTestId } = renderWithRouter() 
   
  fireEvent.click(getByTestId('contact-link'))
   
  expect(container.innerHTML).toMatch('John Doe')
})

Agora, para verificar se a navegação funciona, precisamos disparar um evento de clique nos links de navegação.

Para o primeiro teste, verificamos se o conteúdo é igual ao texto na página Sobre e, para o segundo, testamos os parâmetros de roteamento e verificamos se foi aprovado corretamente.

Agora podemos passar para a seção final e aprender como testar uma solicitação do Axios.

Estamos quase terminando!

ainda aqui

8. Testando Solicitação HTTP

Como sempre, vamos ver primeiro o que TextAxios.js arquivo se parece.

import React from 'react'
import axios from 'axios'

const TestAxios = ({ url }) => {
  const [data, setData] = React.useState()

  const fetchData = async () => {
    const response = await axios.get(url)
    setData(response.data.greeting)    
 }     
 
 return (
  <>
    
    { 
    data ?
    
{data}
:

Loading...

} ) } export default TestAxios

Como você pode ver aqui, temos um componente simples que possui um botão para fazer uma solicitação. E se os dados não estiverem disponíveis, será exibida uma mensagem de carregamento.

Agora, vamos escrever os testes.

Teste se os dados foram buscados e exibidos corretamente:

TextAxios.test.js

import React from 'react'
import { render, waitForElement, fireEvent } from '@testing-library/react'
import axiosMock from 'axios'
import TestAxios from './TestAxios'

jest.mock('axios')

it('should display a loading text', () => {

 const { getByTestId } = render()

  expect(getByTestId('loading')).toHaveTextContent('Loading...')
})

it('should load and display the data', async () => {
  const url = '/greeting'
  const { getByTestId } = render()

  axiosMock.get.mockResolvedValueOnce({
    data: { greeting: 'hello there' },
  })

  fireEvent.click(getByTestId('fetch-data'))

  const greetingData = await waitForElement(() => getByTestId('show-data'))

  expect(axiosMock.get).toHaveBeenCalledTimes(1)
  expect(axiosMock.get).toHaveBeenCalledWith(url)
  expect(greetingData).toHaveTextContent('hello there')
})

Este caso de teste é um pouco diferente porque temos que lidar com uma solicitação HTTP. E para fazer isso, precisamos zombar de uma solicitação de axios com a ajuda de jest.mock('axios').

Agora podemos usar axiosMock e aplique um get() método para isso. Por fim, usaremos a função Jest mockResolvedValueOnce() para passar os dados simulados como um parâmetro.

Com isso, agora para o segundo teste, podemos clicar no botão para buscar os dados e usar async / waitit para resolvê-los. E agora temos que testar 3 coisas:

  1. Se a solicitação HTTP foi feita corretamente
  2. Se a solicitação HTTP tiver sido feita com o url
  3. Se os dados buscados correspondem à expectativa.

E para o primeiro teste, apenas verificamos se a mensagem de carregamento é exibida quando não temos dados para mostrar.

Dito isto, agora concluímos as 8 etapas simples para começar a testar seus aplicativos do React.

Não tenha mais medo de testar.

sem medo

Pensamentos finais

A Biblioteca de testes do React é um ótimo pacote para testar o React Apps. Isso nos dá acesso a jest-dom matchers que podemos usar para testar nossos componentes de forma mais eficiente e com boas práticas. Espero que este artigo tenha sido útil e ajude você a criar aplicativos robustos do React no futuro.

Você pode encontrar o projeto finalizado aqui

Obrigado por ler!

Leia mais artigosSubscreva a minha newsletterSiga me no twitter

Você pode ler outros artigos como este em meu blog.

Próximos passos

Documentos da React Testing Library

Cheatheet da biblioteca de testes de reação

Jest DOM matchers cheatsheet

Jest Docs





Fonte

Leave a Reply

Your email address will not be published. Required fields are marked *