15

I have a Vue page like this:

<template>
</template>

<script>
created(){
    this.doSomething();
}

methods: {
    doSomething() {
        .....
    }
}

</script>

Now, we want to the testing of this created hook and check that doSomething() method is called.

Tried like this, jest is also imported in package.json

import {
  shallowMount,
  createLocalVue,
} from '@vue/test-utils';

const localVue = createLocalVue();

import Xyx from '/Xyx.vue';

const init = () => {
  wrapper = shallowMount(Xyx, { localVue });
  cmp = wrapper.vm;
};

describe('#created', () => {
  it('#doSomething', () => {
    init();
    wrapper.setMethods({
      doSomething: jest.fn(),
    })
    expect(cmp.doSomething).toHaveBeenCalled();
  });
});

Can I do the unit test case of this created hook?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Neeladri Rudra
  • 151
  • 1
  • 1
  • 4

3 Answers3

11

The methods option was deprecated in v1 of @vue/test-utils, so the accepted answer no longer works. I ran into this issue myself and decided to dig into the source to figure out how I could test this.

It looks like Vue actually stores all the hooks in the $options property. Each hook has an option that is an array of functions. It is important to note that a context is not bound to said functions, so you will need to use call or apply to execute them.

vm.$options.created.forEach(hook => {
  hook.call(vm);
});
callmehiphop
  • 636
  • 5
  • 10
10

Because your method is called on created, it is run before you are setting the mock. Therefore, your test will fail.
You have to replace the method with the mock on initialization (in your case, on shallowMount):

describe('Xyz', () => {
  it('should call doSomething() when created', () => {
    const doSomething = jest.fn()
    wrapper = shallowMount(Xyz, {
      localvue,
      methods: { doSomething }
    });
    expect(doSomething).toHaveBeenCalled();
  });
});

Sidenote: you're not declaring cmp. At the start of your test, you should have a let cmp;


A very similar discussion here. Above the linked comment there's a method to mock properties of most Vue component lifecycle hooks.

tao
  • 82,996
  • 16
  • 114
  • 150
  • 2
    Should it be `expect(doSomething).toHaveBeenCalled();` Otherwise, you will be met with an error `Matcher error: received value must be a mock or spy function` – WhosDustin May 13 '20 at 14:40
  • 1
    @tao, thank you for the method. However, `expect(wrapper.vm.doSomething)` didn't work for me and returned the error specified by @WhosDustin. @WhosDustin, thank you for the correction, my test ran successfully with it. – elushnikova May 30 '20 at 12:07
  • @elushnikova, please ask a new question and provide the relevant code. If you've done the above (mocked the method, placed it in methods of shallowMount or mount and done whatever that component should do in order to trigger the method) it should work. Without seeing your code, I can't help. The error *per-se* states that you can't assess whether or not the method was called because it wasn't mocked (it wasn't replaced with a spy function, as in my example). – tao May 30 '20 at 12:15
  • I also confirm error mentioned by @WhosDustin, and his solution works – Alonad Jul 05 '20 at 12:28
1

It's possible to call hooks when we need in our tests. For example if we need to mock some data before calling a hook.

import App from '@/App.vue';

// in test
App.created.call(wrapper.vm);

Also in Typescript if we use vue-property-decorator it changes the shape of component, so needs to be done like this:

App.extendOptions.created.call(wrapper.vm)
Alonad
  • 1,986
  • 19
  • 17