Chapter 2 – Testing Vue.js Components with Jest

Chapter 2

Test Deeply Rendered Vue.js Components

So far, we've seen how to use shallow rendering to test a component in isolation, preventing the component's sub-tree from rendering.

But in some cases, we want to test components that behave as a group, or molecules (http://atomicdesign.bradfrost.com/chapter-2/#molecules), as stated in Atomic Design. Keep in mind that this applies to Presentational Components (https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) since they're unaware of app state and logic. In most cases, you'd want to use shallow rendering for container components.

Adding a Message Component

In the case of Message and MessageList components, apart from writing their own individual unit tests, we might want to test them both as a unit as well.

Let's start by creating components/Message.vue:

<template>

  <li class="message">{{ message }}</li>

</template>

<script>

  export default {

    props: ["message"]

  };

</script>

And update components/MessageList.vue to use it:

<template>

  <ul>

    <Message :message="message" v-for="message in messages" />

  </ul>

</template>

<script>

  import Message from "./Message";

  export default {

    props: ["messages"],

    components: {

      Message

    }

  };

</script>

Testing MessageList with a Message Component

To test MessageList with deep rendering, we just need to use mount instead of shallowMount in the previously created test/MessageList.test.js:

import { mount } from "@vue/test-utils";

import MessageList from "../src/components/MessageList";

describe("MessageList.test.js", () => {

  let cmp;

  beforeEach(() => {

    cmp = mount(MessageList, {

      // Be aware that props is overridden using 'propsData'

      propsData: {

        messages: ["Cat"]

      }

    });

  });

  it('has received ["Cat"] as the message property', () => {

    expect(cmp.vm.messages).toEqual(["Cat"]);

  });

  it("has the expected html structure", () => {

    expect(cmp.element).toMatchSnapshot();

  });

});

By the way, have you noticed the beforeEach thing? That's a very clean way to create a clean component before each test, which is very important in unit testing since it defines that tests shouldn't depend on each other.

Both mount and shallowMount use exactly the same API; the difference is in the rendering. I'll progressively show you more of the API as we move along in this series.

If you run npm t, you'll see the test is failing because the Snapshot doesn't match MessageList.test.js. To regenerate it, run with the -u option:

npm t -- -u

Then, if you open and inspect test/__snapshots__/MessageList.test.js.snap, you'll see the class="message" is there, meaning the component has been rendered:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports['MessageList.test.js has the expected html structure 1'] = '

<ul>

  <li class="message">

    Cat

  </li>

</ul>

';

Keep in mind to avoid deep rendering when there could be side effects, since the children component hooks, such as created and mount, will be triggered, and there could be HTTP calls or other side effects there that we don't want to be called. If you want to try out what I'm saying, add a console.log to the Message.vue component, in the created hook:

export default {

  props: ["message"],

  created() {

    console.log("CREATED!");

  }

};

Then, if you run the tests again with npm t, you'll see the "CREATED!" text in the terminal output. So, be cautious.

You can find the code and examples for this chapter on GitHub (https://github.com/alexjoverm/vue-testing-series/tree/Test-fully-rendered-Vue-js-Components-in-Jest).