Fazendo uma aplicação em Vue.js com TDD — Um guia extensivo para quem quer aprender — parte 1
Afinal, ensinar a montar uma aplicação sem testes é muito fácil
Este é o primeiro de uma série de artigos:
- Parte 1: Setup e o primeiro teste
- Parte 2: Continuando a UserView
- Parte 3: Testando a store e o restante dos componentes de apresentação
- Parte 4: Testando o serviço de requisições para a API
- Parte 5: Adicionando e testando com dependências de terceiros
- Parte 6: Resumo geral — 26/11
Caso tenha curiosidade, entre diretamente no repositório com o código final:
Caso você decidiu fazer todo o tutorial, vamos lá 🚀
Durante os workshops do VueJS Summit 2018, acabei conversando pessoalmente com o Edd Yerburgh, e mostrei a forma como eu estava testando as minhas aplicações, e depois de um incentivo, cá estou eu escrevendo esse artigo 😅
Espero com ele, mostrar como é fácil testar no front, principalmente, como é fácil testar uma aplicação com Vue.js!
Este tutorial possui muitas imagens e uma certa densidade de conceitos, por isso eu recomendo uma leitura calma caso você não tenha a base das ferramentas.
O que vamos fazer
O projeto será muito simples, vamos fazer uma aplicação que se comunica com a API do Github, buscando um usuário a partir de um username digitado.
Pode parecer um projeto pequeno, mas nele iremos ver vários tipos de testes que encontramos no desenvolvimento de uma aplicação Vue.js, aqui iremos testar:
- Componentes
- Vuex
- Serviços
Vamos aplicar neste projeto a tecnica do TDD!
Vamos escrever um teste que falhe, então fazer o mínimo de esforço para fazê-lo passar, e finalmente o iremos refatorar caso necessário, repetindo isso até finalizarmos a nossa aplicação.
Uma das vantagens de utilizar esta técnica, é que acabamos tendo feedbacks muito mais rápidos, podendo trabalhar com ciclos muito menores entre as alterações durante o desenvolvimento do nosso projeto.
Aplicar o TDD pode ser difícil no início, pois ele exige uma mudança de mindset, afinal, estamos escrevendo testes antes mesmo de escrever um código de produção.
Quero lembrar aqui que não somos obrigados a seguir a risca tudo do que é proposto, mas para este projeto, eu espero mostrar que isso na realidade pode ser algo simples de ser feito.
Modelando a aplicação
Antes de mais nada, vamos planejar como iremos fazer a nossa aplicação.
Iremos quebrar ela em apenas 3 componentes:
- UserView — Componente “inteligente”, responsável por fazer a comunicação com a store e carregar os nossos componentes de apresentação
- VUserSearchForm — Componente “burro”, responsável por renderizar o formulário, e também resposável por transmitir uma mensagem para o componente pai com o termo de pesquisa
- VUserProfile — Componente “burro”, responsável por renderizar as informações do nosso usuário pesquisado
Também iremos contar com um serviço para fazer requisições para a API do Github.
Baixe o vue-cli e vamos criar o nosso projeto:
npm i -g @vue/cli
vue create tdd-app
Abaixo, estão as features que eu escolhi, selecione o que for mais conveniente para você, ressaltando que irei cobrir testes E2E em um próximo artigo quem sabe.
Vamos propor um desafio aqui, só iremos rodar o npm run serve
apenas quando finalizarmos a nossa aplicação.
Vamos limpar o projeto
Um projeto pelo Vue CLI acaba trazendo alguns arquivos iniciais, vamos remover tudo o que não precisamos neste primeiro momento.
Remova:
- src/store.js
- src/assets/logo.png
- src/components/HelloWorld.vue
- src/views/About.vue
- src/views/Home.vue
- tests/unit/HelloWorld.spec.js
Limpe o App.vue
<template>
<div id="app">
<router-view/>
</div>
</template><style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
Limpe o router.js
import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: []
})
Crie uma pasta para colocar a nossa store:
// src/store/index.jsimport Vue from 'vue'
import Vuex from 'vuex'
import state from '@/store/state'
import mutations from '@/store/mutations'
import actions from '@/store/actions'Vue.use(Vuex)export default new Vuex.Store({
state,
mutations,
actions,
})
Criamos os arquivos: src/store/state.js
src/store/actions.js
src/store/mutations.js
e todos eles possuem o mesmo trecho de código abaixo:
export default {}
Adicionamos um npm script para observar os nossos testes no package.json
..."test:unit": "vue-cli-service test:unit",
"test:unit:watch": "vue-cli-service test:unit --watchAll"
E finalmente, vamos instalar algumas dependências que iremos usar no projeto.
npm i -d axios
npm i -D flush-promises nock
Criando nosso primeiro teste
Agora podemos começar a criar os nossos testes, vamos começar pelo nosso primeiro componente, o UserView
lembrando que estamos utilizando jest como nosso framework de testes.
Este será um componente inteligente, responsável por carregar todos os componentes da tela, e ele fará a comunicação com a store para fazer a busca do usuário do Github.
Vamos criar então o arquivo: tests/unit/UserView.spec.js
describe('UserView', () => {
it('works', () => {})
})
E podemos rodar os testes: npm run test:unit
Mas o que exatamente a gente acaba testando nos nossos componentes?
Podemos testar várias coisas nos nossos componentes, mas podemos nos basear nos seguintes tópicos:
Se o componente renderiza
Precisamos garantir que pelo menos o componente está renderizando corretamente.
Se ele renderiza a coisa certa
Se garantimos que o componente renderiza, podemos testar então se ele está renderizando a coisa certa, o nosso componente contem um botão e um input, ou ele contém um botão e um comentário dizendo “Input será implementado na v2”.
Os seus binds
Testamos todos os binds possíveis, o nosso componente está passando as props corretas para os componentes filhos?
Os eventos
Ao clicar em um botão ou receber um determinado evento, o nosso componente está se comportando da forma esperada?
Casos extremos
No caso de uma lista, precisamos garantir como ela irá se comportar com uma lista vazia, com 5 itens, ou 1000 itens.
Agora sim
Sabendo isso, podemos finalmente fazer o nosso teste, vamos ver o primeiro caso, se o nosso componente UserView
está renderizando:
Estamos usando jest como nosso framework de teste e o vue-test-utils para auxiliar operações com os nossos componentes.
Na linha 7, estamos fazendo um shallowMount do nosso componente, isso quer dizer:
Vamos renderizar apenas o primeiro nível de dependências dele.
O vue-test-utils também disponibiliza um outro método chamado mount, no qual renderizamos a arvore completa de dependências.
Mas o shallowMount já é o suficiente para o nosso caso.
Na linha 10, estamos pegando o wrapper, que é uma representação do nosso componente, criado pelo vue-test-utils, e então estamos “tirando uma foto” do html do nosso componente, esse método html
existe graças ao vue-test-utils.
Ao rodar os testes npm run test:unit
temos a nossa primeira falha.
O componente ainda não existe, então chegamos na fase do TDD no qual podemos finalmente criar o nosso arquivo.
Escrevemos aqui uma representação mínima do nosso componente, e graças a isso, temos o nosso primeiro teste passando, rodamos então: npm run test:unit:watch
Mas o que raios então é esta snapshot?
Basicamente, o jest tirou uma “foto” do htm do nosso componente, se vermos nos diretórios, foi criada uma pasta __snapshots__
dentro de tests
Agora temos uma referência do nosso componente, e caso tenha qualquer tipo de alteração no html dele, o nosso teste irá falhar.
Faça um experimento, e altere o UserView.vue
e veja o teste falhar.
Podemos agora ver que, caso tenha alguma alteração no nosso html, precisaremos corrigir o erro, ou voltar ao estado original.
Caso a alteração seja intencional, podemos atualizar a snapshot, dizendo que esta versão será a nossa nova referência.
Para fazer isto, basta apertar u no terminal, e automaticamente a snapshot será atualizada 😄. Para ver mais opções, basta apertar w no terminal, que irá ser trazida uma listagem de opções do jest.
NUNCA mexa no arquivo de snapshot, este arquivo é gerado para você!
Resumo da obra
Neste primeiro artigo, fizemos:
- A introdução do que iremos fazer
- O planejamento da nossa aplicação
- Setup inicial do nosso projeto deixando apenas os arquivos mínimos a serem trabalhados
- Explicação do que testamos no front
- Criamos o nosso primeiro teste
Fiquem atentos que próxima semana estaremos nos aprofundando nos testes do nosso componente.
Muito obrigado pela atenção, se gostou, por favor, clique no 💚, e qualquer dúvida, sugestões ou correções sinta-se a vontade para me mandar uma mensagem, eu agradeço muuito 😄.
Meu Twitter: @DKuroski
Vejo você próxima semana 😄