I see the changes the method do as event handler, but jest.spyOn(wrapper.vm, 'methodName')
doesn't catch the call in major cases, but in some tests it somehow works. I suspect a possible re-render (maybe, due to options
argument in mount()
call), that replaces the original method with the jest.spyOn()
, because, if I trigger event twice in a row, toHaveBeenCalled()
fulfills and tracks the call.
组件:
<template>
<v-app-bar
app
color="primary"
dark
class="header"
>
<router-link
:to="{name: 'User'}"
class="up-and-down-link"
>
<v-toolbar-title>Тестовое задание</v-toolbar-title>
</router-link>
<v-spacer />
<v-toolbar-items>
<v-btn
v-if="isLoggedIn"
class="button-log-out"
text
@click="showLogOutModal"
>
Выйти из профиля
</v-btn>
</v-toolbar-items>
<Modal
v-bind="modal"
@close="onModalClose"
@click:outside="onModalClose(false)"
>
Вы уверены, что хотите выйти из профиля?
</Modal>
</v-app-bar>
</template>
<script>
import { LOG_OUT } from '@/store/auth/action-types';
import { IS_LOGGED_IN } from '@/store/auth/getter-types';
import Modal from '@/components/Modal.vue';
export default {
name: 'Header',
components: { Modal },
data() {
return {
modal: {
show: false,
withConfirmation: true,
},
};
},
computed: {
isLoggedIn() {
return this.$store.getters[`auth/${IS_LOGGED_IN}`];
},
},
methods: {
showLogOutModal() {
this.modal.show = true;
},
onModalClose(confirmation = false) {
this.modal.show = false;
if (confirmation === false) return;
this.logOut();
},
logOut() {
this.$store.dispatch(`auth/${LOG_OUT}`);
this.$router.push({ name: 'Login' });
},
},
};
</script>
该测试按预期工作:
it('After confirmation of the action user is logged out and redirected to login page', async () => {
const actions = {
[LOG_OUT]: jest.fn(),
};
await store.hotUpdate({ modules: { auth: { ...auth, actions } } });
const mockedRouter = {
push: jest.fn(),
};
const wrapper = createWrapper(Header, {
data: () => ({ modal: { show: true } }),
mocks: {
$route: {},
$router: mockedRouter,
},
});
const mockedLogOutMethod = jest.spyOn(wrapper.vm, 'logOut');
await wrapper.find('.button-yes').trigger('click');
// the method's called
expect(mockedLogOutMethod).toHaveBeenCalled();
// the method performs log out and redirect
expect(actions[LOG_OUT]).toHaveBeenCalled();
expect(mockedRouter.push).toHaveBeenCalledWith({ name: 'Login' });
});
But this one doesn't, though during it the data
of the component is changed and we see it on the component's child prop ('show'
turns to be true), thus the method is called indeed, but toHaveBeenCalled()
can't detect the fact:
it("Show modal with confirmation when 'log out' button was clicked", async () => {
const wrapper = createWrapper(Header);
const mockedShowModalMethod = jest.spyOn(wrapper .vm, 'showLogOutModal');
const modal = wrapper.findComponent(Modal);
// the modal is hidden initially
expect(modal.props('show')).toBe(false);
await wrapper.find('.button-log-out').trigger('click');
// after 'log out' button is clicked the modal appears
expect(modal.props('show')).toBe(true);
expect(mockedShowModalMethod).toHaveBeenCalled();
expect(wrapper.find('.modal-confirmation').exists()).toBe(true);
});
我找到了一种解决方法:
...
const mockedShowModalMethod = jest.spyOn(Header.methods, 'showLogOutModal');
const wrapper = createWrapper(Header);
....
However, I wanna find out the reason of this behavior, what do I miss here? I have another test suites, where my initial assertion with jest.spyOn()
works out as well as in the first test here.