Iniciando seus testes unitários em componentes ReactJS de forma moderna!
De onde surgiu esse artigo
Comecei a aprender sobre ReactJS esses dias, e de cara apanhei muito para configurar um ambiente com Browserify/Webpack + ES5/ES6 além de me virar para entender as várias formas de escrever seus componentes, depois de conseguir entender tudo direitinho, como todo bom desenvolvedor eu estava doido para começar a escrever testes, e ai que a verdadeira surra começou! Dessa vez eu sofri com muitos artigos desatualizados e falta de conteúdo, foi tanta falta de conteúdo atualizado que como todo bom desenvolvedor (de novo rs), resolvi escrever sobre isso para tentar ajudar alguém em situação parecida. E aqui está!
Disclaimer
Este artigo é destinado para quem tem um conhecimento básico sobre ReactJS, ES6 e testes unitários, se você ainda não conhece esses caras recomendo que de uma olhada em:
Planejando a missão
Vamos testar um componente simples, que escreve hello na página. Como somos descolados vamos usar ES6 e um bundler para organizar nossas dependências e componentes.
Para o exemplo vamos de Webpack como bundler e Babel como compiler, o que parece lindo falando assim, mas na realidade é algo bem chato de configurar. Você precisa pensar em coisas como:
- Instalar o Babel e seus plugins para o ES6 e React.
- Instalar e configurar o Webpack para rodar com o Babel e seus plugins.
- Levantar um servidor.
- Instalar o ReactJS e ReactDOM.
- Criar devidamente seus arquivos .html e .js
Preparando o ambiente para o React
Eu apanhei tanto disso quando tive que configurar pela primeira vez, que não desejo isso para ninguém e (claro) não quero apanhar duas vezes, justamente por isso resolvi criar um generator em slush que gera esse ambiente pronto para começarmos a brincar.
PS: Mentira! Todo mundo tem que se ferrar para aprender como tudo funciona direito e só depois usar algo pronto para ganhar produtividade. Mas para adiantar vamos continuar com o generator ;)
Vamos gerar nosso projeto:
1 — Instale o Slush globalmente:
$ [sudo] npm install -g slush
2 — Instale o generator globalmente:
$ [sudo] npm install -g slush-react-start
3 — Inicie o generator, escolha o ES2015 e responda as perguntinhas:
$ slush react-start
OK, nesse ponto podemos rodar o comando npm start e teremos nosso projeto disponível rodando em http://localhost:5000.
Precisamos de ajuda para testar nossos componentes
O facebook oferece um plugin para ajudar na tarefa de testar seus componentes, o kit de utilitários chamado TestUtils, que faz parte do pacote de Add-ons que o React traz para te ajudar em várias coisas. Esse cara é muito importante para conseguirmos emular o comportamento do react no ambiente de testes, veremos mais sobre ele mais a baixo.
1° Pegadinha: O react-addons for descontinuado, e seus plugins separados em pacotes individuais, cuidado ao ver um exemplo como require(‘react/addons’), pois é uma cilada bino (nossa, eu escrevi isso mesmo? rsrs).
para instalar o TestUtils usamos:
$ npm install react-addons-test-utils --save-dev
O próprio facebook indica o Enzyme criado pelo Airbnb para ajudar em testes unitários ao invés do TestUtils, mas sinceramente ainda não parei para brincar com ele, então não posso opinar ;)
Escolhendo o framework de testes
O facebook indica o Jest, mas eu só ouvi coisas ruins dele, então revolvi começar com o bom o velho Mocha que é garantia de sucesso. Assim eu tiver um tempinho vou fazer algo com Enzyme+Jest para formar uma opinião.
Blz, vamos instalar nosso amigo:
$ npm install mocha --save-dev
Vamos instalar também o expect para dar aquela mão na hora da asserção :)
$ npm install expect --save-dev
Escrevendo seu primeiro teste e mais pegadinhas
Vamos criar uma pasta para manter nossos testes e vamos escrever nossos testes em um arquivo chamado index.js
$ mkdir test
$ cd test
$ touch index.js
Massa! Agora vamos começar a escrever um teste unitário para nosso componente <Hello />, que está lá em src/hello.js:
Massa, agora temos nosso teste lindo, escrito com ES6 todo descolado!
Relaxem, mais abaixo vou explicar melhor como funcionam esses métodos do TestUtils.
Vamos rodar o Mocha para ver essa belezinha rodando:
$ mocha
Resultado: SyntaxError: Unexpected reserved word.
2° Pegadinha: Opa, falei ES6 lá em cima? Pois é, temos que informar ao Mocha que ele tem que usar o Babel para transpilar nosso código :(
Como iniciamos nosso projeto com o slush-react-start, já temos o que precisamos para rodar o Babel, então para tudo funcionar de boas executamos o comando:
$ mocha --compilers js:babel-core/register
Resultado: ReferenceError: document is not defined
WTF, o que está acontecendo!
3° Pegadinha: Precisamos de um DOM para renderizar nossos componentes e acessar seu conteúdo para o teste, e para essa missão vamos usar nosso novo amigo jsdom, que nada mais é do que um DOM descolado que roda no NodeJS.
Vamos instalar nosso DOM de forma simples:
$ npm install jsdom --save-dev
Temos que instalar também a integração do Mocha com o jsdom:
$ npm install mocha-jsdom --save-dev
Agora vamos adicionar esse cara ao nosso teste:
Para não ficar executando um comando imenso a toda hora, vamos apontar o npm test para nosso teste, adicionado a linha “test”: “mocha — compilers js:babel-core/register” em nossos scripts lá no package.json, agora temos o comando npm test para facilitar nossa vida.
Finalmente rodamos nosso teste:
$ npm test
Resultado: 1 passing
OMG! Ta rodando!
A filosofia de testes no Front-End
Escrever testes unitários no Back-End é bem simples, basicamente testamos nossos métodos e show. Agora quando passamos a bola para o Front-End, a coisa complica, não pensamos apenas no resultado de um método, mas também temos que nos preocupar em testar se nossos componentes estão sendo renderizados corretamente e pior ainda, nas ações do usuário! Afinal como testar um click?
Vamos por partes, primeiro vamos seguir um pattern para escrever nossos testes:
- 1° Renderizar o HTML.
- 2° Encontrar o nó(no DOM) que queremos testar.
- 3° Verificar o conteúdo.
Vamos entender os métodos do TestUtils que usamos em nosso teste:
TestUtils.renderIntoDocument(<React-tag />);
Renderiza um componente criado com react.
TestUtils.findRenderedDOMComponentWithTag(<component>, 'tag');
Localiza todas as instâncias de componentes no DOM a partir da tag passada como parâmetro.
Opa, agora podemos entender melhor o fluxo do nosso teste, e entender como estamos aplicando nosso pattern:
O poder dos utilitários
No TestUtils temos métodos úteis para nossos testes, você pode conferir a lista completa no link abaixo:
Conclusão
Iniciar seus testes com React tem seu lado aterrorizante, pois temos Front-End no meio, e principalmente por culpa dos vários artigos desatualizados espalhados pela internet. Porém com um pouco de paciência e pesquisa, conseguimos escrever nossos testes, e seguindo nosso pattern fica até fácil ;)
PS: Todo o código usado aqui está disponível no Github.