“gray laptop computer turned on” by Rich Tervet on Unsplash

Working an application in Vue.js with TDD — An extensive guide for people who have time — part 1

Daniel Kuroski
magnetis backstage
Published in
8 min readOct 10, 2018

--

After all, teaching how to mount an application without tests is very easy

This is the first in a series of articles:

If you want to read it in pt-BR, check it out here.

If you are curious, go directly to the repository with the final code:

In case you’ve decided do go over the full tutorial, let’s go! 🚀

During the VueJS Summit 2018 workshops I talked to Edd Yerburgh in person and showed him the way I was testing my applications, and after some encouragement, here I am, writing this article 😅

I hope to show how easy it is to test on the front, mainly how easy it is to test an application with Vue.js!

This tutorial has many images and a certain density of concepts, that’s why I recommend a calm reading in case you don’t have the tool’s base.

What we are going to do

Our application

The project will be very simple. We are going to make an application that communicates with the Github API, searching for a user from a typed username.

It may seem a small project but in it we are going to see many kinds of tests we find in a Vue.js application development. Here we are going to test:

  • Components
  • Vuex
  • Services

In this project we are going to apply the TDD technique!

TDD

We are going to write a test that will fail and then make a minimum effort to make it pass. Finally, we are going to refactor it if necessary, repeating this until we finalize our application.

One of the advantages of this technique is that we end up having much faster feedbacks allowing us to work with much smaller cycles among the alterations during our project’s development.

TDD & Traditional Approach

It may seem difficult to apply the TDD in the beginning because it demands a mindset change, as we are writing tests before writing a production code.

I want to remind you here that we are not meant to strictly follow everything that is proposed, but for this project I want to show that this can be something simple to be done.

Modelling the application

First of all, let’s plan how we are going to make our application.

Application components

We are going to brake it into three components:

  • UserView — “smart” component, responsible for making the communication with the store and loading our presentation components
  • VUserSearchForm — “dumb” components, responsible for rendering the form and also for transmitting a message to the parent component with the research term
  • VUserProfile — “dumb” component, responsible for rendering our researched user information

We are also going to count with a service to make requests for the Github API.

Github API — https://developer.github.com/v3/users/
Get your coffee and let’s get started

Download the vue-cli and let’s create our project:

npm i -g @vue/cli
vue create tdd-app

Below you have the features I’ve chosen. Choose the most convenient to you. I may cover E2E tests on a next article, who knows?

Selected options for this project
Wait for everything to finish installing and we will be with our project ready to start

Let’s propose a challenge: we are only going to run the npm run serve when we finish our application.

Let’s clean the project

A project through the Vue CLI ends up bringing some initial files. Let’s remove everything we don’t need in this first moment.

Remove:

  • src/store.js
  • src/assets/logo.png
  • src/components/HelloWorld.vue
  • src/views/About.vue
  • src/views/Home.vue
  • tests/unit/HelloWorld.spec.js

Clean 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>

Clean 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: []
})

Create a file to put in our 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,
})

We created the files: src/store/state.js src/store/actions.js src/store/mutations.js and all of them have the same piece of code above:

export default {}

We added a npm script to observe our tests on package.json

..."test:unit": "vue-cli-service test:unit",
"test:unit:watch": "vue-cli-service test:unit --watchAll"

And finally, we are going to install some dependencies we are going to use in the project

npm i -d axios
npm i -D flush-promises nock

Creating our first test

Now we can start creating our tests. Let’s start by our first component, the UserView, remembering that we are using jest as our tests’ framework.

This will be a smart component, responsible for carrying all the other screen components, and it will make the communication with the store to make the Github user’s search.

Let’s create then the file: tests/unit/UserView.spec.js

describe('UserView', () => {
it('works', () => {})
})

And we can run the tests: npm run test:unit

Our first test

But what exactly do we test in our components?

We can test many things, but we can base ourselves in the following topics:

If the component renders

We need to guarantee that at least the component is rendering correctly.

If it renders the right thing

If we guarantee that the component renders, then we can test if it is rendering the right thing. Our component has a button and an input, or it contains a button and a comment saying “Input will be implemented in v2”.

Its binds

We tested all possible binds. If our component passing the right props to its son components?

The events

By clicking a button or receiving certain event, is our component behaving expectedly?

Extreme cases

In the case of a list, we need to guarantee how it will behave with an empty list, a list with 5 items, or 100 items.

Now, yes

By knowing this, we can finally make our test. Let’s see the first case, if our UserView component is rendered:

UserView.spec.js — WRITE

We are using jest as our test framework and the vue-test-utils to help operations with our components.

On line 7, we are making a shallowMount of our component. That means:

Let’s render only the first level of its dependencies

Shallow mount renders only our component’s first level

The vue-test-utils also provides another method called mount, in which we render the complete dependencies tree.

Here we fully render the whole components’ tree from the rendering component

But the shallowMount is already enough for our case.

On line 10, we are taking the wrapper, which is a representation of our component, created by the vue-test-utils, and then we are “taking a picture” of our component’s html. This html exists thanks to the vue-test-utils.

By running the npm run test:unit we have our first error

RED

The component still doesn’t exist. Then we get to the TDD phase where we can finally create our file.

Create— src/views/UserView.vue

Here we have written a minimum representation of our component, and thanks to this, we have our first test passing, running then: npm run test:unit:watch

GREEN

But what the hell is this snapshot, exactly?

Basically, jest took a “picture” of our component’s htm and if we check in the directories, a file __snapshots__ was created inside tests

Our first snapshot

Now we have a reference of our component and in case there is any kind of alteration on its html, our test will fail.

Make a test, change the UserView.vue and see the test failing

src/views/UserView.vue
Our test failing due to the html alteration

Now we can see that, in case there is any alteration in our html, we need to correct the error or go back to the original status.

In case the alteration is intentional we can update the snapshot, saying that this version will be our new reference.

Snapshot testing

To do this, you only need to press u on the terminal and the snapshot will be updated automatically 😊. To see more options, you only need to click w on the terminal that a list of jest options will open.

Updated snapshot, GREEN
The snapshot file is updated automatically

NEVER touch on a snapshot file. This file is generated for you!

Overview

summing up

In this first article, we did:

  • The introduction of what we will do
  • Planning our application
  • Initial setup of our project leaving only the minimum files to be worked
  • Explanation of what is tested on the front
  • Created our first test

Stay tuned to next week we will be deepening in the tests of our component and we will end up integrating with the store.

Thanks for the attention, if you liked, please click on the 💚, and any questions, suggestions or corrections feel free to send me a message, I thank you very much 😄.

My Twitter: @DKuroski

See you next week 😄

--

--