Deep vs Shallow Rendering in Vue.js Tests

Alex Jover Morales

Alex Jover Morales

Mar 3, 2020
4 min read
Share on Twitter or LinkedIn

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.

Alex Adrian VueAmsterdam

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!

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

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.

Alex Jover Morales

Alex Jover Morales

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

Eduardo San Martín

Eduardo San Martín

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

Javier Martínez

Javier Martínez

Apr 14, 2019

Sponsors

VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Silver
Learning Partner