Vue-test-utils: Test case to check if a method was called in `mounted` hook fails, when stubbed using `jest.fn()`

Created on 14 Nov 2018  ·  5Comments  ·  Source: vuejs/vue-test-utils

Version

1.0.0-beta.25

Reproduction link

https://codesandbox.io/s/rw83wwvzym

Steps to reproduce

  • Create a Vuejs component having a method and call that method in the mounted hook
  • In your test case, shallowMount the component and stub the method using jest.fn()
  • Write a test case that checks if the method was called using toBeCalled()

What is expected?

The test case should pass

What is actually happening?

The test case fails with the error message

jest.fn() value must be a mock function or spy.
Received:
  function: [Function bound ]

Most helpful comment

Vue binds methods when it adds them to an instance, so the method on an instance is not a reference to the original function. You can solve your issue by keeping a reference to the original function:

it('calls testMethod on mount', () => {
  const testMethod = jest.fn()
  const wrapper = shallowMount(List, {
    methods: {
      testMethod
    }
  })

  expect(testMethod).toBeCalled()
});

All 5 comments

Vue binds methods when it adds them to an instance, so the method on an instance is not a reference to the original function. You can solve your issue by keeping a reference to the original function:

it('calls testMethod on mount', () => {
  const testMethod = jest.fn()
  const wrapper = shallowMount(List, {
    methods: {
      testMethod
    }
  })

  expect(testMethod).toBeCalled()
});

I'm having a similar issue here.

"@vue/test-utils": "^1.0.0-beta.25"
"jest": "^23.6.0"
"vue-jest": "^2.6.0"
MacOS: 10.14.2 (18C54)

The failing message I'm getting is

● AccountsFetchAccounts › methods › fetchAccountName()

  expect(jest.fn())[.not].toHaveBeenCalled()

  jest.fn() value must be a mock function or spy.
  Received:
    function: [Function bound mockConstructor]
const localVue = createLocalVue();
let wrapper;
let methods = {
  fetchAccountName: jest.fn(() => 'Empty'),
  fetchChildAccountsData: jest.fn(),
};
let computed = {
  instance: jest.fn().mockReturnValue({post: jest.fn(), get: jest.fn()}),
  accountId: jest.fn().mockReturnValue(1)
};
function shallowMountComponent() {
  return shallowMount(AccountsFetchAccounts, {
    localVue,
    methods,
    computed,
  });
}

describe('methods', () => {
  let spy;
  it('created() should get called when component mounts.', () => {
    spy = jest.spyOn(AccountsFetchAccounts, 'created');
    wrapper = shallowMountComponent();
    expect(spy).toHaveBeenCalled();
    spy.mockReset();
  });
  it('fetchAccountName() its been called.', () => {
    let { vm } = shallowMountComponent();
    vm.fetchAccountName();
    expect(vm.fetchAccountName).toHaveBeenCalled();
    // setTimeout(() => {
    // });
  });
});

The first test passes fine. I'm having problems with the second test though. If I take the expect(vm.fetchAccountName).toHaveBeenCalled(); and put it inside the setTimeout() the test pass, outside the setTimeout() doesn't pass. I did try the following without success. I'm trying to figure this out but can't get it to work without setTimeout(). Any help is appreciated.

it('fetchAccountName()', async () => {
  let { vm } = shallowMountComponent();
  await vm.fetchAccountName();
  expect(vm.fetchAccountName).toHaveBeenCalled();
  // setTimeout(() => {
  // });
});

It seems that deprecating the ability to set methods has made the upvoted answer above an approach that has ceased to work. Is there a new way to test logic in lifecycle hooks?

Hook in component

private mounted(): void {
    this.getStuff();
}

Test (not working, obviously, but an example of what I'm trying to test)

  it("getStuff() is called on mounted", () => {
    const getStuff = jest.fn();
    wrapper = mountFunction();
    expect(getStuff).toBeCalled();
    wrapper.destroy();
  });

Vue binds methods when it adds them to an instance, so the method on an instance is not a reference to the original function. You can solve your issue by keeping a reference to the original function:

it('calls testMethod on mount', () => {
  const testMethod = jest.fn()
  const wrapper = shallowMount(List, {
    methods: {
      testMethod
    }
  })

  expect(testMethod).toBeCalled()
});

What about this?

[vue-test-utils]: overwriting methods via themethodsproperty is deprecated and will be removed in the next major version. There is no clear migration path for themethodsproperty - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex method extract it from the component and test it in isolation. Otherwise, the suggestion is to rethink those tests.

Hi! The original comment was posted on 15 Nov 2018, more than two years ago. The deprecation message offers a couple of alternatives to overriding methods directly.

Was this page helpful?
0 / 5 - 0 ratings