Teste de Aceitação com React, Jest e Nightmare
Jest é um framework de testes com baterias incluídas criado pelo Facebook. Ele é rápido, cheio de recursos e integrado perfeitamente com Babel (outra importante ferramenta do nosso processo de build hoje em dia). Jest cria uma experiência excepcional para testes unitários.
Porém, nunca pude falar o mesmo sobre testes de aceitação. Será que algum dia poderíamos ter uma integração de alto nível, fácil de manter e com a mesma experiência para testes de aceitação?
Nightmare, uma biblioteca poderosa e de alto nível para automação de navegadores escrita em Electron, nos permite uma experiência bem próxima. Usando Nightmare, nós podemos rodar um navegador sem GUI (mais conhecido como headless) e realizar várias ações através de qualquer framework de testes baseado em NodeJS.
Jest é um desses frameworks. Neste artigo, vamos ver como configurar Jest e Nightmare em um projeto, criando um recurso ótimo para testes de aceitação.
Projeto exemplo
Vamos usar um projeto exemplo usando create-react-app como padrão. Você pode copiar o repositório ou acompanhar o passo a passo abaixo.
Usando Jest
Antes de conhecermos o Nightmare, vamos olhar um teste básico:
// src/tests/unit/App.test.js import React from 'react' import App from '../../src/app' import {mount} from 'enzyme' test('welcomes the user to React', function () { const wrapper = mount(<App />) expect(wrapper.text()).toContain('Welcome to React') })
Aqui, estamos usando Enzyme para montar nosso componente React e assegurar o que foi renderizado com o texto correto. Para aqueles que não estão familizariados com Enzyme, imagine que ele é o jQuery para testar componentes React. Com esteróides! $ npm test > jest test/unit PASS test/unit/app.test.js ✓ welcomes the user to React (29ms) Test Summary › Ran all tests matching "test/unit". › 1 test passed (1 total in 1 test suite, run time 1.256s)
Irado, mas esse artigo é sobre testes de aceitação. Vamos começar logo com eles! Usando Nightmare para testes de aceitação Nightmare deixa tudo muito fácil para criar um navegador sem GUI dentro de um framework de testes JavaScript. Ele usa o Electron, disponibilizando um ambiente bem similar ao Chrome. Vamos olhar o nosso arquivo de teste: // src/tests/acceptance/greeting.test.js import nightmare from 'nightmare' describe('When visiting the homepage', function () { test('it welcomes the user', async function () { let page = nightmare().goto('http://localhost:3000') let text = await page.evaluate(() => document.body.textContent) .end() expect(text).toContain('Welcome to React') }) })
Nesse exemplo, estamos rodando uma instância do Nightmare e visitando a nossa página principal. Chegando lá, pegamos o texto da página e asseguramos que ele existe baseado no que queremos. Como Jest suporta async/await, nós eliminamos o que antes seria algumas linhas de callback! Nota: Nightmare expõe vários outros comportamentos de navegador, tais como: clicar em elementos, mudar valor do input de formulário e executar um evento. Para saber mais, conheça a documentação completa. Voltando ao nosso exemplo, é meio chato ficar digitando a URL e porta, certo? Imagina se os valores mudarem? Teríamos que atualizar todos os nossos arquivos? Vamos escrever um helper para esconder esses detalhes: // src/tests/helpers/visit.js import nightmare from 'nightmare' import url from 'url' const BASE_URL = url.format({ protocol : process.env.PROTOCOL || 'http', hostname : process.env.HOST || 'localhost', port : process.env.PORT || 3000 }) export default function (path='', query={}) { const location = url.resolve(BASE_URL, path) return nightmare().goto(location) }
Podemos atualizar nosso teste: // src/tests/acceptance/greeting.test.js import nightmare from 'nightmare' import visit from '../helpers/visit' describe('When visiting the homepage', function () { test('it welcomes the user', async function () { let page = visit('/') let text = await page.evaluate(() => document.body.textContent) .end() expect(text).toContain('Welcome to React') }) })
Aha! Agora sim! Podemos mudar dinamicamente a URL base e HOST da nossa aplicação, sem manualmente atualizar os nossos testes! E como faço Integração Contínua? Conhecido em inglês como CI (Continuous Integration). Significa que não adianta escrevermos nossos testes se não os rodarmos frequentemente para ter certeza de que nossa aplicação está correta. Neste exemplo, iremos usar o CircleCI para rodar nossos testes automaticamente. # scripts/test.sh # Esse script será usado pelo CircleCI para executar nossas testes # Compilando o projeto npm run build # Mudando para o diretório de build pushd build # Iniciando um servidor básico/estático php -S localhost:3001 & # Salvando o PID do processo do servidor APP_TEST_PID=$(echo $!) # Executando os testes PORT=3001 CI=true npm run test:all # Saindo do diretório de build popd # Desligando o servidor kill $APP_TEST_PID
O que fizemos acima: Compilamos nosso projeto Criamos um host na pasta build gerada pelo create-react-app Rodamos os testes com o mesmo endereço Limpamos nossa bagunça A última etapa é configurar o CircleCI: # circle.yml machine: node: version: stable test: override: # “-e” aqui é para fazer o script # parar o processo em caso de error - bash -e scripts/test.sh
Agora, toda vez que esse projeto for atualizado, CircleCI automaticamente irá rodar nossos testes de aceitação usando nosso build de produção. Isso é super prático para deploys automáticos, onde garantimos a execução de todos os testes. Testes de Aceitação estão usando código de produção que irá ser usado por nossos usuários! Finalizando Nós realizamos o ciclo completo. Jest nos garantiu um poderoso e rápido ambiente de teste e vimos como que, com Nightmare, é de fácil uso e configuração. No final, nós temos o mesmo framework executando ambos os testes de aceitação e unitários. Você pode ver o exemplo completo aqui. Se você quiser saber mais sobre o ecossistema de testes em JavaScript em 2017 e, até mesmo, mais detalhes sobre Jest, eu recomendo ler meus outros posts. Jest é uma agradável plataforma de testes! O ecossistema de Testes em JavaScript em 2017 Jest: Escrever testes nunca foi tão divertido Jest: Snapshot Testing com React e Enzyme Créditos Acceptance Testing React Apps with Jest and Nightmare, escrito originalmente por Nate Hunzaker