Deep vs Shallow Rendering in Vue.js Tests
What a nice feeling to get to write a tip right after the Vue.js Amsterdam! It was a boost, thanks to everyone that were so kind, friendly and curious about VueDose. Just so you know, if you'd like to write a tip here, just let me know!
To give you an impression on how Vue Amsterdam went, just see this picture taken by my friend GustoJS and his amazing camera.
Now let's get serious and start with the tip!
Testing is still one of the most controversial dev topics, and deep vs shallow rendering is no exception. In this tip I want to make my point on why and when to use each of them.
# Deep Rendering
Deep rendering, as the name states, renders all component tree given a root component.
In order to illustrate it, given this UserList.vue
component:
<template>
<ul>
<li v-for="user in users" :key="user">
{{ user }}
</li>
</ul>
</template>
<script>
export default {
props: {
users: Array
}
};
</script>
That you use in an App.vue
component like this:
<template>
<div>
<h3>User List</h3>
<UserList :users="['Rob Wesley']" />
</div>
</template>
<script>
import UserList from "./UserList";
export default {
components: { UserList }
};
</script>
Then it will give us the combined DOM Tree of both components:
<div>
<h3>User List</h3>
<ul>
<li>
Rob Wesley
</li>
</ul>
</div>
In order to check that, you can use Jest Snapshots. If you don't know much about Snapshots, check the article The power of Snapshot Testing that goes deeper into them.
When using @vue/test-utils, the official Vue.js testing library, you can perform deep rendering by using the mount
method.
With these clues, you can imagine the previous snapshot was taken from a test with a shape like this:
import { mount } from "@vue/test-utils";
import App from "@/App";
describe("App.vue", () => {
it("Deeply renders the App component", () => {
const wrapper = mount(App);
expect(wrapper.html()).toMatchSnapshot();
});
});
# Shallow Rendering
Opposite to deep rendering, shallow rendering only renders the component that you're testing without going into deeper levels.
To implemente shallow rendering, you can use the shallowMount
method from @vue/test-utils.
If you rewrite the previous test to use shallow rendering:
import { shallowMount } from "@vue/test-utils";
import App from "@/App";
describe("App.vue", () => {
it("Shallow renders the App component", () => {
const wrapper = shallowMount(App);
expect(wrapper.html()).toMatchSnapshot();
});
});
You'll see that the generated snapshot is:
<div>
<h3>User List</h3>
<userlist-stub users="Rob Wesley"></userlist-stub>
</div>
What happened? Basically Jest has created the <userlist-stub>
tag automatically instead of creating and rendering the UserList component.
Notice one point: the UserList component wasn't even created, meaning the component isn't used at all. Not their props, not their lifecycle hooks... nothing. You'll see now why that's important.
# What to Use and When
Taking back some testing theory, a test should be:
- Independant from others
- Focus on testing one thing
- Easy to maintain and stable over the time
- Valuable
And as you may see already, when you use deep rendering you're already violating the first three points, since every time a child component changes, you'll test will fail.
Additionally, imagine a child component performs side effects, like interacting with the store or calling an API. That could be even worse since the results might be unexpected.
That's why, my take on this is: Use shallowMount most of the time.
The question is: When not to use it?. I'll use mount
just in those cases that you're testing a group of components as a unit, treating them as molecules.
Think of UserList
and UserListItem
, or Tab
, TabGroup
and TabItem
. For those cases, it makes sense to use deep rendering when you want to test the interaction of the whole group working together.
# Follow Up
To end up I wanted to share that I'll be giving the workshop Vue.js Testing for Everyone in Vue Day Italy, Verona, on 4th April.
In that workshop you'll be able to learn all the techniques and best practices to test a Vue.js App, step by step and in the most practical way. Definitely we'll cover this content in a much deeper way.
That's it for today's tip!
Related Articles
Hybrid Rendering: the secret way to smoothly test Vue.js components
Find out how to combine Deep and Shallow Rendering in order to achieve a flexible solution to test your Vue.js combining the best of both worlds.
Mar 7, 2022
Quick Content Testing using Snapshots in Vue.js
Useful tip about how to use snapshot testing in Vue.js the right way and have consistent and coherent tests in your applications
May 28, 2019
Testing logic inside a Vue.js watcher
Tutorial on how to test the logic of a vue.js component watcher instead of testing the framework
Apr 14, 2019
Sponsors
VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.