Testando na prática seus componentes React usando o Jest

Uma das maiores vantagens do React, é, sem dúvida, utilizar o Enzyme (feito pelo Airbnb) para testar componentes tirando todo proveito do virtual DOM. Também podemos explorar as ferramentas poderosas do Jest como teste com snapshot e mocks para módulos externos. Porém, no caso do Jest, não é exclusividade somente para o React, embora sua popularidade tenha crescido na mesma época em que o React se tornou o framework da vez e ele combina bastante com este paradigma.

Já falei aqui sobre como trabalhar com os diferentes padrões de componentes para react, que logo em seguida, vem a questão: como testar de uma forma útil e eficiente estes componentes?

Estes testes podem fazer também parte da sua integração contínua, no processo de trabalho e na validação de pronto, caso você queira validá-lo em diferentes ambientes.

Vou mostrar um exemplo prático de um componente que foi isolado para simular um teste de um preenchimento de formulário com opção de pagamento no cartão de crédito, e como conseguimos testar este componente sem precisar ir na interface.

Além disto, vou mostrar como integrá-lo como parte do build no Circleci, rodando os testes em um servidor remoto quando um push para o repositório é realizado.

Aqui temos o componente que será testado:

Componente de Checkout

Como boa prática, construímos um componente que chamamos de Checkout, onde teremos o preenchimento dos dados do cartão de crédito, informações do usuário e envio.

Este componente contém estados (state), propriedades (props) que tratam das diferentes interações no preenchimento dos campos do formulário por um usuário.

É possível testá-lo de forma unitária e ainda simular os eventos e validação e todas as ações que acontecem internamente ao componente. Podemos saber dos estados, propriedades, além de poder configurar estados diferentes e ver o que acontece no componente, podendo simular vários cenários de testes. Isto não é incrível?

Temos aqui o código base do componente de Checkout que vamos testar:

Quer ver o componente completo? Temos aqui o código fonte.

Temos aqui um componente React que tem os estados referente aos campos do formulário, que muda de acordo com eventos de mudança nos campos. Isto quer dizer que preenchemos os estados quando o usuário digita os dados, como é bastante usado em aplicações React.

Como este componente tem dependência de outro componente, neste caso o Stripe, eu resolvi fazer uma modificação que torna mais fácil testá-lo, pois não quero testar o fluxo do pagamento completo, apenas certificar que o componente grava os dados do formulário para ser enviado posteriormente.

Neste caso eu exportei o componente puro e conectei o componente ao Redux em uma outra parte, assim ele está exposto como módulo disponível para ambos.

Ambiente necessário para rodar o Jest com o React

Para que seu projeto reconheça o React e consiga processar o Javascript escrito nas diferentes variações do Javascript como ES5, você precisa adicionar uma configuração do Babel:

{
  "presets": ["es2015", "react"]
}

O que queremos testar?

Para realizar os testes de componentes, seria ideal fazê-lo antes de qualquer código, mas no mundo real muitas vezes desenvolvemos sem teste e depois temos que correr atrás do prejuízo. Isto por que quando desenvolvemos com o TDD realizamos o design do projeto de acordo com os testes e isto muitas vezes afeta toda a arquitetura. Quando não pensamos nos testes, criamos componentes dependentes e que descobrimos o quanto nosso código não estava eficiente quando temos de testar. Por isto, é importante que o teste pelo menos mínimo faça parte do desenvolvimento.

No caso aqui, temos um caso de um teste que será adicionado posteriormente, e que foi útil cobri-lo com teste de qualquer forma. Cobrimos com um teste para conseguir testar uma parte que muitas vezes temos bugs.

Adicionando testes e evoluindo o código

Neste exemplo dos testes que realizamos, usamos o enzyme com o componente mount, que cria toda estrutura de um componente react e uma API que é possível realizar diversas ações, como mudar um state e aplicar eventos, como fizemos a seguir com o simulate.

Você pode ver o código fonte aqui.

Fizemos alguns testes em que alteramos o state interno do componente, e verificamos se esta mudança altera o estado de fato, um bom jeito de começar a testar o básico, pois sempre bom seguir baby steps.

Depois adicionamos uma simulação de evento, alterando os campos do formulário e vendo se ele vai alterar o estado como esperado. Com isto temos um teste prático e a partir daí realizar várias ações e continuar com os testes do componente, buscando sempre ter o mínimo de dependência possível, e como explicado neste artigo sobre padrões de componentes react que falei anteriormente, temos que separar os componentes em componentes puros e componentes conectados.

Integrando ao build

Com o processo de integração contínua conseguimos rodar estes testes como parte da integração do projeto e do lançamento das versões do software, validando em diferentes ambientes antes de ir para produção e assegurando de que ele irá passar em todos estes testes antes de ser lançado.

Um servidor de integração contínua é um termo bastante comum na infraestrutura de desenvolvimento, ou devOps em que equipes conseguem trabalhar em um projeto realizando novos releases a cada código integrado, passando por diferentes testes e estágios automatizados

E com esta configuração no Circleci você consegue integrar e rodar estes no seu processo de build e release.

# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
  
build:
    docker:
    # specify the version you desire here
    - image: circleci/node:8.6.0
      environment:
        PG_HOST: 127.0.0.1
        POSTGRES_DB: gitpay_test
        POSTGRES_USER: postgres
        PG_PASSWD: postgres
        NODE_ENV: test
    - image: circleci/postgres:9.5
      environment:
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: postgres
        POSTGRES_DB: gitpay_test

    # Specify service dependencies here if necessary
    # CircleCI maintains a library of pre-built images
    # documented at https://circleci.com/docs/2.0/circleci-images/
    # - image: circleci/mongo:3.4.4

    working_directory: ~/repo

    steps:
      - checkout
      - run:
          name: install
          command: 'curl -k -O -L https://npmjs.org/install.sh | sh'
      - restore_cache:
          key: dependency-cache-{{ checksum "package.json" }}
      - run:
          name: Install packages
          command: npm install
      - save_cache:
          key: dependency-cache-{{ checksum "package.json" }}
          paths:
          - node_modules
      #- run: sudo apt install postgresql-client
      - run:
          name: install dockerize
          command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
          environment:
            DOCKERIZE_VERSION: v0.3.0
      - run:
          name: Wait for db
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      #- run:
      #    name: Set up database
      #    command: psql -h localhost -p 5432 -c 'create database gitpay_test' -U postgres
      - run:
          name: Migrate
          command: npm run migrate-test
      # run tests!
      - run:
          name: run node tests
          command: npm run test
      - run:
          name: run frontend tests
          command: cd frontend && npm run test

workflows:
  version: 2
  build-all:
    jobs:
      - build:
          filters:
            branches:
              ignore: gh-pages

Note que é um processo de build para rodar um projeto Node com react no frontend.

Se você quiser saber mais sobre as importância de se trabalhar com builds em projetos eu falo melhor aqui sobre como trabalhar com o Workflow do git para times remotos.

O que aprendemos?

Aprendemos aqui como criar testes de componentes react na prática, controlando os diferentes estados e verificando se temos o resultado esperado. Este foi um exemplo de um projeto já iniciando, mostrando como podemos integrar os testes do React posteriormente em um projeto com o Jest de uma forma fácil e realizar testes essenciais sem ter que modificar todo o projeto ou começar do zero. Também conseguimos fazer que este processo seja realizado no CI (integração contínua) para que o teste seja realizado em qualquer integração do código, e com isto permitir que quando outros enviarem modificações, os testes garantam que o componente ainda tem o seu funcionamento básico.

Espero que tenha ajudado e tenha sido um aprendizado de como utilizar os testes de componentes do React de um jeito direto e com um componente real onde você possa entender melhor e na prática.

Acompanhe o Pull Request onde estes testes foram implementadoshttps://github.com/worknenjoy/gitpay/pull/160/files

Quer aprender React na prática?

Com o Gitpay você pode trabalhar contribuindo com um projeto open source construído com o React. Veja nossas issues, cadastre-se na plataforma e veja as tarefas disponíveis para começar a criar soluções com o React , aprender e ser recompensado!

Fontes:

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *