How to test Vue Component method call within an async method

2.3k Views Asked by At

I believe I am struggling to properly mock my methods here. Here is my situation, I have a component with two methods;

    name: 'MyComponent',
    methods: {
       async submitAction(input) {
           // does await things
           // then ...
           this.showToastMessage();
       },
       showToastMessage() {
           // does toast message things
       },
    }

And I want to write a test that will assert that showToastMessage() is called when submitAction(input) is called. My basic test looking something like this;

    test('the toast alert method is called', () => {
      let showToastMessage = jest.fn();
      const spy = jest.spyOn(MyComponent.methods, 'showToastMessage');
      const wrapper = shallowMount(MyComponent, { localVue });

      const input = // some input data
      wrapper.vm.submitAction(input); // <--- this calls showToastMessage
      expect(spy).toHaveBeenCalled();
    };

NOTE: localVue is declare as such at the top of the file const localVue = createLocalVue();

I confirmed that both submitAction() and showToastMessage() methods are being called during the tests, by sneaking a couple of console.log()'s and observing it in the test output, however the test still fails;

    expect(jest.fn()).toHaveBeenCalledWith(...expected)

    Expected: called with 0 arguments

    Number of calls: 0

      566 |           const wrapper = shallowMount(MyComponent, { localVue } );
      567 |           wrapper.vm.submitAction(input);
    > 568 |           expect(spy).toHaveBeenCalledWith();

I've tried spying on both methods as well

    const parentSpy = jest.spyOn(MyComponent.methods, 'submitAction');
    const spy = jest.spyOn(MyComponent.methods, 'showToastMessage');
    // ...
    expect(spy).toHaveBeenCalled()

same results, test fail.

What am I missing?

Tech Stack: vue 2, jest, node 14

2

There are 2 best solutions below

0
On BEST ANSWER

Took me a minute to realize/try this, but looks like since my calling function is async that I was suppose to make my test async, and await the main method call. This seems to have done the trick. Here's what ended up being my solution:

    test('the toast alert method is called', async () => {
      let showToastMessage = jest.fn();
      const spy = jest.spyOn(MyComponent.methods, 'showToastMessage');
      const wrapper = shallowMount(MyComponent, { localVue });

      const input = // some input data
      await wrapper.vm.submitAction(input);
      expect(spy).toHaveBeenCalled();
    };
2
On

@TekkSparrow you can pass a heap of stuff into the shallowMount function. It accepts an object as a second argument which can look something like

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

const localVue = createLocalVue()
localVue.use(Vuex)

let mocks = {
  // this could be something like the below examples
  // I had in a previous project
  $route: {
    query: '',
    path: '/some-path'
  },
  $router: [],
  $validator: {
    validateAll: jest.fn()
  },
  $toast: {
    show: jest.fn(),
    error: jest.fn()
  },
}
let propsData = {
  // some props you want to overwrite or test.
  // needs to be called propsData
}
let methods = {
  showToastMessage: jest.fn()
}
let store = new Vuex.Store({
  actions: {
    UPLOAD_ASSET: jest.fn(),
  },
})

const wrapper = shallowMount(MyComponent, { mocks, propsData, methods, store, localVue })

I believe that by doing similar to the above, your mocked function will run and be recorded by the Jest spy.