Teste de Aceitação com React, Jest e Nightmare

Em:

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!

Créditos

  • A importância de eventos de tecnologia exclusivos para mulheres

    Há quem diga que é vitimismo ou outros termos do gênero, mas não é, mulheres são realmente tratadas de forma diferente.

  • FrontInBH e BrazilJS 2016

    É com imenso prazer que anunciamos o primeiro evento oficialmente afiliado ao BrazilJS, o FrontInBH. O FrontInBH é um dos maiores eventos de tecnologias Front-end do Brasil, sempre levando para a comunidade mineira um conteúdo de extrema relevância através de palestrantes nacionais e internacionais. Em Agosto de 2016, mais precisamente no dia 06, acontecerá a […]

  • Posição sobre quebra do Código de Conduta  –  BrazilJS Conf 2015

    Infelizmente tomamos conhecimento de uma violação do código de conduta da BrazilJS Conf 2015. Este fato chegou até nós após a conferência. Ou seja, uma atitude durante o evento (que é o ideal) se tornou impossível. Levamos a sério o código de conduta e acreditamos que todos os 1300 participantes também. Estamos discutindo como organização, […]

Patrocinadores BrazilJS

Gold

Silver

Bronze

Apoio

BrazilJS® é uma iniciativa NASC.     Hosted by Getup