Write and test your first Vue.js component with Jest
Tags: vue, webdev, tutorial
Published: 2023-05-08 16:50:55

Jest is a great developer tool as it provides all necessary tooling for making quick to write unit tests in a Vue.js application.

**Jest**, developed by Facebook, is a great companion testing framework which makes testing your programs a breeze. 

Below are just a few of its awesome features:

* Almost no config by default
* Very cool interactive mode
* Run tests in parallel
* Spies, stubs and mocks out of the box
* Built in code coverage
* Snapshot testing
* Module mocking utilities

Below we'll explore just how easy testing becomes with these tools by building and testing a Vue project step-by-step.

By the end, you'll see why so many developers have thrown away traditional testing strategies in favor of Jest. 

**Here’s what we’ll go through today:**
 
* [How to create a vue-test project](#create)
* [How to test a Vue component](#test)
* [Disadvantage of nested components](#disadvantage)
* [What is shallow rendering?](#shallow-rendering)
* [How to test a Vue component with shallow rendering](#shallow-test)
* [Wrapping up and Resources](#end)

<br>

<a name="create"></a>

## How to create a vue-test project

Let's start by creating a new project using `vue-cli`. When prompted, answer "NO" to all yes/no questions.

```cpp
npm install -g vue-cli
vue init webpack vue-test
cd vue-test
```

Then, we'll need to install some dependencies.

```cpp
# Install dependencies
npm i -D jest vue-jest babel-jest
```

`jest-vue-preprocessor` allows Jest to understand `.vue` files, and `babel-jest` for the integration with the transcompiler software, **Babel**.

Next, install `vue-test-utils` from the package manager, `npm`.

```cpp
npm i -D vue-test-utils
```

Now that we have all our tools working, add the following Jest configuration in the `package.json`.

```cpp
...
"jest": {
  "moduleNameMapper": {
    "^vue$": "vue/dist/vue.common.js"
  },
  "moduleFileExtensions": [
    "js",
    "vue"
  ],
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
    ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
  }
}
...
```

The `moduleFileExtensions` will tell Jest which extensions to look for, and `transform` determines which preprocessor to use for a file extension.


<br>
 
<a name="test"></a>

## How to test a Vue component

>**Note on Single File Restriction**
>
>I'll be using Single File Components for this example, if split to seperate files results may vary.

Below, we'll begin adding a `test` script to our `package.json`.

To add our test, first create a `MessageList.vue` component under `src/components`.

```cpp
<template>
    <ul>
        <li v-for="message in messages">
            {{ message }}
        </li>
    </ul>
</template>

<script>
export default {
  name: 'list',
  props: ['messages']
}
</script>
```

Then update your `App.vue` to look like so. This will complete our program so we can move on to a test folder.

```cpp
<template>
  <div id="app">
    <MessageList :messages="messages"/>
  </div>
</template>

<script>
import MessageList from './components/MessageList'

export default {
  name: 'app',
  data: () => ({ messages: ['Hey John', 'Howdy Paco'] }),
  components: {
    MessageList
  }
}
</script>
```

We have already a couple of components that we can test. Let's create a `test` folder under the project root, and a `App.test.js`.


```cpp
import Vue from "vue";
import App from "../src/App";

describe("App.test.js", () => {
  let cmp, vm;

  beforeEach(() => {
    cmp = Vue.extend(App); // Create a copy of the original component
    vm = new cmp({
      data: {
        // Replace data value with this fake data
        messages: ["Cat"]
      }
    }).$mount(); // Instances and mounts the component
  });

  it('equals messages to ["Cat"]', () => {
    expect(vm.messages).toEqual(["Cat"]);
  });
});
```

Right now, if we run `npm test` (or `npm t` as a shorthand version), the test should run and pass. Since we're modifying the tests, let's better run it in **watch mode**:

```cpp
npm t -- --watch
```

<br>
 
<a name="disadvantage"></a>

## Disadvantage of nested components

While a great start, this test is currently too simple. 

Let's change our rest to check that the output is the expected as well. For that we can use the amazing Snapshots feature of Jest, that will generate a snapshot of the output and check it against in the upcoming runs. 

Add code below after the previous `it` in your `App.test.js`.

```cpp
it("has the expected html structure", () => {
  expect(vm.$el).toMatchSnapshot();
});
```

Running the test now will create a `test/__snapshots__/App.test.js.snap` file.

Let's open it and inspect it.

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

exports[`App.test.js has the expected html structure 1`] = `
<div
  id="app"
>
  <ul>
    <li>
      Cat
    </li>
  </ul>
</div>
`;
```

Another good step forward, but there is a big problem here: the `MessageList` component has been rendered as well. 

This demonstrates a key takeaway: **unit tests must be tested as an independent unit**.

 In other words, in  `App.test.js` we want to test the `App` component and don't care at all about anything else.

This can lead to several problems. Imagine for example, that the children components (`MessageList` in this case) performed side effect operations on the `created` hook, such as calling `fetch`, which causes state changes.

This would mean that our test would alter our component to succeed, breaking repeat executions.

Luckily, **Shallow Rendering** solves this nicely.

<br>
 
<a name="shallow-rendering"></a>

## What is shallow rendering?

Shallow Rendering is a technique that assures your component is rendered without children. This is useful for:

* Testing only the component you want to test and leaving other intact
* A void side effects that children components can have, such as making HTTP calls, calling store actions, etc.

> Shallow rendering works by stubbing the `components` key, the `render` method and the lifecycle hooks, all behind the scenes.

<br>
 
<a name="shallow-test"></a>

## How to test a Vue component with shallow rendering

`vue-test-utils` provide us with Shallow Rendering among other features. Look below to see how we can apply shallow rendering in our test script.

```cpp
import { shallowMount } from "@vue/test-utils";
import App from "../src/App";

describe("App.test.js", () => {
  let cmp;

  beforeEach(() => {
    cmp = shallowMount(App, {
      // Create a shallow instance of the component
      data: {
        messages: ["Cat"]
      }
    });
  });

  it('equals messages to ["Cat"]', () => {
    // Within cmp.vm, we can access all Vue instance methods
    expect(cmp.vm.messages).toEqual(["Cat"]);
  });

  it("has the expected html structure", () => {
    expect(cmp.element).toMatchSnapshot();
  });
});
```

When running Jest in watch mode, you'll see the test passes, but the Snapshot doesn't match. 

Press `u` to regenerate the snapshot. 

Open and inspect it again:

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

exports[`App.test.js has the expected html structure 1`] = `
<div
  id="app"
>
  <!--  -->
</div>
`;
```

Notice that no children components were generated. This means that we successfully tested the `App` component fully isolated from the component tree. We can now test our app without fear of calling or altering any of our other components.


To accomplish a similar test with shallow rendering, you can implement the `MessageList.test.js` test as follows.

```cpp
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();
  });
});
```

<br>
 
<a name="end"></a>

## Wrapping up and Resources

To see other time saving tips and walkthroughs on testing with Jest, see Educative's course [Testing Vue Components with Jest](https://www.educative.io/courses/testing-vuejs-components-with-jest?eid=5082902844932096). 

You'll build on what you learned here today, reviewing some expert Jest techniques and completing more hands-on walkthroughs of testing various types of components. 

By the end, you'll be a Vue and Jest expert able to build professional, comprehensive test scripts for any components used in modern JavaScript programs.

## Continue Reading on Educative
* [Sass Tutorial: Unit Testing with Sass True](https://www.educative.io/blog/sass-tutorial-unit-testing-with-sass-true?eid=5082902844932096)
* [Comparing the most popular frontend JavaScript frameworks](https://www.educative.io/blog/compare-popular-frontend-javascript-frameworks?eid=5082902844932096)

### Start a discussion
What are some other helpful Jest techniques? Was this article helpful? Let us know in the comments below!