87. Testing components with Vue Test Utils


Resources


Our objective in this module is to learn how to unit test a Vue.js app. But so far, we've only seen how to test a regular JavaScript function.

An important to understand that, in a component-based app, a "unit" is generally not a single function, but is instead a whole component.

So, how do we unit test a component? At a high level it's the same concept as unit testing a function - we provide particular inputs and assert a particular output.

We will, however, need a way to mount a component in isolation from the app to which it belongs. We'll also need a way of supplying the inputs, which could include props, user input etc, and a way of testing the output, which will usually be the rendered markup, but could also be events or something else.

Vue Test Utils

This is where the Vue Test Utils library will be required, as it can do all the things that I've just described.

In this video, we'll learn how to use Vue Test Utils to unit test a component, so that we have the knowledge to start unit test testing PrintBay in the following videos.

Testing components

Let's begin by deleting the contents of our example.spec.js file again.

Now, let's create an example component that we can practice testing.

We'll make it a very simple component which displays a greeting. So let's create a const displayGreeting and assign it an object that will contain the component definition.

Let's give it a template property and assign to this "<div>Hello, {{ name }}</div>". As you can see, the template includes a text interpolation for a property name.

Next, we'll give the component a data property and assign to it a function that returns an object. We'll now create the property name and assign to it a value like "George" or whatever you like.

test/unit/client/example.spec.js

const displayGreeting = {
  template: "<div>Hello, {{ name }}</div>",
  data: () => ({ name: "George" })
};

Test

Let's now create a test block where we're going to write a unit test for this component. So we'll call the global describe and pass to it the component name "displayGreeting" as the first argument.

For the second argument, we'll create a function, and inside that, we'll define a new test by calling it. The first argument will be "should display greeting", and the second argument will be a function as well.

test/unit/client/example.spec.js

...

describe("displayGreeting", () => {
  it("should display greeting", () => {})
});

Mounting a component

Unlike a regular JavaScript function, a component can't simply be tested on its own. We'll need to first mount our component using Vue Test Utils.

So let's go to the top of the file and put import { mount } from "@vue/test-utils";.

The mount method is used to create an instance of the component in a virtual DOM. This allow us to test the component without the hassle of compiling the whole app in a browser.

The mount method returns a wrapper which I'll talk about in a moment. So in our test, let's begin creating the test logic by put const wrapper = mount(displayGreeting);. As you can see, the mount method takes a Vue component as it's first argument.

test/unit/client/example.spec.js

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

const displayGreeting = {
  template: "<div>Hello, {{ name }}</div>",
  data: () => ({ name: "George" })
};

describe("displayGreeting", () => {
  test("should display greeting", () => {
    const wrapper = mount(displayGreeting);
  });
}

Wrapper

The wrapper we get back from the mount method is a fully-functioning Vue instance, and includes a number of API methods that allow us to interact with the component.

Let's use the API wrapper method text to get the text content of the rendered component. So we'll put const text = wrapper.text();. We'll then console log the output so we can check what we got, so let's put console.log(text);.

test/unit/client/example.spec.js

test("should display greeting", () => {
  const wrapper = mount(displayGreeting);
  const text = wrapper.text();
  console.log(text);
});

Let's now run the test.

You'll see it passes, although we don't yet have any assertions yet. And you'll also notice the text in the console "Hello, George", which is the result of our console log.

Assertion

Remember that the point of a unit test is to ensure a particular output is produced by a given input. In the case of this displayGreeting component, there are no possible inputs as there are no buttons or props or any other way to provide input for this component. So you can think of this one just like a function that takes no arguments.

However, this component does have an output, which is the rendered markup. We've used the text method to extract text from the markup, so let's make an assertion about that. So we'll delete the console log, and instead put expect(text).toBe("Hello, George").

test/unit/client/example.spec.js

test("renders the text Hello, George", () => {
  const wrapper = mount(displayGreeting);
  const text = wrapper.text();
  expect(text).toBe("Hello, George");
});

Let's run the test again.

And hopefully, you'll see a green tick and the message "should display greeting". If you do, it means you've just successfully created your first component unit test!

Let's delete our example test file now, as we'll begin work on testing PrintBay components in the next video. So go:

$ rm -rf tests/unit/client/example.spec.js

With that done, I'll see you in the next video.

Discussion

0 comments