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

  • Tipos e imutabilidade em JavaScript: por que você deveria se preocupar?

    Recentemente, tive o prazer de apresentar Tipos e Imutabilidade no maior evento de JavaScript do mundo. Por acreditar que o assunto é muito pertinente, resolvi também escrever um texto a respeito.

  • React: do básico ao avançado – Parte 3

    React é uma biblioteca JavaScript para desenvolvimento de interfaces de usuário. Esta é a terceira parte de uma série de artigos que ensina a desenvolver e estruturar aplicações com JavaScript e React. Clique aqui caso você ainda não tenha lido a segunda parte. Imagino que você deve estar ansioso para escrever código, mas antes quero […]

  • Weekly #174 – Splittable, NPM 4 e últimos eventos do ano

    A BrazilJS Weekly é a seleção semanal que reúne as novidades sobre o desenvolvimento Web no Brasil e no mundo. Ainda não é inscrito? Faça o seu cadastro e receba nossa Newsletter semanal 😎👊🙂👌👍 Sugira conteúdo para a Weekly usando o nosso canal de issues no Github. Um agradecimento especial aos 5 colaboradores da edição […]

Patrocinadores BrazilJS

Gold

Silver

Bronze

Apoio

BrazilJS® é uma iniciativa NASC.     Hosted by Getup