为什么 jest.spyOn() 有时不适用于 Vue 组件的方法?

vye*_*nkv 2 javascript unit-testing vue.js jestjs

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

组件:

<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>
Run Code Online (Sandbox Code Playgroud)

该测试按预期工作:

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' });
  });
Run Code Online (Sandbox Code Playgroud)

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

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);
  });
Run Code Online (Sandbox Code Playgroud)

我找到了一个解决方法:

...    
const mockedShowModalMethod = jest.spyOn(Header.methods, 'showLogOutModal');
const wrapper = createWrapper(Header);
....
Run Code Online (Sandbox Code Playgroud)

但是,我想找出这种行为的原因,我在这里想念什么?我有另一个测试套件,在这里我的初始断言和jest.spyOn()这里的第一个测试一样有效。

Est*_*ask 5

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

logOut 被称为常规方法:

this.logOut();
Run Code Online (Sandbox Code Playgroud)

showLogOutModal作为回调传递:

  <v-btn
    v-if="isLoggedIn"
    class="button-log-out"
    text
    @click="showLogOutModal"
Run Code Online (Sandbox Code Playgroud)

this.showLogOutModal被读取jest.spyOn后被嘲笑以this.showLogOutModal用作事件处理程序,因此间谍不会影响任何事情。

这可能会通过在替换wrapper.vm.showLogOutModal为间谍后强制重新渲染来解决:

const mockedShowModalMethod = jest.spyOn(wrapper.vm, 'showLogOutModal');
await wrapper.vm.$forceUpdate();
Run Code Online (Sandbox Code Playgroud)

但是问题中列出的解决方法是推荐的方法:

const mockedShowModalMethod = jest.spyOn(Header.methods, 'showLogOutModal');
const wrapper = createWrapper(Header);
Run Code Online (Sandbox Code Playgroud)

  • 今天间谍后的这个forceUpdate()救了我的命 (2认同)