admin管理员组文章数量:1391974
I am using Vue v2.6 with Jest (v24.9) and Vue-Test-Utils (v1.03).
In order to mock a method I have seen two different syntaxes,
wrapper.vm.updateCart = jest.fn();
and
wrapper.setMethods({ updateCart: jest.fn() });
but the first is not documented, while the second is deprecated (see docs).
The problem is that with both these methods, the only way to make a test pass is to call the method with the parentheses inside the template, which is weird because all the docs I've read somehow encourage to use methods without parentheses in the templates.
So this test:
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();
});
will only pass if I call the method with parentheses:
<button class="btn" @click="updateCart()">
{{ dictionary('remove') }}
</button>
but will fail otherwise (eg. using @click="updateCart"
).
Which is the right syntax to test that an event in a template is calling a function?
And why the deprecation warning in the docs (here and here) define the setMethod
api as an anti-pattern?
Maybe it is just wrong to only test that an event in a template triggers a function because this behavior should already be guaranteed by the framework (Vue) and instead we should only focus on testing the function itself?
EDIT 07/02/2020
I have also tried a different syntax:
const spy = jest.spyOn(wrapper.vm, 'updateCart');
const $btn = wrapper.find('.btn');
$btn.trigger('click');
expect(spy).toHaveBeenCalled();
which prevents from overwriting the method and replaces the call to setMethods
, but still the test only passes when the function is called with parentheses.
I am using Vue v2.6 with Jest (v24.9) and Vue-Test-Utils (v1.03).
In order to mock a method I have seen two different syntaxes,
wrapper.vm.updateCart = jest.fn();
and
wrapper.setMethods({ updateCart: jest.fn() });
but the first is not documented, while the second is deprecated (see docs).
The problem is that with both these methods, the only way to make a test pass is to call the method with the parentheses inside the template, which is weird because all the docs I've read somehow encourage to use methods without parentheses in the templates.
So this test:
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();
});
will only pass if I call the method with parentheses:
<button class="btn" @click="updateCart()">
{{ dictionary('remove') }}
</button>
but will fail otherwise (eg. using @click="updateCart"
).
Which is the right syntax to test that an event in a template is calling a function?
And why the deprecation warning in the docs (here and here) define the setMethod
api as an anti-pattern?
Maybe it is just wrong to only test that an event in a template triggers a function because this behavior should already be guaranteed by the framework (Vue) and instead we should only focus on testing the function itself?
EDIT 07/02/2020
I have also tried a different syntax:
const spy = jest.spyOn(wrapper.vm, 'updateCart');
const $btn = wrapper.find('.btn');
$btn.trigger('click');
expect(spy).toHaveBeenCalled();
which prevents from overwriting the method and replaces the call to setMethods
, but still the test only passes when the function is called with parentheses.
- 1 Even today with Vitest + Vue 3 (position API) + Vue Testing Library, if you don't put parenthesis on the events on child ponents the spy won't register the call. I found out what I needed to do thanks to this post :) – zenw0lf Commented Sep 13, 2022 at 16:03
1 Answer
Reset to default 6Both @click="updateCart"
and @click="updateCart()"
syntax variations are supported, which is confusing because Vue DSL allows to provide expressions in v-on
. The former uses updateCart
method as event handler, while the latter evaluates the expression against ponent instance and isn't limited to methods.
@click="updateCart()"
is preferable for consistency reasons because expressions are monly used in Vue templates, also @click="notAFunction"
silently fails while @click="notAFunction()"
throws an error. This also allows to spy on it with:
jest.spyOn(wrapper.vm, 'updateCart');
Otherwise the method needs to be spied before ponent instantiation:
jest.spyOn(Modal.methods, 'updateCart');
const wrapper = shallowMount(Modal);
The deprecation of setMethod
has been explained:
There's no clear path to replace setMethods, because it really depends on your previous usage. It easily leads to flaky tests that rely on implementation details, which is discouraged .
...
To stub a plex method extract it from the ponent and test it in isolation. To assert that a method is called, use your test runner to spy on it.
The concerns about testing the implementation are subjective because it's often not a bad thing. It depends on the case whether the extraction is practical, because a function needs to be extracted to another module in order to be spyable.
As for updateCart
, it may be enough to mock underlying API that updates the carе, not the method itself.
It still may be useful to test click event with stubbed method, or at least spy on real method. It's the template that is tested this way, not just the behaviour of the framework. Without a spy, it's unknown whether the test fails because of btn
or updateCart
.
本文标签:
版权声明:本文标题:javascript - Test on function call in Vue template only passes if the function is called with parentheses - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744652678a2617779.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论