Vue checking if action calls other action with spyOn
Asked Answered
W

2

6

In Vue, I want to check if an action in my store is correctly calling another action using Jest's spyOn, I tried it different ways but it doesn't seem to work, here's my code:

// index.js

getRecipes ({ dispatch }) {
  const fruits = ['apple', 'banana', 'pear']
  fruits.forEach((fruit) => {
    dispatch('getRecipe', fruit)
  })
},
async getRecipe ({ commit }) {
  const recipe = await recipesService.fetchRecipe(payload)

  commit(SET_RECIPE, { recipe })
},

// index.spec.js

test('getRecipes calls getRecipe 3 times, each with the right fruit', () => {
  const commit = jest.fn()
  const dispatch = jest.fn()
  const spy = spyOn(actions, 'getRecipe')
  const result = actions.getRecipes({ commit, dispatch })

  expect(spy).toHaveBeenCalledTimes(3)
  expect(spy).toHaveBeenCalledWith('apple')
})

But when I run the tests, this is the output I get:

Expected spy to have been called three times, but it was called zero times.

I have other places where I want to test these kind of integrations (an action calling another one), but it still gives me this error.

Wasting answered 7/12, 2018 at 11:49 Comment(0)
L
9

Test only your code, not vuex's

The problem with this kind of test, is that you're testing that vuex works as expected, which is probably worthless.

Instead of spy directly on the actions, and assert that vuex correctly calls the getRecipe action when dispatch('getRecipe', fruit) is called, I would test just that the getRecipes action calls dispatch properly:

test('getRecipes dispatches 3 "getRecipe" actions, each with the right fruit', () => {
  const commit = jest.fn()
  const dispatch = jest.fn()
  const result = actions.getRecipes({ commit, dispatch })

  expect(dispatch).toHaveBeenCalledTimes(3)
  expect(dispatch.mock.calls[0][0]).toBe('apple')
  expect(dispatch.mock.calls[1][0]).toBe('banana')
  expect(dispatch.mock.calls[2][0]).toBe('pear')
})

What if you still wanna test vuex integration

You're not really showing how you're importing and exporting the modules, but I guess in your code, the actions file exports just a plain object with the actions, and the test just imports it.

In your application code, it's likely that a you're adding those actions to vuex, then loading vuex into your app with:

new Vue({store})

So, in your tests, the actions module really does not know anything about vuex itself (here I'm guessing really, can't really tell from your published code but it's likely).

That's why your tests does not work as expected, because in the test the getRecipes method just gets a dispatch parameter and calls it, but vuex is not really doing anything there, so there is no way that dispatch call would invoke another action.

Now, if you want to still test this with jest, you should do it from a component, so you're testing the actions in the context of vue and vuex.

There is a good tutorial about this in the vue test utils documentation.

Lambent answered 7/12, 2018 at 12:16 Comment(0)
B
1

when you trying to test async function you need to use await

const getAsyncWithSpyOn = spyOn(actions, 'getRecipe');
expect(await getAsyncWithSpyOn()).toHaveBeenCalledTimes(3)
Blanketing answered 7/12, 2018 at 12:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.