jest.createMockFromModule vs jest.mock - unit-testing

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)

Related

How to mock an imported constant with Jasmine?

A component is meant to behave differently based on a external variable, which is used as a kind of configuration. I would like to test all the possible behaviors, but I don't get how to mock a constant variable.
I tried to use spyOnProperty as in the code below, but an error occurs, stating that the variable is not declared configurable.
// constants.js
export const DEFAULT_STATUS = 'test';
// component.spec.js
import * as constants from './constants';
// here other stuff and component init
it('should change default class based on a constant', () => {
const tmpDefaultStatus = 'test1';
spyOnProperty(constants, 'DEFAULT_STATUS', 'get').and.returnValue(tmpDefaultStatus);
expect(component.className).toBe(tmpDefaultStatus)
});
Then this error is thrown:
Error: : DEFAULT_STATUS is not declared configurable.
Is it still possible to mock that variable, without changing constant.js content?
I don't think there is. I would do:
it('should change default class based on a constant', () => {
const oldState = constants.DEFAULT_STATUS;
const tmpDefaultStatus = 'test1';
constants.DEFAULT_STATUS = tmpDefaultStatus;
expect(component.className).toBe(tmpDefaultStatus);
constants.DEFAULT_STATUS = oldState;
});
I am not sure if that test will pass or not but the idea is to change the value and take it back to its original for each test.

jest.fn() v/s jest.mock()?

For mocking uuidv4, I am using this :
import { v4 as uuidv4 } from "uuid";
jest.mock("uuid");
uuidv4.mockReturnValue("uuid123");
And for mocking window.confirm, I am using this:
window.confirm = jest.fn().mockImplementation(() => true);
These both are working all right.
But when i try doing this i.e
const uuidv4 = jest.fn.mockImplementation(() => "uuid123");
I get this error
TypeError: jest.fn.mockImplementation is not a function
I am confused between jest.fn() and jest.mock().
Can someone please elaborate on which one to use and when to use, with suitable example?
Just a quick explanation for you:
jest.mock is to mock a certain module. Once you write jest.mock('uuid') then it means all exported things would be turned to a jest.Mock type, that's why you can mock v4 method: v4.mockReturnValue('yourV4Id');
jest.mock('aModule');
import {aMember} from "aModule";
// is now a jest mock type <=> jest.fn()
aMember.mockReturnValue('a value');
jest.fn is a function which returns a jest.Mock type which can be considered as an function to create whatever you want:
const aMock = jest.fn().mockReturnValue(1) // <=> const aMock = () => 1;
// The difference is jest mock type can be used to assert then. Most of cases is to check
// whether it gets called or not

Jest: Spy on other function in module being tested

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.

How to assert a default exported function is called when mocking a module in Jest?

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.

node.js: any way to export ALL functions in a file en masse (e.g., to enable unit testing), vs. one by one

in node.js, is there any shortcut to export ALL functions in a given file? i want to do this for unit testing purposes, as my unit tests are in a separate file from my production code.
I know i can go through and export each function manually, as in:
exports.myFunction = myFunction;
But i'm wondering if there is a simpler/slicker way to do this.
(and yes, i realize for modularity reasons it isn't always a good idea to export all functions, but for unit testing purposes you do want to see all the little functions so you can test them piece by piece.)
Thanks!
You could do something like this:
// save this into a variable, so it can be used reliably in other contexts
var self = this;
// the scope of the file is the `exports` object, so `this === self === exports`
self.fnName = function () { ... }
// call it the same way
self.fnName();
Or this:
// You can declare your exported functions here
var file = module.exports = {
fn1: function () {
// do stuff...
},
fn2: function () {
// do stuff...
}
}
// and use them like this in the file as well
file.fn1();
Or this:
// each function is declared like this. Have to watch for typeos, as we're typing fnName twice
fnName = exports.fnName = function () { ... }
// now you can use them as file-scoped functions, rather than as properties of an object
fnName();
Mixin objects is the answer.
This lib can help you: https://github.com/shimondoodkin/nodejs-clone-extend
//file1.js
var _ = require('cloneextend');
_.extend(this, require('file2.js'));
file1.js has now all exports from file2.js
Here's a simple way to do it. Parse the AST and look for top level function definitions, and export those.
const esprima = require('esprima')
const program = fs.readFileSync(__filename,'utf8')
const parsed = esprima.parseScript(program)
for (let fn of parsed.body) {
if (fn.type.endsWith('FunctionDeclaration')) {
module.exports[fn.id.name] = eval(fn.id.name)
}
}