本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-02-26
在 Vue Test Utils
中,每个包装器都有一个 trigger
方法,用于在包装元素上分发一个合成事件。
合成事件是 JavaScript 中创建的事件。实际上,合成事件的处理方式与浏览器分发事件的方式相同。区别在于原生事件通过 JavaScript 事件循环异步调用事件处理程序,合成事件则同步调用事件处理程序。
trigger
使用一个 eventType
参数创建包装器上分发的事件。
示例:测试按钮被点击时 onClose prop 是否被调用。
test('calls onClose when button is clicked', () => {
const onClose = jest.fn();
const wrapper = shallowMount(Modal, { // 浅挂载一个Modal组件传递一个props
propsData: { onClose }
});
warpper.find('button').trigger('click');
expect(onClose).toHaveBeenCalled();
})
对应的 Modal
组件如下,父组件在调用时会传一个函数过来 <Modal :onClose="parentCloseEvent"/>
<template>
<div>
<button @click="onClose" />
<slot />
</div>
</template>
<script>
export default {
props: ['onClose']
}
</script>
1、测试触发:测试自定义事件是否被触发
Vue Test Utils
的 emitted
方法测试组件是否发射事件,使用事件名称调用 emitted
以返回一个数组,该数组包含了每个发射事件的 payload
; 你也可以使用emitted
来测试一个事件是否以正确的顺序或使用正确的数据被调用。
this.$emit('test-emit', paylaod1);
this.$emit('test-emit', paylaod2);
wrapper.emitted('test-emit') // [payload1, payload2]
示例:在按钮上触发 click 事件,断言组件实例是否使用 emitted 方法触发了一个 close-modal 事件;
test('emits on-close when button is clicked', () => {
const wrapper = shallowMount(Modal);
warpper.find('button').trigger('click');
expect(warpper.emitted('close-modal')).toHaveLength(1); // 断言close-modal被处罚了一次
})
<template>
<div>
<button @click="$emit('close-modal')" />
<slot />
</div>
</template>
2、测试监听:测试在触发自定义事件后,被测组件的响应是否是正确的
示例:测试当你从 Modal 事件发射一个 close-modal 事件时,App 组件是否正确响应了。
所以我们需要测试的 App 组件,只需要引入 Modal 组件然后主动触发事件(不需要挂载),然后测试 App 的响应是否正确。
import App from '../../App.vue'
import { shallowMount } from '@vue/test-utils'
import Modal from '../../components/Modal.vue'
describe('App.vue', () => {
test('hides Modal when Modal emits close-modal', async () => {
const wrapper = shallowMount(App)
wrapper.findComponent(Modal).vm.$emit('close-modal')
expect(wrapper.findComponent(Modal).exists()).toBeFalsy()// 是否正常响应
})
test('App.closeModal called when Modal emits close-modal', async () => {
const closeModal = jest.fn();
const wrapper = shallowMount(App, {
methods: {
closeModal
},
})
wrapper.findComponent(Modal).vm.$emit('close-modal')
expect(closeModal).toHaveBeenCalled() // 对应的方法是否被处罚
})
})
<!-- App.vue -->
<template>
<Modal
v-if="displayModal"
@close-modal="closeModal"
/>
</template>
<script>
import Modal from './components/Modal'
export default {
name: 'App',
data: () => ({
displayModal: true
}),
components: {
Modal
},
methods: {
closeModal () {
this.displayModal = false
}
}
}
</script>
输入表单可以包含许多逻辑来处理验证并使用输入值执行操作,所以这些逻辑是需要被测试的。
1、测试文本输入框
const wrapper = shallowMount(Form);
const input = wrapper.find('input[type="email"]');
input.setValue('email@gmail.com');
2、测试触发提交表单事件后,是否使用了正确的参数调用了POST;
test('send post request with email on submit', () => {
const axios = {
post: jest.fn()
}
const wrapper = shallowMount(Form, {
mocks: { axios }
})
const input = wrapper.find('input[type="email"]');
input.setValue('email@gmail.com');
wrapper.find('button').trigger('submit');
const url = 'http://demo.test.io/validate';
const expectData = expect.objectContaining({
email: 'email@gmail.com',
})
expect(axios.post).toHaveBeenCalledWith(url, expectData);
// 这一段使用 objectContaining
// 是因为你此时可能只想测试是否带了正确的参数 email
// 但是可能 axios的参数有多个 objectContaining 指包含就可以
// 如果直接写,则要求是 '全等于'
// 不使用 objectContaining
// expect(axios.post).toHaveBeenCalledWith(url, {
// email: 'email@gmail.com',
// })
})
3、测试单选按钮
const wrapper = shallowMount(Form);
const radioInput = wrapper.find('input[type="radio"]');
radioInput.setChecked();
// 找到对应的单选按钮点击
const radioNoInput = wrapper.find('input[value="no"]');
radioNoInput.setChecked();
// 普通写法
// radioInput.element.checked = true;
要在 Node 中运行 Vue 单元测试,你需要使用 jsdom 模拟 DOM 环境。多数情况下,这是有效的,但有时你也会遇到未实现特性的问题。
在 jsdom 中,web平台未实现的两大部分是:
布局:关于计算元素位置的,如 Element.getBoundingRects
这样的 DOM 方法将不会按预期执行,你如果使用元素的位置来计算组件的样式就会遇到类似的问题;
导航:jsdom 中没有页面的概念,因此你无法创建请求并导航到其他页面上;
本章例子中,表单中的submit
事件的行为与它在浏览器中的行为不一样,在浏览器中表单的 submit
事件会在默认情况下创建一个 GET 请求,从而使页面重新加载,但是我们不需要这种行为,因此你需要编写代码防止事件发送 GET 请求导致页面重新加载;
<form name="email-form" @submit.prevent="onSubmit">
也正因为此,如果需要检查一个表单的提交动作是否会导致页面重新加载,你需要编写的是端到端测试来补充。
jsdom 中未实现的两个部分,布局和导航;了解这些限制很重要,因为当你遇到这些限制的时候,你不该做模拟,而是应该使用端到端测试补充你的单元测试。