In Jest, to spy (and optionally mock the implementation) on a method, we do the following:
const childProcess = require('child_process');
const spySpawnSync = jest.spyOn(childProcess, 'spawnSync').mockImplementation();
This allows us to use spySpawnSync
to check what arguments it was last called with, like so:
expect(spySpawnSync).lastCalledWith('ls');
However, this is not possible with Node modules that export a function, such as with the execa package.
I tried each the following, but none of them spy or mock the function:
// Error: `Cannot spy the undefined property because it is not a function; undefined given instead`
jest.spyOn(execa);
// Error: `Cannot spyOn on a primitive value; string given`
jest.spyOn('execa');
// Error: If using `global.execa = require('execa')`, then does nothing. Otherwise, `Cannot spy the execa property because it is not a function; undefined given instead`.
jest.spyOn(global, 'execa');
Therefore, is there any way to spy on modules that export a function, such as execa
in the given example?
I had the exact same need and problem with execa
, and here's how I made it work:
import execa from 'execa'
jest.mock('execa', () => jest.fn())
test('it calls execa', () => {
runSomething()
expect(execa).toHaveBeenCalled()
})
So basically, since the imported module is the function itself, what you do is mock the whole module with jest.mock
, and simply return a Jest mock function as its replacement.
Since jest.fn()
is what jest.spyOn()
relies on under the hood, you benefit from the same assertion methods in your tests :)