如何模拟被 vue 指令触发的方法?
Posted
技术标签:
【中文标题】如何模拟被 vue 指令触发的方法?【英文标题】:How do I mock a method that gets fired by a vue directive? 【发布时间】:2021-02-24 15:21:12 【问题描述】:我试图在我的Test
组件中调用close()
方法,但只有在该指令启用的div
外部单击时才会触发它。我应该在测试中做些什么来确保该方法被触发?我在我的组件中使用v-click-outside
npm 包。
组件
<script>
import vClickOutside from 'v-click-outside';
export default
name: 'Test',
directives:
vClickOutside,
,
data: () => (
isOpen: false,
),
methods:
close()
this.isOpen = false;
,
;
</script>
<template>
<div
v-click-outside="close"
class="test-class"
>
<OtherComponent />
</div>
</template>
这是我的测试文件。
const clickOutsidelDirective = jest.fn();
describe('Test.vue', () =>
const wrapper = shallowMount(Component,
directives:
clickOutside: clickOutsidelDirective,
,
);
wrapper.find('.test-class').trigger('click');
//not sure what i have to do to mock the close() function
//This doesn't get called
expect(clickOutsidelDirective).toHaveBeenCalled();
【问题讨论】:
【参考方案1】:在您的主要组件中,该指令是显式导入的。因此,在您的测试中,您不需要再次定义它。 v-click-outside 有一个后果,你应该测试它。这意味着, close 方法应该触发,而不是模拟整个指令。类似的东西:
编辑: 你的定义包括the directive is wrong:
<template>
<div>
<div
v-click-outside="close"
class="test-class"
>
<h1>H1</h1>
</div>
<div>
<h1 class="outside-class">Outside</h1>
</div>
</div>
</template>
<script>
import clickOutside from 'v-click-outside';
export default
name: 'Test',
directives:
clickOutside: clickOutside.directive,
,
data()
return
isOpen: false,
;
,
methods:
close()
this.isOpen = true;
,
</script>
通过新版本的 Vue-test-utils,方法覆盖将被弃用,所以,这样的事情应该可以工作:
const wrapper = shallowMount(HelloWorld)
wrapper.find('.test-class').trigger('click')
expect(wrapper.vm.isOpen).toBeTruthy()
wrapper.find('.outside-class').trigger('click')
expect(wrapper.vm.isOpen).toBeFalsy()
但事实并非如此。它与内部的 v-click-outside 实现有关。我认为指令和shallowMount有问题。
【讨论】:
似乎即使这样做也不会触发方法/指令被调用 我已经在浏览器中测试了这个模板,一切都很顺利。但是在单元测试中没有用。它应该与指令工作的环境有关。【参考方案2】:该指令未在您的组件中正确设置:
import vClickOutside from 'v-click-outside'
export default
directives:
// BEFORE: ❌
vClickOutside,
// AFTER: ✅
clickOutside: vClickOutside.directive
,
验证close()
在组件外部单击时是否被调用:
-
Mock the
close
method 和 jest.spyOn
。
为测试组件创建一个div
,并为它创建一个已安装的包装器attach。
v-click-directive
adds its event listeners on the next macro-tick (using setTimeout
with no timeout),所以测试还需要等待一个宏滴答来初始化指令。
在包装器上触发click
事件,并在结果中触发await
。然后,断言 close()
被调用。
测试应该如下所示:
it('click directive', async () =>
1️⃣
const closeFn = jest.spyOn(HelloWorld.methods, 'close')
2️⃣
const div = document.createElement('div')
document.body.appendChild(div)
const wrapper = mount(
template: `<div><HelloWorld /></div>`,
components:
HelloWorld
,
, attachTo: div )
try
3️⃣
await new Promise(r => setTimeout(r))
4️⃣
await wrapper.trigger('click')
expect(closeFn).toHaveBeenCalled() ✅
finally
wrapper.destroy()
)
【讨论】:
@FirzokNadeem 这个特定指令的实现检查元素外部的点击,因此我们将该元素包装在可以在测试中点击的div
中。目标元素需要附加到 div
才能使测试正常工作。以上是关于如何模拟被 vue 指令触发的方法?的主要内容,如果未能解决你的问题,请参考以下文章