Vue 模板中的函数调用测试仅在使用括号调用函数时通过

Posted

技术标签:

【中文标题】Vue 模板中的函数调用测试仅在使用括号调用函数时通过【英文标题】:Test on function call in Vue template only passes if the function is called with parentheses 【发布时间】:2020-10-23 02:06:37 【问题描述】:

我正在使用带有 Jest (v24.9) 和 Vue-Test-Utils (v1.03) 的 Vue v2.6。

为了模拟一个方法,我见过两种不同的语法,

wrapper.vm.updateCart = jest.fn();

wrapper.setMethods( updateCart: jest.fn() );

但第一个没有记录,而第二个已弃用(请参阅docs)。

问题在于,对于这两种方法,使测试通过的唯一方法是在模板中调用带有括号的方法,这很奇怪,因为我读过的所有文档都以某种方式鼓励使用不带括号的方法在模板中。

所以这个测试:

test('Click on .btn calls the right function', () => 
    const wrapper = shallowMount(Modal, 
        propsData: 
            validate: jest.fn(),
        ,
    );
    wrapper.setMethods( updateCart: jest.fn() );
    const $btn = wrapper.find('.btn');
    $btn.trigger('click');
    expect(wrapper.vm.updateCart).toHaveBeenCalled();
);

只有当我用括号调用方法时才会通过:

<button class="btn" @click="updateCart()">
   dictionary('remove') 
</button>

但否则会失败(例如,使用@click="updateCart")。

测试模板中的事件是否正在调用函数的正确语法是什么?

为什么文档中的弃用警告(here 和 here)将 setMethod api 定义为反模式?

也许只测试模板中的事件触发函数是错误的,因为框架(Vue)应该已经保证了这种行为,而我们应该只专注于测试函数本身?

编辑 07/02/2020

我也尝试了不同的语法:

const spy = jest.spyOn(wrapper.vm, 'updateCart');
const $btn = wrapper.find('.btn');
$btn.trigger('click');
expect(spy).toHaveBeenCalled();

这可以防止覆盖方法并替换对setMethods的调用,但仍然只有在使用括号调用函数时才能通过测试。

【问题讨论】:

【参考方案1】:

同时支持@click="updateCart"@click="updateCart()" 语法变体,这令人困惑,因为Vue DSL 允许在v-on 中提供表达式。前者使用updateCart 方法作为事件处理程序,而后者根据组件实例评估表达式并且不限于方法。

@click="updateCart()" 出于一致性原因更可取,因为表达式通常用于 Vue 模板中,@click="notAFunction" 也会静默失败,而 @click="notAFunction()" 会引发错误。这也允许通过以下方式对其进行监视:

jest.spyOn(wrapper.vm, 'updateCart');

否则需要在组件实例化之前窥探该方法:

jest.spyOn(Modal.methods, 'updateCart');
const wrapper = shallowMount(Modal);

已经解释了setMethod的弃用:

没有明确的方法可以替换 setMethods,因为它确实取决于 关于你以前的用法。它很容易导致依赖于 实施细节,这是不鼓励的。

...

为了存根一个复杂的方法,从组件中提取它并测试它 隔离。要断言调用了某个方法,请使用您的测试运行程序 监视它。

关于测试实施的担忧是主观的,因为这通常不是一件坏事。这取决于提取是否实用的情况,因为一个函数需要被提取到另一个模块才能被窥探。

至于updateCart,模拟更新carе的底层API可能就足够了,而不是方法本身。

使用存根方法测试点击事件仍然可能有用,或者至少监视真实方法。以这种方式测试的是模板,而不仅仅是框架的行为。没有间谍,不知道测试失败是因为btn还是updateCart

【讨论】:

初始化前的间谍活动完美无缺。也感谢您解释测试模板行为的原因。

以上是关于Vue 模板中的函数调用测试仅在使用括号调用函数时通过的主要内容,如果未能解决你的问题,请参考以下文章

从 vue.js 中的父模板调用函数

明显调用括号前的表达式必须具有(指向)函数类型

循环函数中的异步调用。仅在异步完成时返回

vue模板内用箭头函数轻松的增加了第二参数吗?

JS调用函数时啥时候加小括号()?啥时候不加小括号()?

lua 函数调用的时候使用小括号和使用大括号有啥区别,如何定义?