I'm learning unit testing with jest. I can not understand the difference between the jest.createMockFromModule and jest.mock. Seems that they do the same? Can someone please explain me the difference?
jest.mock - does module auto-mocking and implicitly replaces imported module in the test file.
If you provide fabric function by the second argument it will define the module implementation like:
jest.mock('./moduleName', () => ({
default: 12345 // default constant definition
MyClass: { // Named export object or class definition
get: () => { /* get method class definition */ }
}
/* etc... */
}))
You also can override only part of imported module.
jest.createMockFromModule - generates auto-mocked module and returns it as a value. It useful in the manual mocking. You can override required module values:
// __mocks__/MyModule.js
const moduleName = jest.createMockFromModule('./moduleName');
moduleName.someNamedImport = () => 12345; // override method implementation
expect(moduleName.default.mocked).toBeTruthy(); // to check default import auto-mocking
expect(moduleName.someNamedImport()).toBe(12345)
I'm trying to test a module using jest. In the module, I have a function which works as a kind of front to two other functions, and delegates to them based on its parameter. I'm trying to figure out if these functions have indeed been called.
I have tried using a spy function, but it is never called. Instead, the actual function is called, bypassing my spy.
All examples I have found with mocking and spies involve mocking and spying on another module than the one being tested, but in this case I am trying to spy on a function from the module being tested. Is this even possible? Is there a better way to do this?
Example code:
// funcs.js
const decide = obj => {
if (obj.a !== undefined) {
return funcA(obj);
} else {
return funcB(obj);
}
};
const funcA = obj => obj.a;
const funcB = obj => obj.b;
export { decide, funcA, funcB };
// funcs.test.js
import * as fns from "./funcs";
describe("decide", () => {
it("should delegate to 'funcA' when the parameter has an 'a' property", () => {
const spy = jest.spyOn(fns, "funcA");
fns.decide({ a: "Cake" });
expect(spy).toHaveBeenCalled(); // Error! Number of calls: 0
});
});
There's no way to spy or mock a function that is called in the same ES module it is defined.
This is possible for CommonJS modules but only if functions are consistently referred as methods:
exports.decide = obj => {
...
exports.funcA(obj);
...
};
exports.funcA = obj => obj.a;
It's possible to adopt this recipe to ES modules but this discards their benefits:
const exports = {};
export default exports;
// same as CommonJS
funcA and funcB should be either moved to separate module for testability purposes and be spied or mocked with jest.mock, or all of them should be tested as a single unit.
I'm trying to mock an external dependency in my Jest test.
My goal is to validate that the dependency was called with some specified arguments.
The dependency exports a default function, which makes it hard (impossible?) to use jest.SpyOn.
I've tried using jest.mock as follows:
const callback = jest.fn(() => 'output');
jest.mock('dependecy', () => callback);
it('call dep with some args' () => {
...
expect(callback).toBeCalledWith('arg1' , 'arg2')
});
Also tried jest.mock('dependecy', () => ({ default: callback }));.
But neither where successful, I was thinking this was because of the hoisting of jest.mock. Thus I've tried jest.doMock, but this does not even seem to call/create my mock.
Any ideas on how to validate that a method was called on an external dependency that exports a default function in jest?
Here is a simple working example that should get you going:
code.js
import dependency from 'dependency';
export const func = () => 'returned ' + dependency();
code.test.js
import { func } from './code';
import dependency from 'dependency'; // <= dependency will be...
jest.mock('dependency', () =>
jest.fn(() => 'mocked') // <= ...this mock function
);
describe('func', () => {
it('should call dependency', () => {
const result = func();
expect(result).toBe('returned mocked'); // Success!
expect(dependency).toHaveBeenCalled(); // Success!
});
});
Note that the module factory function must be self-contained so it can be hoisted by babel-jest.
Roughly, my JavaScript function that I want to unit-test looks like this:
const request = require('request-promise-native');
async function callServer() {
// Prepare parameters
// Call `request` with parameters
// Parse response JSON and return
}
Is there any way to unit-test this function without making an actual call to the real server? Can I use a jest mock function to somehow override request()? To do that, will I need to modify every function to take the request function as a parameter or there is another way?
You can mock imported module via jest.mock. https://jestjs.io/docs/en/api#requirerequiremockmodulename
describe('main description', () => {
it('description of test case', () => {
jest.mock('request-promise-native', () => {
return {}; // Return what the request-promise-native supposed to return
});
const result = callServer();
expect(result).toBe({});
});
});
I have the following module I'm trying to test in Jest:
// myModule.js
export function otherFn() {
console.log('do something');
}
export function testFn() {
otherFn();
// do other things
}
As shown above, it exports some named functions and importantly testFn uses otherFn.
In Jest when I'm writing my unit test for testFn, I want to mock the otherFn function because I don't want errors in otherFn to affect my unit test for testFn. My issue is that I'm not sure the best way to do that:
// myModule.test.js
jest.unmock('myModule');
import { testFn, otherFn } from 'myModule';
describe('test category', () => {
it('tests something about testFn', () => {
// I want to mock "otherFn" here but can't reassign
// a.k.a. can't do otherFn = jest.fn()
});
});
Any help/insight is appreciated.
Use jest.requireActual() inside jest.mock()
jest.requireActual(moduleName)
Returns the actual module instead of a mock, bypassing all checks on whether the module should receive a mock implementation or not.
Example
I prefer this concise usage where you require and spread within the returned object:
// myModule.test.js
import { otherFn } from './myModule.js'
jest.mock('./myModule.js', () => ({
...(jest.requireActual('./myModule.js')),
otherFn: jest.fn()
}))
describe('test category', () => {
it('tests something about otherFn', () => {
otherFn.mockReturnValue('foo')
expect(otherFn()).toBe('foo')
})
})
This method is also referenced in Jest's Manual Mocks documentation (near the end of Examples):
To ensure that a manual mock and its real implementation stay in sync, it might be useful to require the real module using jest.requireActual(moduleName) in your manual mock and amending it with mock functions before exporting it.
Looks like I'm late to this party, but yes, this is possible.
testFn just needs to call otherFn using the module.
If testFn uses the module to call otherFn then the module export for otherFn can be mocked and testFn will call the mock.
Here is a working example:
myModule.js
import * as myModule from './myModule'; // import myModule into itself
export function otherFn() {
return 'original value';
}
export function testFn() {
const result = myModule.otherFn(); // call otherFn using the module
// do other things
return result;
}
myModule.test.js
import * as myModule from './myModule';
describe('test category', () => {
it('tests something about testFn', () => {
const mock = jest.spyOn(myModule, 'otherFn'); // spy on otherFn
mock.mockReturnValue('mocked value'); // mock the return value
expect(myModule.testFn()).toBe('mocked value'); // SUCCESS
mock.mockRestore(); // restore otherFn
});
});
import m from '../myModule';
Does not works for me, I did use:
import * as m from '../myModule';
m.otherFn = jest.fn();
I know this was asked a long time ago, but I just ran into this very situation and finally found a solution that would work. So I thought I'd share here.
For the module:
// myModule.js
export function otherFn() {
console.log('do something');
}
export function testFn() {
otherFn();
// do other things
}
You can change to the following:
// myModule.js
export const otherFn = () => {
console.log('do something');
}
export const testFn = () => {
otherFn();
// do other things
}
exporting them as a constants instead of functions. I believe the issue has to do with hoisting in JavaScript and using const prevents that behaviour.
Then in your test you can have something like the following:
import * as myModule from 'myModule';
describe('...', () => {
jest.spyOn(myModule, 'otherFn').mockReturnValue('what ever you want to return');
// or
myModule.otherFn = jest.fn(() => {
// your mock implementation
});
});
Your mocks should now work as you would normally expect.
The transpiled code will not allow babel to retrieve the binding that otherFn() is referring to. If you use a function expession, you should be able to achieve mocking otherFn().
// myModule.js
exports.otherFn = () => {
console.log('do something');
}
exports.testFn = () => {
exports.otherFn();
// do other things
}
// myModule.test.js
import m from '../myModule';
m.otherFn = jest.fn();
But as #kentcdodds mentioned in the previous comment, you probably would not want to mock otherFn(). Rather, just write a new spec for otherFn() and mock any necessary calls it is making.
So for example, if otherFn() is making an http request...
// myModule.js
exports.otherFn = () => {
http.get('http://some-api.com', (res) => {
// handle stuff
});
};
Here, you would want to mock http.get and update your assertions based on your mocked implementations.
// myModule.test.js
jest.mock('http', () => ({
get: jest.fn(() => {
console.log('test');
}),
}));
Basing on Brian Adams' answer this is how I was able to use the same approach in TypeScript. Moreover, using jest.doMock() it's possible to mock module functions only in some specific tests of a test file and provide an individual mock implementations for each of them.
src/module.ts
import * as module from './module';
function foo(): string {
return `foo${module.bar()}`;
}
function bar(): string {
return 'bar';
}
export { foo, bar };
test/module.test.ts
import { mockModulePartially } from './helpers';
import * as module from '../src/module';
const { foo } = module;
describe('test suite', () => {
beforeEach(function() {
jest.resetModules();
});
it('do not mock bar 1', async() => {
expect(foo()).toEqual('foobar');
});
it('mock bar', async() => {
mockModulePartially('../src/module', () => ({
bar: jest.fn().mockImplementation(() => 'BAR')
}));
const module = await import('../src/module');
const { foo } = module;
expect(foo()).toEqual('fooBAR');
});
it('do not mock bar 2', async() => {
expect(foo()).toEqual('foobar');
});
});
test/helpers.ts
export function mockModulePartially(
modulePath: string,
mocksCreator: (originalModule: any) => Record<string, any>
): void {
const testRelativePath = path.relative(path.dirname(expect.getState().testPath), __dirname);
const fixedModulePath = path.relative(testRelativePath, modulePath);
jest.doMock(fixedModulePath, () => {
const originalModule = jest.requireActual(fixedModulePath);
return { ...originalModule, ...mocksCreator(originalModule) };
});
}
Mocking functions of a module is moved to helper function mockModulePartially located in a separate file so it can be used from different test files (which, in common, can be located in other directories). It relies on expect.getState().testPath to fix path to a module (modulePath) being mocked (make it relative to helpers.ts containing mockModulePartially). mocksCreator function passed as a second argument to mockModulePartially should return mocks of the module. This function receives originalModule and mock implementations can optionally rely on it.
I solved my problem with a mix of the answers that I found here:
myModule.js
import * as myModule from './myModule'; // import myModule into itself
export function otherFn() {
return 'original value';
}
export function testFn() {
const result = myModule.otherFn(); // call otherFn using the module
// do other things
return result;
}
myModule.test.js
import * as myModule from './myModule';
describe('test category', () => {
let otherFnOrig;
beforeAll(() => {
otherFnOrig = myModule.otherFn;
myModule.otherFn = jest.fn();
});
afterAll(() => {
myModule.otherFn = otherFnOrig;
});
it('tests something about testFn', () => {
// using mock to make the tests
});
});
On top of the first answer here, you can use babel-plugin-rewire to mock imported named function too. You can check out the section superficially for
named function rewiring.
One of the immediate benefits for your situation here is that you do not need to change how you call the other function from your function.