Voltar para os posts

Como testar os seus componentes no Vue

30/05/2021

vuejavascriptjestteste unitário

Introduçao

Esse tutorial tem como objetivo ajudar as pessoas que ainda não tem nenhum conhecimento sobre testes unitários e querem entender o básico para testar componentes isolados, vamos abordar alguns assuntos como testes de prop, de eventos e slots.

The more effort I put into testing the product conceptually at the start of the process, the less I effort I had to put into manually testing the product at the end because less bugs would emerge as a result.

-- Trish Khoo

Essa frase resumi o porquê de eu começar a fazer testes, já trabalhei em alguns projetos e comecei a ter o sentimento de que eu perdia mais tempo testando manualmente a aplicação do que realmente desenvolvendo alguma coisa nova, resolvendo um bug ou refatorando o código.

Dessa forma eu resolvi procurar algum tipo de solução de testes para o front-end, me esbarrei com a biblioteca Vue Test Utils que auxilia os testes com componentes do Vue, usando como base o Jest.

Pré-requisitos

Antes de você começar a fazer algo, você precisa:

  • Do Node e Npm (ou Yarn) instalados na sua máquina
  • Do Vue CLI instalada na sua máquina
  • De algum conhecimento prévio com Vue
  • De algum conhecimento prévio com Jest

1º Passo - Criação do projeto

Nesse post, utilizaremos como base o projeto default do Vue CLI, pra criar vá para o terminal e escolha o que contém apenas o Babel e o ESlint, com isso você já vai ter todos os arquivos necessários do Vue.

Para mais informações sobre a criação de projetos, clique aqui.

Para vê o resultado final clique aqui.

2º Passo - Instalação das depêndencias

Para começar, existem algumas formas de instalar o Vue Test Utils, tanto na hora de você criar o seu projeto usando o vue create nome_do_projeto, como também instalando manualmente, seguindo o passo a passo do próprio site, aqui eu vou mostrar a segunda opção:

vue add unit-jest
npm install --save-dev @vue/test-utils

Com isso feito, você irá notar que houveram algumas modificações no seu projeto, no caso foram adicionados algumas depêndencias de desenvolvimento e um script para rodar os testes:

"scripts": {
    ...
    "test:unit": "vue-cli-service test:unit",
    ...
  },
  "devDependencies": {
    ...
    "@vue/cli-plugin-unit-jest": "~4.5.0",
    "@vue/test-utils": "^1.2.0",
  },

Também foi criado um arquivo jest.config.js e um arquivo example.spec.js no caminho test/unit/.

3º Passo - Utilização

você agora pode rodar o seguinte comando no terminal para visualizar todos os testes da sua apliacação:

npm run test:unit

Resultado:

Rodando testes pela primeira vez

4º Passo - Explicando alguns conceitos

O mundo de testes é bem grande e contém vários conceitos, eu provavelmente não vou conseguir explicar todos esses conceitos, mas você sempre pode olhar a documentação oficial e tirar suas próprias conclusões.

Com isso em mente, vou descrever alguns conceitos importantes:

  • ShallowMount

É um método que serve para renderização de componentes, porém ele não renderiza as depêndencias desse arquivo, um exemplo disso, seria um componente com vários filhos. Esse método ajuda a Stubar automaticamente os componentes, deve ser usado principalmente em componentes soltos.

O primeiro argumento esperado é o componente e o segundo argumento que é opcional é um objeto de opções que você pode ver cliquando aqui.

  • Mount

Também é um método que é basicamente o oposto do ShallowMount, é usado para renderizar o componente e não se preocupa se ele contém muitas depêndencias, deve ser usado em páginas com muitos elementos em uma apliacação real.

O primeiro argumento esperado é o componente e o segundo argumento que é opcional é um objeto de opções que você pode ver cliquando aqui.

  • Wrapper

É o nome utilizado para a convenção de um componente, ou seja, você pode criar um componente X e no teste, você irá ter um wrapper desse componente, contendo várias propriedades e métodos para auxiliar a execução e validação do teste.

Para saber mais clique aqui.

5º Passo - Testando props com um componente simples

Para utilizar como exemplo, eu criei um componente Botao.vue que ficou assim:

<template>
    <button :disabled="desativado" @click="acaoClique">
        <slot>
            {{ texto }}
        </slot>
    </button>
</template>

<script>
export default {
    props: {
        texto: {
            type: String
        },
        desativado: {
            type: Boolean
        }
    },
    methods: {
        acaoClique() {
            this.$emit('click');
        }
    }
}
</script>

Eu também criei um arquivo de teste chamado botao.spec.js e adicionei o primeiro teste:

import {
    shallowMount
} from '@vue/test-utils'
import Botao from '@/components/Botao.vue'

describe('Testando props', () => {
    it('Deve renderizar o botão com o texto passado', () => {
        const texto = 'Texto do botão';
        const wrapper = shallowMount(Botao, {
            propsData: {
                texto
            }
        });
        expect(wrapper.text()).toMatch(texto);
    })
})

Resultado:

Primeiro teste com um componente simples

Como vimos, o teste foi um sucesso. No código podemos ver que a estrutura é idêntica com a do Jest.

Com a utilização do método shallowMount citado no quarto passo, a gente usa o segundo parâmetro do método, passando então a propriedade propsData, no qual espera receber alguma prop do componente.

Criamos o wrapper contendo as informações do componente, e utilizando o método text() recuperamos o valor do primeiro elemento do componente, no final, comparamos o dado retornado com a variável que a gente utilizou para o teste, validando assim o teste.

6º Passo - Testando eventos com um componente simples

Nesse passo, veremos como testar a emissão de eventos em um componente, utilizaremos o componente do passo anterior:

... omitindo código anterior

describe('Testando eventos', () => {
    it('Deve emitir o evento de clique quando houver clique no botao', () => {
        const wrapper = shallowMount(Botao);

        wrapper.trigger("click");

        expect(wrapper.emitted().click).toBeTruthy();
    })
})

Resultado:

Segundo teste com um componente simples

Vamos analisar o código: novamente usamos o shallowMount para a criação do nosso wrapper, logo em seguida, usamos o método trigger para forçar uma emissão de evento em algum elemento do DOM.

Nesse caso, ele força o botão que existe no componente, se você quiser forçar algum emissão customizada deverá usar wrapper.vm.$emit('evento-customizado').

Logo em seguida, usamos a função emitted(), que retorna um objeto onde as chaves são os eventos e cada campo, contém uma array de array de valores que foram emitidos, podemos ver um exemplo retirado da documentação:

  {
    foo: [[ ], [123]]
  }

Com isso, verificamos se a chave click é truthy, validando então o teste escrito.

7º Passo - Testando slots com um componente simples

Nessa última parte vamos testar o slot:

... omitindo código anterior

describe('Testando slots', () => {
    it('Deve renderizar o texto que é passado no slot default', () => {
        const textoSlot = "Texto do slot";

        const wrapper = shallowMount(Botao, {
            slots: {
                default: textoSlot
            }
        })

        expect(wrapper.text()).toBe(textoSlot);
    })
})

Resultado:

Terceiro teste com um componente simples

Continuamos usando o shallowMount e dessa vez usamos a propriedade slots que aceita um objeto onde cada chave é o nome do slot, nesse caso usamos a chave default para indicar que a gente quer usar o slot padrão do componente.

Depois disso nós utilizamos a mesma maneira de validar o texto que a gente enviou.

Passo Extra - Alguns pontos de atenção

Em alguns momentos na hora de escrever os testes, nos vemos em situações aonde não sabemos o porquê de o teste não funcionar, com isso em mente vou tentar indicar alguns aspectos que podem ser os culpados.

  • Ação assíncrona

Em algums momentos você pode se deparar com uma ação que altera algum valor do DOM, sendo assim, você deverá usar o método nextTick() para que seja aguardada a alteração do valor, clique aqui para ler mais sobre.

  • Mount vs ShallowMount

Na maioria dos casos, o shallowMount() será a melhor opção, mas por um acaso você estiver testando algum tela com muitos componentes e ações diversas, o mount() servirá melhor, clique aqui para entender um pouco melhor.

  • Mocks e Stubs

Mocks e Stubs são muito usados em componentes que contém algum tipo de ação externa, seja alguma lib do Vue, como o Vuex ou até mesmo o Axios. Para ler sobre Stubs clique aqui e para ler sobre mocks, clique aqui.

Conclusão

Com o artigo chegando ao fim conseguimos observar alguns aspectos interessantes sobre os testes, nesse texto eu me propus a escrever sobre os tipos de testes mais básicos e simples, no entanto existem alguns cenários que eu acabei não conseguindo escrever sobre, porém no futuro eu pretendo escrever mais sobre esses casos que vão de ações assíncronas até testar depêndencias externas.

Referências

Feito com e Gatsby