为什么jest.spyOn()有时不能在Vue组件的方法上工作? [英] Why doesn't jest.spyOn() sometimes work on a Vue component's method?

查看:143
本文介绍了为什么jest.spyOn()有时不能在Vue组件的方法上工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了该方法作为事件处理程序所做的更改,但是jest.spyOn(wrapper.vm, 'methodName')在大多数情况下都无法捕获该调用,但是在某些测试中它以某种方式起作用.我怀疑可能进行重新渲染(可能是由于mount()调用中的options参数),用jest.spyOn()替换了原始方法,因为如果我连续两次触发事件,则toHaveBeenCalled()会满足并跟踪呼叫.

I see the changes the method makes 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' });
  });

但是这个并没有,尽管在此期间组件的data发生了变化,我们在组件的子道具('show'变为true)上看到了它,因此确实调用了该方法,但toHaveBeenCalled()无法检测到事实:

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);
....

但是,我想找出这种现象的原因,在这里我想念什么?我还有另一个测试套件,其中我对jest.spyOn()的初始声明与此处的第一个测试一样有效.

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.

推荐答案

logOutshowLogOutModal方法之间的区别在于它们的使用方式.

The difference between logOut and showLogOutModal methods is how they are used.

logOut被称为常规方法:

this.logOut();

showLogOutModal作为回调传递:

  <v-btn
    v-if="isLoggedIn"
    class="button-log-out"
    text
    @click="showLogOutModal"

在读取this.showLogOutModal用作事件处理程序后,

this.showLogOutModaljest.spyOn进行了模拟,因此间谍不会产生任何影响.

this.showLogOutModal is mocked with jest.spyOn after this.showLogOutModal is read to to be used as event handler, so a spy doesn't affect anything.

通过用间谍代替wrapper.vm.showLogOutModal后强制重新渲染可以解决此问题:

This would likely be fixed by forcing a re-render after replacing wrapper.vm.showLogOutModal with a spy:

const mockedShowModalMethod = jest.spyOn(wrapper.vm, 'showLogOutModal');
await wrapper.vm.$forceUpdate();

但是建议使用问题中列出的解决方法:

But a workaround listed in the question is the recommended way to do this:

const mockedShowModalMethod = jest.spyOn(Header.methods, 'showLogOutModal');
const wrapper = createWrapper(Header);

这篇关于为什么jest.spyOn()有时不能在Vue组件的方法上工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆