一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
模拟用户输入
Vue Test Utils 可以轻松模拟真实用户最终在生产中所做的事情。在我们的例子中,用户可以点击星星来切换它们。我们可以在我们的测试中使用该trigger方法伪造这一点,并调度各种事件。
it('adds `active` class on an inactive star when the user clicks it',
() => { const fourthStar = wrapper.findAll('.star').at(3)
fourthStar.trigger('click') expect(fourthStar.classes()).toContain('active')})
在这里,我们首先使用findAlland获得第四颗星,它在传递的索引处从 aat返回 a (从零开始编号)。然后,我们在上面模拟事件——我们正在模仿用户点击或点击第四颗星的动作。Wrapper``WrapperArray``click
由于我们将gradeprop 设置为 3,因此第四颗星在我们点击之前应该是不活动的,因此点击事件应该使其处于活动状态。在我们的代码中,这由一个类表示active,我们仅在它们被激活时附加在星上。我们通过调用classesstar 上的方法对其进行测试,该方法将其类名作为字符串数组返回。然后,我们使用toContain匹配器来确保active类在这里。
设置和拆卸
由于我们触发了对组件的点击,我们已经改变了它的状态。问题是我们在所有测试中都使用相同的组件。如果我们改变测试的顺序,并将它移动到第一个位置会发生什么?那么第二次测试就会失败。
当涉及到测试时,您不想依赖诸如顺序之类的脆弱事物。测试套件应该是健壮的,并且现有的测试最好不要改变,除非你破坏了 API。
我们想确保我们总是有一个可预测的包装器来执行断言。我们可以通过设置和拆卸功能来实现这一点。这些是帮助我们在运行测试之前初始化事物,然后进行清理的助手。
在我们的例子中,一种方法可能是在每次测试之前创建我们的包装器,然后在之后销毁它。
let wrapper = null
beforeEach(() => {
wrapper = shallowMount(Rating,
{
propsData: {
maxStars: 6, grade: 3
} })
})
afterEach(() => { wrapper.destroy()})
describe('Rating', () => { // we remove the `const wrapper = …` expression // …}
正如他们的名字所暗示的那样,分别在每次测试之前和之后运行beforeEach。afterEach通过这种方式,我们可以 100% 确定我们在运行新测试时使用的是新包装器。
测试的特殊标识符
将选择器混合用于样式和其他目的(例如测试挂钩)绝不是一个好主意。
如果您更改标签名称或类别怎么办?
如果您想要测试的元素(例如在我们的例子中是计数器)上没有特定标识符怎么办?
您不想用在那里无用的类污染您的生产代码。最好有专门的测试钩子,例如专门的数据属性,但仅限于测试期间。这样,最终构建中就不会留下混乱。
处理此问题的一种方法是创建自定义 Vue 指令。
Vue 实例有一个directive方法,该方法接受两个参数 - 一个name和一个用于注入 DOM 时组件生命周期的每个钩子的函数对象。 如果您不关心特定的钩子,您也可以传递单个函数。
让我们创建一个名为directivesin的新目录src/,并添加一个test.js文件。我们将导出要在指令中传递的函数。
// test.js
export default (el, binding) => { // do stuff}
一个指令钩子可以接受多个参数,在我们的例子中,我们只需要前两个:el和binding. el参数引用指令绑定到的元素。参数是一个对象,binding其中包含我们在指令中传递的数据。这样我们就可以随心所欲地操纵元素。
export default (el, binding) => { Object.keys(binding.value).forEach(value => { el.setAttribute(`data-test-${value}`, binding.value[value]) })}
我们将一个对象传递给我们的指令,因此我们可以生成以 . 开头的数据属性data-test-。在处理函数中,我们遍历 的每个属性binding,并在我们的元素上设置一个基于名称和值的数据属性。