[TOC]

知识点

  • 将 mock 对象断言为特定类型 使用 jest.Mocked
  • 使用 it.only 来指定测试的 case
  • 使用 skip 跳过指定测试的 case

    测试内容

  • 触发事件

    • trigger 方法
  • 测试界面是否更新
    • 特别注意 DOM 更新是个异步的过程
    • 使用 async await
  • 更新表单
    • setValue 方法
  • 验证事件是否发送
    • emitted 方法
  • 测试异步请求

    • 模拟第三方库实现

      测试准备和结束

      钩子用于一次性完成测试准备

  • beforeAll

  • afterAll

    let wrapper: VueWrapper<any>;
    describe('HelloWorld.vue', () => {
    // 在多个 case 运行之前执行,只执行一次,由于这样会让所有的用例使用一个 `warpper` 实例,可能会造成错误。
    beforeAll(() => {
      // 获取组件
      wrapper = shallowMount(HelloWorld, {
        props: { msg },
      });
    });
    // 在多个 case 运行之后执行,只执行一次
    afterAll(() => {});
    });
    

    钩子用于每个测试用例测试准备

  • beforeEach

  • afterEach

    let wrapper: VueWrapper<any>;
    describe('HelloWorld.vue', () => {
    beforeEach(() => {
      // 获取组件
      wrapper = shallowMount(HelloWorld, {
        props: { msg },
      });
    });
    afterEach(() => {
      mockAxios.get.mockReset();
    });
    });
    

    测试建议

    如果一个测试失败了,需要注意

  • 它是否是唯一在运行的用例,使用 only 单独运行一次, skip 跳过一个用例

  • 如果单独运行没问题,整体运行出错,应该检查 beforeEach ,beforeAll 等全局钩子中的逻辑是否有问题,判断是否需要清空共享状态。

    测试组件

    ```javascript
``` ```javascript
<a name="N4faT"></a>
## 触发事件 trigger
```javascript
import { shallowMount, mount, VueWrapper } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
import hello from '@/components/hello.vue'

jest.mock('axios')

let wrapper: VueWrapper<any>
const msg = 'new message'

describe('HelloWorld.vue', () => {
  beforeEach(() => {
    // 获取组件
    wrapper = shallowMount(HelloWorld, {
      props: { msg },
    })
  })
  it('renders props.msg when passed', async () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      props: { msg },
    })
    //触发事件  trigger是一个异步的过程 记得加async await
    await wrapper.get('button').trigger('click')
    expect(wrapper.get('button').text()).toBe('1')
  })
})

image.png

更新表单 setValue

import { shallowMount, mount, VueWrapper } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
import hello from '@/components/hello.vue'

jest.mock('axios')

let wrapper: VueWrapper<any>
const msg = 'new message'

describe('HelloWorld.vue', () => {
  ...
  it('should add todo when fill the input and click the add button', async () => {
    const todoContent = 'haha'
    //setValue  赋值
    await wrapper.get('input').setValue(todoContent)
    //wrapper.get('input').element  得到一个dom节点
    expect(wrapper.get('input').element.value).toBe(todoContent)
    //.add-todo
    await wrapper.get('.add-todo').trigger('click')
    //数组长度 toHaveLength
    expect(wrapper.findAll('li')).toHaveLength(1)
    expect(wrapper.get('li').text()).toBe(todoContent)
  })
})

验证事件 emitted


...
// 断言 触发了 名为 send 的 emit 事件
expect(wrapper.emitted()).toHaveProperty('send')
// 获取 send 事件的 对象
const events = wrapper.emitted('send')!
console.log('events', events)
// 检查对象内容是否相同使用 toEqual, toBe 要求类型也相同
expect(events[0]).toEqual([todoContent])

image.png

异步请求

...
// 使用 it.only 来指定测试的 case
it.only('should load user message when click the load button', async () => {
  mockAxios.get.mockResolvedValueOnce({
    data: {
      username: 'haha',
    },
  })
  await wrapper.get('.load-user').trigger('click')
  //请求是否被调用
  expect(mockAxios.get).toHaveBeenCalled()
  //exists 是否存在;toBeTruthy 匹配任何if语句为真
  expect(wrapper.find('.loading').exists()).toBeTruthy()
  // 让 promise 完成,并且界面更新完成
  await flushPromises()
  //toBeFalsy 匹配任何if语句为假
  expect(wrapper.find('.loading').exists()).toBeFalsy()
  expect(wrapper.get('.user-name').text()).toBe('haha')
})


//skip跳过一些用例
it.skip('should load user message when click the error button', async () => {
 //处理error的情况
  mockAxios.get.mockRejectedValueOnce('error')
  await wrapper.get('.load-user').trigger('click')
  //请求是否被调用
  expect(mockAxios.get).toHaveBeenCalled()
  await flushPromises()
  //toBeFalsy 匹配任何if语句为假
  expect(wrapper.find('.loading').exists()).toBe(false)
  expect(wrapper.find('.error').exists()).toBe(true)
})