1. <!-- 单元测试 -->
    2. <template>
    3. <h1>{{ msg }}</h1>
    4. <button @click="setCount">{{ count }}</button>
    5. <input type="text" v-model="todo">
    6. <button class="addTodo" @click="addTodo">add</button>
    7. <ul>
    8. <li v-for="(todo,index) in todos" :key="index">{{todo}}</li>
    9. </ul>
    10. <button class="loadUser" @click="loadUser">load</button>
    11. <p v-if="user.loading" class="loading">Loading</p>
    12. <div v-else class="userName" >{{user.data?.userName}}</div>
    13. <p v-if="user.error" class="error">error!</p>
    14. <Hello msg="1234" />
    15. </template>
    16. <script lang="ts">
    17. import { defineComponent, reactive, ref } from "vue";
    18. import axios from 'axios';
    19. import Hello from "./Hello.vue";
    20. export default defineComponent({
    21. name: "",
    22. components: {
    23. Hello,
    24. },
    25. props: {
    26. msg: String
    27. },
    28. emits: ['send'],
    29. setup(props,context) {
    30. const count = ref(1);
    31. const todo = ref('')
    32. const todos = ref<string[]>([])
    33. const user = reactive({
    34. data: null as any,
    35. loading: false,
    36. error: false,
    37. })
    38. const setCount = () => {
    39. count.value++
    40. }
    41. const addTodo = () => {
    42. if(todo.value) {
    43. todos.value.push(todo.value)
    44. context.emit('send', todo.value)
    45. }
    46. }
    47. const loadUser = () => {
    48. user.loading = true
    49. axios.get('https:/ljsonplaceholder.typicode.com/users/1').then(res=>{
    50. console.log(res);
    51. user.data = res.data
    52. }).catch(() => {
    53. user.error = true
    54. }).finally(() => {
    55. user.loading = false
    56. })
    57. }
    58. return {
    59. count,
    60. todo,
    61. todos,
    62. setCount,
    63. addTodo,
    64. user,
    65. loadUser
    66. };
    67. },
    68. });
    69. </script>
    70. <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的正确返回和错误返回。

    1. import { shallowMount, VueWrapper } from '@vue/test-utils'
    2. import axios from 'axios'
    3. import flushPromises from 'flush-promises'
    4. import HelloWorld from '@/components/HelloWorld.vue'
    5. import Hello from '@/components/Hello.vue'
    6. jest.mock('axios')
    7. const mockAxios = axios as jest.Mocked<typeof axios>
    8. const msg = 'new message'
    9. let wrapper: VueWrapper<any>
    10. describe('HelloWorld.vue', () => {
    11. beforeAll(() => {
    12. wrapper = shallowMount(HelloWorld, {
    13. props: { msg }
    14. })
    15. })
    16. it('renders props.msg when passed', () => {
    17. expect(wrapper.get('h1').text()).toBe(msg)
    18. expect(wrapper.findComponent(Hello).exists()).toBeTruthy()
    19. })
    20. it('should update the count when clicking the button', async () => {
    21. await wrapper.get('button').trigger('click')
    22. expect(wrapper.get('button').text()).toBe('2')
    23. })
    24. it('should add todo when fill the input and click the add button', async () => {
    25. const todoContent = 'buy milk'
    26. await wrapper.get('input').setValue(todoContent)
    27. expect(wrapper.get('input').element.value).toBe(todoContent)
    28. await wrapper.get('.addTodo').trigger('click')
    29. expect(wrapper.findAll('li')).toHaveLength(1)
    30. expect(wrapper.get('li').text()).toBe(todoContent)
    31. console.log(wrapper.emitted())
    32. expect(wrapper.emitted()).toHaveProperty('send')
    33. const events = wrapper.emitted('send')
    34. expect(events[0]).toEqual([todoContent])
    35. })
    36. it('should load user message when click the load button', async () => {
    37. mockAxios.get.mockResolvedValueOnce({ data: { username: 'viking'}})
    38. await wrapper.get('.loadUser').trigger('click')
    39. expect(mockAxios.get).toHaveBeenCalled()
    40. expect(wrapper.find('.loading').exists()).toBeTruthy()
    41. await flushPromises()
    42. // 界面更新完毕
    43. expect(wrapper.find('.loading').exists()).toBeFalsy()
    44. expect(wrapper.get('.userName').text()).toBe('viking')
    45. })
    46. it('should load error when return promise reject', async () => {
    47. mockAxios.get.mockRejectedValueOnce('error')
    48. await wrapper.get('.loadUser').trigger('click')
    49. expect(mockAxios.get).toHaveBeenCalledTimes(1)
    50. await flushPromises()
    51. expect(wrapper.find('.loading').exists()).toBe(false)
    52. expect(wrapper.find('.error').exists()).toBe(true)
    53. })
    54. afterEach(() => {
    55. mockAxios.get.mockReset()
    56. })
    57. })