23

Putting in a small snippet below :

import xyz from '../xyz'
function calculate() {
  return xyz(arg1, arg2).catch((err) => {
    func1()
    func2()
  })
}
export default calculate

I'm just trying to assert that xyz is called in jest. How can I do it ?

I tried the following but doesn't work :

import * as myModule from '../xyz'
import calculate from '../../calculate'
const mock = jest.spyOn(myModule, 'xyz')
mock.mockReturnValue('mocked value')
const op = calculate()
expect(op).toBe('mocked value')

This gives me the following error:

Cannot spy the xyz property because it is not a function; undefined given instead

cassmtnr
  • 927
  • 13
  • 26
user2821242
  • 1,041
  • 3
  • 9
  • 16

2 Answers2

10

You can mock the module like this:

import calculate from '../../calculate'
jest.mock('../xyz', ()=> () => Promise.resolve('mocked value'))

it('does something', async()=>{
  const op = await calculate()
  expect(op).toBe('mocked value')
})

if you need different return values from your mock you need to mock the module so it returns a spy. Then you have to import the module and you can set the return value during your tests:

import calculate from '../../calculate'
import myModule from '../xyz'
jest.mock('../xyz', ()=> jest.fn())

it('does something', async() => {
  myModule.mockImplementation(() => () =>  Promise.resolve('mocked value'))

  const op = calculate()
  expect(op).toBe('mocked value')
})

it('does something else', async() => {
  myModule.mockImplementation(() => () =>  Promise.resolve('another value'))
  const op = await calculate()
  expect(op).toBe('another value')
})


it('does fail', async() => {
  myModule.mockImplementation(() => () =>  Promise.reject('some Error')
  try{
    const op = await calculate()
  }catch (e){
    expect(e).toBe('some Error')
  }
})

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • Thanks for suggesting TypeError: (0 , _xyz2.default)(...).catch is not a function with the first approach @andreas – user2821242 Mar 06 '19 at 11:01
  • Also, why can I not assert that xyz is called in calculate test ? – user2821242 Mar 06 '19 at 11:08
  • argh, sorry I overlooked the `catch` part, will update my answer – Andreas Köberle Mar 06 '19 at 12:05
  • 1
    How would you do this if you were mocking the functionality of an imported class? – wattry Oct 21 '20 at 00:04
  • 49
    I don't think this answers the question, the OP is wondering how they can spy on a function, while the answer mocks the function. I could be wrong, however if you spy you keep the implementation of the function, where if you mock you remove it. – Charklewis Feb 22 '21 at 03:15
  • 3
    This code doesn't work, at least in Typescript. `myModule` is the original function so I don't understand how it would have a `mockImplementation` property. Surely not from executing this line first: `jest.mock('../xyz', ()=> jest.fn())` – mellis481 Oct 20 '21 at 17:07
-1

There's no need to mock, which is something of a broad sword, since it works at the module level. Jest's spyOn is a more focussed way of doing this, since it is at the method level.

The confusion here is solely because of the internal workings of 'xyz'. You have assumed that the module called 'xyz' has a function within it also called 'xyz'. Hence Jest fails to find it.

If we assume that 'xyz' is actually the default export of the 'xyz' module, we can test using this:

const mock = jest.spyOn(myModule, 'default')

All of the rest of your test code is perfect:

mock.mockReturnValue('mocked value')
const op = calculate()
expect(op).toBe('mocked value')
Paul F. Wood
  • 1,453
  • 16
  • 19