Official test tool

Be especially careful to use version 2.0.0 and above: document address

Purpose: Provides specific methods for mounting components in an isolated environment, as well as a series of tests

Configuring the Development Environment

Skip this step if you select unit tests when creating your project

Before configuration, vuE-CLI has the following features:

  • Vue-cli is developed based on plug-ins that can:
    • Install the corresponding dependencies
    • Modifying Internal Configurations
    • Into the command
  • Install plug-ins in existing projects
    • vue add xxx

Installing a plug-in

Vue add unit-jest Add-on address unit-jest

Json, and generate the tests folder and jest.config.js in the root directory:

Plug-in runtime

  • Install dependencies
    • vue-test-unit
    • vue-jest
    • A new command was injected
  • vue-cli-server test:unit
    • any files in tests/unit that end in .spec.(js|jsx|ts|tsx)
    • any (js(x) | ts(x))files inside __tests__ directories
  • Vue – jest transformation
    • Convert the VUE SFC file format to the corresponding TS file
    • Convert ts via presets/typescript-babel to the corresponding JS file

To begin testing

Here’s what we need to know before we start testing:

  • Rendering component
    • mountandshallowMount
    • Passing attributes
  • Whether the element was successfully displayed
    • Find different ways to write elements
    • The get, getAl
    • The find, the.findall
    • FindComponent, getComponent
  • Triggering event
    • trigger
  • Test whether the interface is updated
    • Note in particular that DOM updates are a one-step process, and note the use of ASyn, await in tests

It feels like jquery

The test case

Let’s start with a simple example of determining the text content of an element and what happens when the click event is triggered.

Judge text content

{{MSG}}

and

{{count}}

after the addCount event

<template>
  <div>
      <p class="msg">{{ msg }}</p>
      <h1 class="number">{{ count }}</h1>
      <button @click="addCount">ADD</button>
  </div>
</template>

<script lang='ts'>
import { ref } from 'vue'
interface DataProps {}
export default {
    name: 'Test'.props: {
        msg: {
            type: String.default: ' '}},setup() {
        const count = ref<number>(0)
        const addCount = () = > {
            count.value++
        }
        return {
            count,
            addCount
        }
    }
  };
</script>
Copy the code

Next write the test case and create the test.spec.ts file under tests/ Unit

import Test from '@/components/test.vue'
import {  mount, shallowMount } from '@vue/test-utils'
describe('test.vue'.() = > {
    it('renders props.msg when passed'.() = >{
        const msg = "new msg"
        // Get the component instance
        const  wrapper = mount(Test, {
            // Pass props in the instance
            props: {
                msg
            }
        })
        // Get the HTML text of the component
        console.log(wrapper.html())
        // case
        expect(wrapper.get('.msg').text()).toBe(msg)

    })
})
Copy the code
  1. First introducedTestComponent, call@vue/test-utilsIn themountMethod, get totest.vueComponent instance object
  2. We hope that<p class="msg">{{ msg }}</p>The text fornew msg
  3. Start test commandnpm run test:unit -- --watch, note that — –watch isjestWebpack-like wacth comes with it
  4. Take a look at the test results:

It has been passed. Let’s change the case toexpect(wrapper.get('.msg').text()).toBe('222'), failed to pass

Indicates that the test case is OK

Next we trigger the click event

Trigger click event

describe('test.vue'.() = > {
   
    it('renders props.msg when passed'.() = >{...// Trigger the click event
        wrapper.get('.addCount').trigger('click')
        expect(wrapper.get('.number').text()).toBe('1')})})Copy the code

The code above triggers the click event and then gets the expected value because it is count.value++. The count should be 1. The addCount can be triggered by running project discovery, so it is possible to have async and await.

describe('test.vue'.() = > {
   
    it('renders props.msg when passed'.async() = > {...// Trigger the click event
        await wrapper.get('.addCount').trigger('click')
        expect(wrapper.get('.number').text()).toBe('1')})})Copy the code

View the console again as shown below:

Update the form

<template>
  <div>
      <p class="msg">{{ msg }}</p>
      <h1 class="number">{{ count }}</h1>
      <button class="addCount" @click="addCount">ADD</button>
      <! - form - >
      <input type="text" v-model="inputValue" /> 
      <! -- Trigger add -->
      <button @click="addTodo"  class="addTodo">Add data</button>
      <! Render list -->
      <ul>
        <li v-for="(item, index) in list" :key="index">
           {{ item }}
        </li>
      </ul>
  </div></template> <script lang='ts'> import { ref } from 'vue' interface DataProps {} export default { name: 'Test', props: { msg: { type: String, default: '' } }, setup(props, context) { const count = ref<number>(0) const inputValue = ref<string>('') const list = ref<string[]>([]) const addCount  = ()=> { count.value++ } const addTodo = () => { if(inputValue.value) { list.value.push(inputValue.value) context.emit('send', inputValue.value) } } return { count, addCount, inputValue, addTodo } } }; </script>Copy the code

The process is as follows:

  1. Input box to enter text content
  2. Enter and clickAdd dataA push button tolistIn the
  3. Render on the page

Start writing test cases:

describe('test.vue'.() = > {
   
    it('renders props.msg when passed'.async() = > {const msg = "new msg"
        const  wrapper = mount(Test, {
            props: {
                msg
            }
        })
        // Mock a line of data
        const value = 'inputValue'
        // Write to input
        await wrapper.get('input').setValue(value)
        // Validate input value input usage
        expect(wrapper.get('input').element.value).toBe(value)
        // Trigger the click addTodo event
        await wrapper.get('.addTodo').trigger('click')
        // Get the length of all rendered Li's
        expect(wrapper.findAll('li')).toHaveLength(1)
        // Determine the text of the first li
        expect(wrapper.get('li').text()).toBe(value)
    })
})
Copy the code

You can see that all the test cases have passed the following figure:

Verify the event

We’re going to have some send event handling in the component, so let’s look at the code. We’re going to send an send event when we click the button, and we’re going to pass in inputValue.value

export default {
    name: 'Test'./ / add the send
    emits: ['send'].setup(props, context){...const addTodo = () = > {
          if(inputValue.value) {
            ...
            context.emit('send', inputValue.value) } } .... }};Copy the code

Next, start writing test cases:

it('renders props.msg when passed'.async() = > {const msg = "new msg"
        const  wrapper = mount(Test, {
            props: {
                msg
            }
        })
        ...
        // Determine whether the launch event exists
        expect(wrapper.emitted()).toHaveProperty('send')
        const events = wrapper.emitted('send')
        // Determine the parameters passed in
        expect(events ? events[0]: []).toEqual([value])

        
// 2. Input and click 'Add Data' button push to 'list'
    
// 3. Render the page

    })
Copy the code

The result is shown in the following figure, indicating that it has passed

An asynchronous request

<template>
    <div>.<button class="loadUser" @click="loadUser">load</button>
        <p v-if="user.loading" class="loading">Loading</p>
        <div v-else class="userName">{{user.data && user.data.username}}</div>
        <p v-if="user.error" class="error">error!</p>.</div>
</template>
<script lang="ts">
import { defineComponent, watchEffect, ref, reactive } from "vue";
import  userLoader from '@/hooks/useLoader'
import axios from "axios";
import Hello from './hello.vue'
interface PostProps {
  count: number,
  errorCode: number,
  message: string,
  result: boolean,
  data?: [
    {
      agentId: string,
      agentName: string,
      id: string
    }
  ]
}
export default defineComponent({
  ...
  setup(props,context) {
    const user = reactive({
      data: null as any,
      loading: false.error: false
    })
    const loadUser = () = > {
      user.loading = true
      axios.get('https://jsonplaceholder.typicode.com/users/1').then(resp= > {
        console.log(resp)
        user.data = resp.data
      }).catch(() = > {
        user.error = true
      }).finally(() = > {
        user.loading = false})}return{ user, loadUser }; }});</script>
Copy the code

The process is also simple: first click the Button, then trigger the AXIos request, and finally render to the page

Start test case writing:

import { shallowMount, mount, VueWrapper } from '@vue/test-utils'
/ / introduce axios
import axios from 'axios'
// Flush-promises will clear all Promise handles waiting to be completed
import flushPromises from  'flush-promises'
/ / simulation axios
jest.mock('axios')
// The important step is to assert true mock types while preserving axios methods
const mockAxios = axios as jest.Mocked<typeof axios>

describe('axios'.() = > {
    it('test axios'.async ()=> {
    mockAxios.get.mockResolvedValueOnce({ data: {username: 'xxxx'}})/ / click
    await wrapper.get('.loadUser').trigger('click')
    // Determine whether the request is invoked
    expect(mockAxios.get).toHaveBeenCalled()
    // Check whether the button is displayed
    expect(wrapper.find('.loading').exists()).toBeTruthy()
    // The interface is updated
    await flushPromises()
    // Check whether loading 

Loading

exists after the request succeeds
expect(wrapper.find('.loading').exists()).toBeFalsy()
The final text is XXXX
expect(wrapper.get('.userName').text()).toBe('xxxx')})})Copy the code

All right, that’s the basic introduction.

Write in the last

Finally, recommend a full set of TS tutorials. Recent TS in ascension, collect a set of very good tutorial, free to share with XDM www.yidengxuetang.com/pub-page/in…