Making: jest/unit

Let’s dive right into the subject and learn Vue Test Utils(VTU) step by step by building a simple example Todo App and writing Test cases

This summary will cover the following:

  • Mount Mount components
  • Find Find element
  • Fill in the form
  • Trigger event

start

First of all,Setting up the project environmentAnd selectUnit Testing, here we takeVue3.0 TypescriptProject Examples:

TodoApp.vue
<template>
  <div>
    <div
      v-for="todo in todos"
      :key="todo.id"
      data-test="todo"
      :class="[ todo.completed ? 'completed' : '' ]"
    >
      {{ todo.text }}
      <input
        type="checkbox"
        v-model="todo.completed"
        data-test="todo-checkbox"
      />
    </div>

    <form data-test="form" @submit.prevent="createTodo">
      <input data-test="new-todo" v-model="newTodo" />
    </form>
  </div>
</template>

<script lang="ts">
import { Options, Vue } from 'vue-class-component';

@Options({
  props: {
    msg: String}})export default class TodoApp extends Vue {
     newTodo=' ';
      todos=[
        {
          id: 1.text: 'Learn Vue.js 3'.completed: false}]createTodo() {
      this.todos.push({
        id: 2.text: this.newTodo,
        completed: false}}})</script>
Copy the code

First test case

First we write our first test case to verify that the Todo App is rendered. Let’s take a look at the test case first and discuss each part later:

Complete TodoApp. Spec. Js
import { mount } from '@vue/test-utils'
import TodoApp from '@/components/TodoApp.vue'
test('creates a todo'.async() = > {const wrapper = mount(TodoApp)
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)
  
    await wrapper.get('[data-test="new-todo"]').setValue('New todo')
    await wrapper.get('[data-test="form"]').trigger('submit')
  
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)
  })

  test('completes a todo'.async() = > {const wrapper = mount(TodoApp)
  
    await wrapper.get('[data-test="todo-checkbox"]').setValue(true)
  
    expect(wrapper.get('[data-test="todo"]').classes()).toContain('completed')})Copy the code

First we import mount via import – this is one of the main rendering components in VTU.

You can use the test method to declare a test case and briefly state the current test case. The Test and Expect functions are globally available in most test runners. If Test and Expect are still confused, there are more straightforward examples in the Jest documentation that show you how to use them.

Next, we call mount and pass in a component as the first argument — a step that almost all test cases write about. By convention, we assign the result to a variable named Wrapper, since mount provides a simple “wrapper” for the application and some convenient testing methods. Such as.find,.get, etc

Finally, we use another Jest method, expect, that is common to most test cases. Its main purpose is to allow us to assert or expect that the actual output in this test case will conform to our expectations. In this test case, we find DOM elements with the selector data-test=”todo”, such as

… < / div >. We then call the Call method to get the DOM content, which is the expected result, Learn Vue.js 3

Using the “data-test” selector is not required, but it can make your tests less vulnerable. Classes and ids tend to change or move as the application grows — by using “data-test,” other developers can clearly see which elements are being used in tests and should not be changed.

Execute the test case: Pass

yarn test:unit
Copy the code

Add a new charge item

Next we need to enrich our test cases. We need to have the user create a new todo Item. So we need a form with an input box that allows the user to enter items. When the user clicks Submit, we expect the new to-do item content to be rendered. Let’s take a look at the following test cases:

import { mount } from '@vue/test-utils'
import TodoApp from '@/components/TodoApp.vue'
test('creates a todo'.() = > {
    const wrapper = mount(TodoApp)
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)
  
    wrapper.get('[data-test="new-todo"]').setValue('New todo')
    wrapper.get('[data-test="form"]').trigger('submit')
  
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)})Copy the code
  • In order to update<input>, we usesetValue– This method will make our input value.
  • update<input>After we passtriggerMethod to simulate the behavior of a user operating on a form submission.
  • And finally we expecttodo itemsThe number of will increase from 1 to 2;

We use v-Model to dynamically bind the value of and @submit to listen for the form’s submission event. When the user is submitted, createTodo will be called and the TODOS array will be inserted into a new agent object.

Let’s re-execute the current test case and find the following error:

The toDOS array object we expected was not added, Received Length :1;

The reason:

  • Jest executes test cases synchronously, terminating the current use case as soon as the last method of the use case completes execution.
  • Vue updates Dom asynchronously.

Solution:

  • We need to go throughasyncMark the test case method, calledawaitBefore asynchronous methods that might change the Dom. Such astrigger,setValue.

Modifying the test case to look like this will pass correctly:

import { mount } from '@vue/test-utils'
import TodoApp from '@/components/TodoApp.vue'
test('creates a todo'.async() = > {const wrapper = mount(TodoApp)
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)
  
    await wrapper.get('[data-test="new-todo"]').setValue('New todo')
    await wrapper.get('[data-test="form"]').trigger('submit')
  
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)})Copy the code

Complete a to-do list

We expect the user to be able to mark a test case with a checkbox to see if a backlog item has been completed:

  test('completes a todo'.async() = > {const wrapper = mount(TodoApp)
  
    await wrapper.get('[data-test="todo-checkbox"]').setValue(true)
  
    expect(wrapper.get('[data-test="todo"]').classes()).toContain('completed')})Copy the code

Analyze test cases:

  • We’re throughwrapper.get('[data-test="todo-checkbox")To find thecheckboxElements;
  • Because it isinputTypes we still assign by setValue method;
  • We assert/expect that we will pass a new oneclassClass to mark to-do items in their completed state.

Conclusion:

  • usemount()Method to mount a component.
  • useget() andfindAll() Method to find the DOM.
  • trigger() andsetValue()Method is used to simulate user input actions and form event behavior.
  • updateDOMIs an asynchronous operation, so remember to use itasync andawait.