Search code examples
vue.jsjestjsvue-test-utils

Why is Jest spyOn() only passing in one of these tests, but failing in the other?


I have a vue child component:

    <NavbarSnap
      title="Select Recipient"
      data-testid="navbarsnap"
      v-on:change-screen-handler="onHandleChangeScreen('SnapRecepient')"
      :hasSearch="true"
      :hasInvite="true"
      :groupName="getSelectedChannel.CNM"
      v-on:search-input="handleSearchInputChange"
    />

The component has two v-on directives.

I have two tests that are nearly identical. But the first one passes and the second one fails:

  it("NavBarSnap change screen", async () => {
    const wrapper = factory();
    let spy = jest.spyOn(wrapper.vm, "onHandleChangeScreen");

    let element = wrapper.find("[data-testid='navbarsnap']");

    expect(element.exists()).toBeTruthy();
    element.vm.$emit("change-screen-handler");
    await wrapper.vm.$nextTick();

    expect(spy).toHaveBeenCalled();
  });

  it("NavBarSnap search input", async () => {
    const wrapper = factory();
    let spy = jest.spyOn(wrapper.vm, "handleSearchInputChange");

    let element = wrapper.find("[data-testid='navbarsnap']");

    expect(element.exists()).toBeTruthy();
    element.vm.$emit("search-input");
    await wrapper.vm.$nextTick();

    expect(spy).toHaveBeenCalled();
    // THIS TEST FAILS
  });

The test fails because jest.fn() has not been called.

Both the of the spyed on functions are beings tested in the same suite and work fine (although that shouldn't matter here). Both tests are grabbing the component in the same way and emitting from the child component in the same way. I don't understand why one test passes and one fails.

Any ideas?


Solution

  • The difference is how event handlers are registered:

    v-on:change-screen-handler="onHandleChangeScreen('SnapRecepient')"
    

    and

    v-on:search-input="handleSearchInputChange"
    

    The former evaluates the expression against component instance and isn't limited to methods. The latter uses handleSearchInputChange method as event handler, this requires to spy on it before component instantiation:

    let spy = jest.spyOn(Component.methods, "handleSearchInputChange");
    const wrapper = factory();
    ...
    

    It should be v-on:search-input="handleSearchInputChange()" for consistency. This allows to spy on an instance similarly to onHandleChangeScreen:

    let spy = jest.spyOn(wrapper.vm, "handleSearchInputChange");
    ...