<!-- 单元测试 -->
<template>
<h1>{{ msg }}</h1>
<button @click="setCount">{{ count }}</button>
<input type="text" v-model="todo">
<button class="addTodo" @click="addTodo">add</button>
<ul>
<li v-for="(todo,index) in todos" :key="index">{{todo}}</li>
</ul>
<button class="loadUser" @click="loadUser">load</button>
<p v-if="user.loading" class="loading">Loading</p>
<div v-else class="userName" >{{user.data?.userName}}</div>
<p v-if="user.error" class="error">error!</p>
<Hello msg="1234" />
</template>
<script lang="ts">
import { defineComponent, reactive, ref } from "vue";
import axios from 'axios';
import Hello from "./Hello.vue";
export default defineComponent({
name: "",
components: {
Hello,
},
props: {
msg: String
},
emits: ['send'],
setup(props,context) {
const count = ref(1);
const todo = ref('')
const todos = ref<string[]>([])
const user = reactive({
data: null as any,
loading: false,
error: false,
})
const setCount = () => {
count.value++
}
const addTodo = () => {
if(todo.value) {
todos.value.push(todo.value)
context.emit('send', todo.value)
}
}
const loadUser = () => {
user.loading = true
axios.get('https:/ljsonplaceholder.typicode.com/users/1').then(res=>{
console.log(res);
user.data = res.data
}).catch(() => {
user.error = true
}).finally(() => {
user.loading = false
})
}
return {
count,
todo,
todos,
setCount,
addTodo,
user,
loadUser
};
},
});
</script>
<style lang="scss" scoped></style>
以下组件为例子,该组件有以下功能点:
1、根据props的msg显示到组件
2、点击setCount
按钮,实现自增1
3、TODO功能:
- 输入
input
,页面正常显示输入内容。 - 点击
addTodo
按钮,li
的长度+1,显示输入内容。
4、点击loadUser
按钮,发出请求用户数据请求,按钮处于loading
状态。数据返回之后,元素.userName
显示返回的用户信息。
所以可以编写以上4个测试用例。
重点注意第四点,axios请求测试的方法。mockAxios.get.mockResolvedValueOnce({ data: { username: 'viking'}})
和mockAxios.get.mockRejectedValueOnce('error')
分别模拟axios的正确返回和错误返回。
import { shallowMount, VueWrapper } from '@vue/test-utils'
import axios from 'axios'
import flushPromises from 'flush-promises'
import HelloWorld from '@/components/HelloWorld.vue'
import Hello from '@/components/Hello.vue'
jest.mock('axios')
const mockAxios = axios as jest.Mocked<typeof axios>
const msg = 'new message'
let wrapper: VueWrapper<any>
describe('HelloWorld.vue', () => {
beforeAll(() => {
wrapper = shallowMount(HelloWorld, {
props: { msg }
})
})
it('renders props.msg when passed', () => {
expect(wrapper.get('h1').text()).toBe(msg)
expect(wrapper.findComponent(Hello).exists()).toBeTruthy()
})
it('should update the count when clicking the button', async () => {
await wrapper.get('button').trigger('click')
expect(wrapper.get('button').text()).toBe('2')
})
it('should add todo when fill the input and click the add button', async () => {
const todoContent = 'buy milk'
await wrapper.get('input').setValue(todoContent)
expect(wrapper.get('input').element.value).toBe(todoContent)
await wrapper.get('.addTodo').trigger('click')
expect(wrapper.findAll('li')).toHaveLength(1)
expect(wrapper.get('li').text()).toBe(todoContent)
console.log(wrapper.emitted())
expect(wrapper.emitted()).toHaveProperty('send')
const events = wrapper.emitted('send')
expect(events[0]).toEqual([todoContent])
})
it('should load user message when click the load button', async () => {
mockAxios.get.mockResolvedValueOnce({ data: { username: 'viking'}})
await wrapper.get('.loadUser').trigger('click')
expect(mockAxios.get).toHaveBeenCalled()
expect(wrapper.find('.loading').exists()).toBeTruthy()
await flushPromises()
// 界面更新完毕
expect(wrapper.find('.loading').exists()).toBeFalsy()
expect(wrapper.get('.userName').text()).toBe('viking')
})
it('should load error when return promise reject', async () => {
mockAxios.get.mockRejectedValueOnce('error')
await wrapper.get('.loadUser').trigger('click')
expect(mockAxios.get).toHaveBeenCalledTimes(1)
await flushPromises()
expect(wrapper.find('.loading').exists()).toBe(false)
expect(wrapper.find('.error').exists()).toBe(true)
})
afterEach(() => {
mockAxios.get.mockReset()
})
})