Test Deeply Rendered Vue.js Components in Jest

Posted on Aug 28, 2017
Testing Vue.js components with Jest

You can find the content of this article updated to the most recent version of vue-test-utils and Jest on my book.

In Write the first Vue.js Component Unit Test in Jest we've seen how to use Shallow Rendering to test a component in isolation, preventing the components sub-tree from rendering.

But in some cases, we could want to test components that behave as a group, or molecules as stated in Atomic Design. Keep in mind that this apply to Presentational Components, since they're unaware of app state and logic. In most case, you'd want to use Shallow Rendering for Container components.

Adding a Message Component

For the case of a Message and MessageList components, apart from writing their own unit tests, we could 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 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();
  });
});

Btw, have you realized about 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 test shouldn't depend on each other.

Both mount and shallowMount use exactly the same API, the difference is in the rendering. I'll show you progressively the API along in this series.

If you run npm t you'll see the test are failing because the Snapshot doesn't match for MessageList.test.js. To regenerate them, run it with -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 can be side effects, since the children component hooks, such created and mount will be triggered, and there can be HTTP calls or other side effects there that we don't want to be called. If you wanna try what I'm saying, add to the Message.vue component a console.log 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 full example on Github.

Alex Jover

ALEX JOVER

Google Dev Expert, Vue team member, cats and dance lover. Find here all my teachings about web development, web performance and more.

Alex Jover Morales © 2018