
@djirdehh
A Full Day of Vue.js

06. Testing
Testing
Testing can help reveal bugs before they appear, instill confidence in your web application, and make it easy to onboard new developers on an existing codebase.
Testing - Basics
Unit Testing
Tests are made to parts of an application in isolation.
End to End Testing
Tests focus on whether an application has been built appropriately from start to finish.
Two main ways to test web applications
2
1
Many unit test environments/suites exist
-
Mocha: A JavaScript testing framework. Allows us to specify our test suites with describe and it blocks.
-
Chai: A testing assertion library. Provides interfaces for us to create assertions for our tests (should..., expect..., assert...).
-
Jest: A JavaScript testing framework that comes with an assertion library, mocking support, snapshot testing, etc. with minimal to no configuration/set-up.
and many more....
Testing - Basics

new Calculator()
2 + 2 | we expect 4
5 - 3 | we expect 2
4 x 4 | we expect 16
Testing - Basics
describe('Calculator', () => { it('sums 2 and 2 to 4', () => {
...
});
it('subtracts 5 and 3 to 2', () => {
... }); });
describe functions segment each logical unit of tests.
it functions test each expectation we'd want to assert.
Testing - Basics
describe('Calculator', () => { describe('sum()', () => { it('sums 2 and 2 to 4', () => {
... }); });
describe('subtract()', () => {
it('subtracts 5 and 3 to 2', () => {
... }); }); });
Testing - Basics
describe('Calculator', () => { it('sums 2 and 2 to 4', () => {
const calc = new Calculator();
expect(calc.sum(2,2)).toEqual(4);
});
it('subtracts 5 and 3 to 2', () => {
const calc = new Calculator(); expect(calc.subtract(5,3)).toEqual(2); }); });
Testing - Basics
expect(...).toEqual(...);
Unique functions from the testing framework/assertion library (e.g. Jest) being used.
Testing - Basics
Testing - Basics
The Arrange, Act, Assert (AAA) pattern
describe('Calculator', () => { it('sums 2 and 2 to 4', () => {
const calc = new Calculator(); const sumResult = calc.sum(2,2); expect(sumResult).toEqual(4); });
});
Arrange
Act
Assert
Testing - Basics
We'll now look to test a basic Vue component.
list of todos
input to create new todo
element to remove certain todo
1
2
3
Simple version of TodoMVC
Testing - Vue Component

Testing - Vue Component
<template>
<div id="app">
<section class="todoapp">
<header class="header">
<h1 class="title">todos</h1>
<input class="new-todo"
placeholder="What needs to be done?"
v-model="newTodo"
@keyup.enter="addTodo">
</header>
<section class="main">
<ul class="todo-list">
<li class="todo"
v-for="(todo, index) in todos"
:key="index">
<div class="view">
<label>{{ todo }}</label>
<button class="destroy" @click="removeTodo(todo)"></button>
</div>
</li>
</ul>
</section>
</section>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
todos: [],
newTodo: ''
}
},
methods: {
addTodo() {
if (this.newTodo !== '') {
this.todos.push(this.newTodo);
this.newTodo = '';
}
},
removeTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1);
}
}
};
</script>
App.vue
describe('App.vue', () => {
it('should render correct initial content', () => {
...
});
});
Testing - Vue Component

Testing - Vue Component
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
// ...
});
});
App.spec.js
Testing - Vue Component
To assert the HTML content of our component - we need to have our component mounted().
Before we have our component mounted() , we can create the component constructor.
Testing - Vue Component
import Vue from "vue";
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
const Constructor = Vue.extend(App);
});
});
App.spec.js
Testing - Vue Component
import Vue from "vue";
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
const Constructor = Vue.extend(App);
const vm = new Constructor().$mount();
});
});
App.spec.js
Testing - Vue Component
import Vue from "vue";
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
const Constructor = Vue.extend(App);
const vm = new Constructor().$mount();
expect(vm.$el.querySelector(".title").textContent).toBe("todos");
expect(vm.$el.querySelector(".new-todo").placeholder).toBe(
"What needs to be done?"
);
});
});
App.spec.js
Testing - Vue Component
describe('App.vue', () => { it('should render correct initial content', () => {
...
});
it('should set correct default data', () => {
...
});
});
Testing - Vue Component
todos: [ ] ,
newTodo: ' '
import Vue from "vue";
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
// ...
});
it("should set correct default data", () => {
const initialData = App.data();
});
});
App.spec.js
Testing - Vue Component
import Vue from "vue";
import App from "./App";
describe("App", () => {
it("should render correct initial content", () => {
// ...
});
it("should set correct default data", () => {
const initialData = App.data();
expect(initialData.todos).toEqual([]);
expect(initialData.newTodo).toEqual("");
});
});
App.spec.js
Testing - Vue Component
vue-test-utils?
Testing - Vue Component
Testing - vue-test-utils
vue-test-utils is a utility library that provides useful methods that help make testing easier.
Testing - vue-test-utils
We're able to mount a component by simply doing:
const wrapper = mount(Component);
import { mount } from "@vue/test-utils";
Testing - vue-test-utils
const vm = wrapper.vm;
const html = wrapper.html();
const button = wrapper.find('button');
-
Access the component instance:
-
Retrieve component's html:
-
Find element (wrapper):
-
Get Props:
const propValue = wrapper.props('propKey');
-
Trigger Event:
wrapper.trigger('click');
-
Set Methods:
wrapper.setMethods({});
and a lot more...
Testing - vue-test-utils

Testing - vue-test-utils
.html()
.setProps()
.setData()
.setMethods()
.vm
component
wrapper
Testing - vue-test-utils
mount()
Creates a Wrapper that contains the mounted Vue component.
shallowMount()
Creates a Wrapper that contains the mounted Vue component, but with stubbed child components.
import { mount, shallowMount } from "@vue/test-utils";
import { mount } from "@vue/test-utils";
Testing - vue-test-utils
Tests the component in isolation.
shallowMount()
It's faster.
great to use when we want to focus on a single component...
Testing - vue-test-utils
import Vue from "vue";
import App from "./App";
describe("App.vue", () => {
it("should render correct initial content", () => {
const Constructor = Vue.extend(App);
const vm = new Constructor().$mount();
expect(vm.$el.querySelector(".title").textContent).toBe("todos");
expect(vm.$el.querySelector(".new-todo").placeholder).toBe(
"What needs to be done?"
);
});
it("should set correct default data", () => {
const initialData = App.data();
expect(initialData.todos).toEqual([]);
expect(initialData.newTodo).toEqual("");
});
});
App.spec.js
Testing - vue-test-utils
npm install @vue/test-utils --save-dev
Testing - vue-test-utils
import App from "./App";
import { shallowMount } from "@vue/test-utils";
describe("App.vue", () => {
it("should render correct initial content", () => {
...
});
it("should set correct default data", () => {
...
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
import { shallowMount } from "@vue/test-utils";
describe("App.vue", () => {
let wrapper = shallowMount(App);
it("should render correct initial content", () => {
...
});
it("should set correct default data", () => {
...
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
import { shallowMount } from "@vue/test-utils";
describe("App.vue", () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(App);
});
it("should render correct initial content", () => {
...
});
it("should set correct default data", () => {
...
});
});
Testing - vue-test-utils
import App from "./App";
import { shallowMount } from "@vue/test-utils";
describe("App.vue", () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(App);
});
it("should render correct initial content", () => {
expect(wrapper.find(".title").text()).toBe("todos");
expect(wrapper.find(".new-todo").element.placeholder).toBe(
"What needs to be done?"
);
});
it("should set correct default data", () => {
...
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
import { shallowMount } from "@vue/test-utils";
describe("App.vue", () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(App);
});
it("should render correct initial content", () => {
expect(wrapper.find(".title").text()).toBe("todos");
expect(wrapper.find(".new-todo").element.placeholder).toBe(
"What needs to be done?"
);
});
it("should set correct default data", () => {
expect(wrapper.vm.todos).toEqual([]);
expect(wrapper.vm.newTodo).toEqual("");
});
});
App.spec.js
Testing - vue-test-utils

input to create new todo
1
Testing - vue-test-utils
describe("App.vue", () => {
it("should render correct initial content", () => {
...
});
it("should set correct default data", () => {
...
});
describe("the user populates the text input field", () => {
...
});
});
Testing - vue-test-utils
describe("App.vue", () => {
...
describe("the user populates the text input field", () => {
it("should update the 'newTodo' data property", () => {
...
});
});
});
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field", () => {
it("should update the 'newTodo' data property", () => {
const inputField = wrapper.find(".new-todo");
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field", () => {
it("should update the 'newTodo' data property", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field", () => {
it("should update the 'newTodo' data property", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
expect(wrapper.vm.newTodo).toEqual("New Todo");
});
});
});
App.spec.js
Testing - vue-test-utils

list of todos
2
Testing - vue-test-utils
describe("App.vue", () => {
...
describe("the user populates the text input field and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
...
});
});
});
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
const inputField = wrapper.find(".new-todo");
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
inputField.trigger("keyup.enter");
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
inputField.trigger("keyup.enter");
expect(wrapper.vm.todos).toEqual(["New Todo"]);
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field", () => {
it("should update the 'newTodo' data property", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
expect(wrapper.vm.newTodo).toEqual("New Todo");
});
});
describe("the user populates the text input field and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
const inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
inputField.trigger("keyup.enter");
expect(wrapper.vm.todos).toEqual(["New Todo"]);
});
});
});
App.spec.js
Testing - vue-test-utils
import App from "./App";
describe("App", () => {
// ...
describe("the user populates the text input field", () => {
let inputField;
beforeEach(() => {
inputField = wrapper.find(".new-todo");
inputField.element.value = "New Todo";
inputField.trigger("input");
});
it("should update the 'newTodo' data property", () => {
expect(wrapper.vm.newTodo).toEqual("New Todo");
});
describe("and presses Enter", () => {
it("should add a new todo to the 'todos' array", () => {
inputField.trigger("keyup.enter");
expect(wrapper.vm.todos).toEqual(["New Todo"]);
});
});
});
});
App.spec.js
Testing - vue-test-utils
Mixins, Filters, & Testing - Chapter Summary!
-
vue-test-utils is Vue's official testing utility library.
-
Mount and shallow mount components with mount() and shallowMount() functions.
-
Mounted wrapper contains useful methods to help make testing easier:
wrapper.html();
wrapper.find();
wrapper.trigger();
wrapper.setData();
wrapper.setProps();
wrapper.setMethods();
Mixins, Filters, & Testing - Exercise 💪!
Testing
CodeSandbox
A Full Day of Vue.js Workshop - 06 Testing (slimmed)
By djirdehh
A Full Day of Vue.js Workshop - 06 Testing (slimmed)
- 292