preface

As a programmer, there’s nothing worse than an app that crashes just before it goes live when you find out your code has changed. The only way to ensure that your application works is to test it. So it’s important to test your application thoroughly.

Efficient testing methods can speed up development, improve code quality, and find and remove bugs in code as early as possible. Test-driven development (TDD) is a workflow in which you write tests before you write code, that is, you write tests that ensure that components work properly before you write code.

Unit testing is the process of running tests on the smallest unit of an application. Usually a function, but in VUE, a component is also a unit because a component is essentially a function.

Here is a brief description of how to use JEST to unit test VUE. If you are not familiar with JEST and VUE, check out the official website.

The sample code is on Github

Unit tests of components

A unit is the smallest testable part of an application. In VUE, components and functions are testable units.

Carrying test environment

This is available for new projectsVUE-CLITool creation project (version shown in figure)

Simply ☑️Unit Testing and select JEST as the Testing framework when selecting the configuration.

For existing projects (for @vue/ CLI) you want to add jEST test modules. Running the following command line will help us install the JEST module.

vue add unit-jest
Copy the code

If you are a good hands-on student, you can also build the Test environment by yourself, for example, Vue Test Utils

Okay, now you’re ready to unit test.

Mount components

When importing a VUE component, it is just an object or function with a rendering function and some properties. To test the behavior of a component, you first start it and start the rendering process. According to VUE, you need to mount components.

To mount the component, you need to convert the component option to a VUE constructor. The component option object is not a valid constructor, it’s just a normal JavaScript object. A Vue constructor can be created from the options using the vue.extend method:

import Vue from 'vue';
import Home from '@/views/Home.vue';
const Ctor = Vue.extend(Home);
Copy the code

At this point, we can use the new operator to create an instance:

const vm = new Ctor();
Copy the code

Typically, VUE uses the EL option to find the DOM nodes added to the render in the document. However, the normal component constructor does not have the EL option, so it does not automatically mount and generate a DOM node when creating an instance. You need to manually call the $mount method:

const vm = new Ctor().$mount()
Copy the code

When $mount is called, VUE generates DOM nodes that can be accessed in tests using the $EL attribute in the example:

expect(vm.$el.textContent).toContain('Welcome to Your Vue.js App')
Copy the code

VUE creates a DOM tree using DOM methods. This does not mean that unit tests of VUE components must be run in a browser environment. By default, Jest runs tests in the browser environment created by the JsDOM library. Jsdom is a DOM implementation written entirely with JavaScript running in the DOM.

import Vue from 'vue'; import Home from '@/views/Home.vue'; describe('Home.vue', () => { it('renders msg when mounted', () => { const msg = 'Welcome to Your Vue.js App'; // Create a new Vue constructor with the Home option const Ctor = vue.extend (Home); // create a new Vue instance and mount it const vm = new Ctor().$mount(); Expect (vm.$el.textContent).tocontain (MSG)})}Copy the code

runyarn run test:unit, passed the test

useVue Test Utils

Mounting components requires creating their own constructors and mounting them manually. Instead of writing this code yourself, use the Vue Test Utils library to help.

The Vue Test Utils library makes unit testing of Vue components much easier. It contains helper methods to mount, interact with, and assert component output.

Vue Test Utils exports a mount method that, upon receiving a component, mounts it and returns a wrapper object containing the mounted component instance VM. The wrapper object is returned instead of the VM instance directly because the wrapper contains more than just the instance VM, but also helper methods. One such method is text, which returns the textContent of the instance.

Modify the Test you just did using the Vue Test Utils library

import { mount } from '@vue/test-utils'; import Home from '@/views/Home.vue'; describe('Home.vue', () => { it('renders msg when mounted', () => { const msg = 'Welcome to Your Vue.js App'; // Use the mount method to mount the component const wrapper = mount(Home); Expect (wrapper.text()).tocontain (MSG)})})Copy the code

useshallowMount

In addition tomountMethod,Vue Test UtilsIt also contains ashallowMountMethods.shallowMountDon’t likemountRenders the entire component tree, which renders only one layer of the component treemountSimilar,shallowMountMount a component and return a wrapper. The difference is,shallowMountStub all child components before mounting them.

ShallowMount ensures that a component is tested independently, helping to avoid confusing results with the rendering output of factor components during testing.

describe('Home.vue', () => { it('renders msg when mounted', () => { const msg = 'Welcome to Your Vue.js App'; // Use the shallowMount method to mount the component const wrapper = shallowMount(Home); Expect (wrapper.text()).tocontain (MSG)})})Copy the code

Output test

testprop

When writing unit tests for a component, you need to provide the component with input data received in the build environment. If a component receives a prop in production, it needs to be provided to the component when it is mounted to test.

Pass prop to the component as an option object using Vue Test Utils:

import { shallowMount } from '@vue/test-utils'; import Hello from '@/components/HelloWorld.vue'; describe('HelloWorld.vue', () => { it('renders msg when mounted', () => { const msg = 'hello, world'; // Use the shallowMount method to mount the component const wrapper = shallowMount(Hello, {propsData: {MSG}}); Expect (wrapper.text()).tocontain (MSG)})})Copy the code

Run YARN Run test:unit. The test passes.

The wrapper text method returns all the text rendered by the component. ToContain verifier checks whether a value contained in its examination of a certain position in the string, it is a bit like string. The prorotype. Includes methods.

As in the example above, the MSG variable in props is rendered on the < H1 > tag. There is no need to match all the text under the component, just test the text on the < H1 > tag. You can use the wrapper’s find method.

The find method gets a wrapper for each node in the render output, and find searches for the render output of the first node that matches the selector and returns the wrapper contained for the matching node.

Expect (wrapper.find('h1').text()).tocontain (MSG)Copy the code

Not all prop render text. So also check that the component instance receives the correct prop. You can use the props method.

The props method is a wrapper method. It returns an object containing a wrapper component instance and their value PROP.

expect(wrapper.props().msg).toBe(msg)
Copy the code

Use the toBe matcher to check that all rendered text of the component violates this rule.

You can also check that the current component is transmitting values correctly

const wrapper = shallowMount(fatherComponent)
expect(wrapper.find(ChildComponent).props().propA).toBe('example')
Copy the code

It is important to note here that if a component does not declare to receive a prop, prop is not added to the Vue instance.

Testing DOM properties

In the Vue Test Utils wrapper, there is an attribute method that returns component property objects. You can use this object to test property values

const a = wrapper.find('a');
expect(a.attributes().href === 'http://cli.vuejs.org').toBa(true)
Copy the code

Error message: Expected istrueIs returnedfalse. This is aBooleanAssert that such information is not clear as to why the test failed, so should be avoidedBooleanAssertions. Value assertions should be used insteadThis makes it very clear where the problem is causing the test to fail.

Test the style

In the Vue Test Utils wrapper, there is a classes method that returns an array of classes. You can assert this to see if the element has a class.

expect(a.classes()).toContain('firstA')
Copy the code

The toContain filter not only checks if a string contains another string, but also compares values in arrays.

Testing inline styles is generally worthless, but sometimes you have to test an inline style. For example, the progress bar component dynamically adds an inline style. You need to access the wrapper element directly and get the style attribute value.

Each wrapper contains an Element attribute, which is a reference to the DOM root node that the wrapper contains. You can use it to access inline elements

expect(a.element.style.fontSize).toBe('14px')
Copy the code

At the end

For reasons of space, this test tour ended on the first day and will continue next time. After reading, if you find it helpful, please give a thumbs-up and support.

For more articles, please go to Github, if you like, please click star, which is also a kind of encouragement to the author.