How to mock function using jest.fn() - jestjs

The jest document says, There are two ways to get your hands on mock functions: Either by require()ing a mocked component (via jest.mock('moduleName')) or by explicitly requesting one from jest.fn() in your test:
So I am trying mocking a function thinking whenever a test makes a call to the minus function, it executes the mocked function and returns 10 instead of a*b but it's not working the way I thought.
app.js:
function add(a, b) {
return multiply(a, b) + b;
}
function multiply(a, b) {
return a * b;
}
module.exports = add;
add-test.js
const add = require('./add');
describe('add', () => {
it('should add two numbers', () => {
const multiply = jest.fn((a, b) => {10})
expect(add(1, 2)).toBe(12);
});
});
Note: If I change expect(add(1, 2)).toBe(12); to expect(add(1, 2)).toBe(4); the test will pass, but I want to mock multiply and return 10. So when I actually call made to multiply function then it should invoke mocked function and not real implementation.

You will have to change the structure of app.js slightly to test this the way you want.
You can either extract multiply() into its own file like this:
mulitiply.js
function multiply(a, b) {
return a * b;
}
app.js
function add(a, b) {
return multiply(a, b) + b;
}
add.test.js
const add = require('./add');
const multiply = require('./multiply');
jest.mock('multiply', () => jest.fn(a, b) => 10)
describe('add', () => {
it('adds the numbers', () => {
expect(add(1, 2)).toBe(12);
});
});
or change the implementation to be something like this:
add.js
function add(multiply) {
multiply()
}
add.test.js
const add = require('./add');
describe('add', () => {
it('adds the numbers', () => {
const multiply = jest.fn(a,b) => 10;
expect(add(multiply(1, 2)).toBe(12);
});
});

Related

How do I get rid of unused variable warning on double arrow function?

I am getting an unused variable (for 'dispatch') for both getPlanA and getPlanB functions...
How do I (or can I) pass 'dispatch' to the 'getPlan' function to get rid of the unused var warning?
export const getPlanA = (id) => (dispatch) => {
return getPlan(userId, true);
};
export const getPlanB = (id) => (dispatch) => {
return getPlan(userId, false);
};
const getPlan = (id, isPlanA) => (dispatch) => {
if(isPlanA){
dispatch(setPlanALoading());
} else {
dispatch(setPlanBLoading());
}
}
NOTE: this code comes from a REACT project, these are the action functions that will call an API...
The problem is that getPlanA and getPlanB don't use the dispatch parameter, because they're calling getPlan incorrectly.
getPlan is a function that creates a function. If you want to "bake in" the plan A / B aspect in getPlanA/getPlanB, they should return the function getPlan returns, not create their own function, like this:
export const getPlanA = (id) => {
return getPlan(id, true);
};
export const getPlanB = (id) => {
return getPlan(id, false);
};
const getPlan = (id, isPlanA) => (dispatch) => {
if (isPlanA) {
dispatch(setPlanALoading());
} else {
dispatch(setPlanBLoading());
}
};
(Note that I also changed the userId parameter to id to match what you used when calling getPlan.)
How do I (or can I) pass 'dispatch' to the 'getPlan' function...
Just for clarity: You don't, in getPlanA/getPlanB. getPlan isn't the function that expects to receive dispatch, it's the function getPlan returns that expects to receive dispatch. So getPlanA/getPlanB just return that function to the caller, and it's the caller's responsibility to call it (when/if appropriate), just like it is with getPlan.

Put time limit on Jest test?

I'm running a set of tests with Jest to demonstrate Big O using two different methods for Fibonacci.
const fastFib = require('./../fastFib');
const slowFib = require('./../slowFib');
test('Fast way of getting Fibonacci of 44', () => {
expect(fastFib(44)).toBe(701408733);
});
test('Slow way of getting Fibonacci of 44', () => {
expect(slowFib(44)).toBe(701408733);
});
I'm wondering if there is a way to specify the maximum length of a test? I saw you can pass a third variable for an async timeout but it doesn't seem to have any effect on normal functions:
test('Slow way of getting Fibonacci of 44', () => {
expect(slowFib(44)).toBe(701408733);
}, 5000);
Is there a way I can specify the maximum execution time for a function with Jest?
I will share slowFib.js for reference:
function fib(n) {
return (n<=1) ? n : fib(n - 1) + fib(n - 2);
}
module.exports = fib;
so your test pauses because of sync execution - there is no way to interrupt that by timeout. You need to "split execution". Next version fails to me:
test('Slow way of getting Fibonacci of 44', (done) => {
expect(slowFib(44)).toBe(701408733);
setTimeout(done, 10); // smallest timeout possible to make different macrotask
}, 5000);
PS I also believe this should be achievable by marking test async but have not yet figured how exactly.
[UPD] you actually may achieve your goal without using test's timeout:
test('Slow way of getting Fibonacci of 44', () => {
const start = new Date();
expect(slowFib(44)).toBe(701408733);
expect(new Date() - start).toBeLessThan(5000);
});
In your test file you can set
jest.setTimeout(5000); which overrides the default timeout for a test case in jest
I think you would need to implement your own timer (with setTimeout or using Promises). One alternative would be to use the async keyword for your function to make it work with the built-in parameter :
test('Slow way of getting Fibonacci of 44', async () => {
expect(slowFib(44)).toBe(701408733);
}, 5000);
Here's a (typescript friendly) functions inspired by #skyboyer's suggestion.
(tested using Jest 24.8.0, but should be relevant to any version)
// Takes a threshold and a callback.
// if the callback didn't run within the threshold, the returned function will evaluate to a rejected promise.
// else, the returned function will evaluate to a resolved promise with the value returned by 'cb' (T)
const resolveWithin = <T>(threshold: number, cb: () => T): () => Promise<T> => {
return () => {
const start = Date.now();
return Promise.resolve(cb()).then((t: T) => {
const elapsed = Date.now() - start;
if (elapsed > threshold) {
return Promise.reject(elapsed);
}
return Promise.resolve(t);
});
}
};
// Uses "resolveWithin" to ensure a test has run within the threshold.
const withIn = <T>(threshold: number, fn: () => T): () => Promise<T> => {
const cb = resolveWithin(threshold, fn);
// #ts-ignore
return () => {
return cb().catch((elapsed) => {
expect(elapsed).toBeLessThanOrEqual(threshold);
})
}
};
it("example", withIn(1000, () => { ... }));
it("example", withIn(1000, async () => { ... }));
A note regarding #Khaled Osman's / #HRK44 answers.
From what I could tell, using either approach will not be reflected as a test failure, and will not appear in reports generated by Jest.

Jest spying on function called from within another

I have the following two files:
functions.js
function getOne() {
return 1;
}
function getTen() {
let val = 0;
for (let x = 0; x < 10; x++) {
val+= getOne();
}
return val;
}
module.exports = {
getOne,
getTen,
}
functions.test.js
const numberFunctions = require('../functions.js');
const getOne = numberFunctions.getOne;
const getTen = numberFunctions.getTen;
// passes
test('I should be able to get the number 1', () => {
expect(getOne()).toBe(1);
});
describe('The getTen function', () => {
// passes
it('should return 10', () => {
expect(getTen()).toBe(10);
});
// fails
it('should call the getOne method 10 times', () => {
const spy = jest.spyOn(numberFunctions, 'getOne');
expect(spy).toHaveBeenCalledTimes(10);
});
});
I'm trying to ensure that the the function getOne has been called from within the getTen function. In total it should be called 10 times, but my spy always claims that it has been called zero times.
I've tried rearranging my test so that I mock the getOne function as a global e.g.
it('should call the getOne method 10 times', () => {
global.getOne = jest.fn(() => 1);
expect(global.getOne).toHaveBeenCalledTimes(10);
});
But this results in the same outcome. How can I spy on the getOne function being called from within the getTen function?
I managed to get this working by changing the getOne function called by getTen to directly reference the one exported by the function. Otherwise it seems to be referencing some internally scoped function which is not the one that is exported, making it impossible to spy on.
This is explained in more detail in this github conversation, but to get my test to work as expected meant that I had to refactor my code to be:
function getOne() {
return 1;
}
function getTen() {
let val = 0;
for (let x = 0; x < 10; x++) {
val+= module.exports.getOne(); // <-- this line changed
}
return val;
}
module.exports = {
getOne,
getTen,
}
Now, rather than being internally scoped, the inner function refers to the exported one and can be spied on.

Accessing .mock property of an automocked function

I have this code:
import * as a from 'a-a';
jest.mock('a-a');
describe('a-a', () => {
beforeAll(async () => {
const x = await a.x(1); // Calls the mock
console.log(x); // 1
console.log(a.x.mock) // Undefined
});
});
The mock function is:
export async function x(data) {
cache.push(data);
console.log('HERE'); // this is printed
return data;
}
The mock of the module is in the __mocks__ directory.
The a.x() calls the mocked function, but a.x.mock is undefined.
How is that possible? Where is the .mock property?
So, after some investigation I found out that the functions declared in the __mocks__ directory aren't wrapped by jest.fn() by default.
Personally I find the thing a bit confusing.
So you can do both
function x(data) {
cache.push(data);
return cache;
}
jest.mock('a-a', () => ({x: x}))
if you do everything in the same file, or
jest.mock('a-a');
and then in the __mocks__/a-a.js file
export const x = jest.fn(async (data) => {
cache.push(data);
return cache;
});

How to test javascript function independently with mocha chai and sinon?

I am new to unit testing and have been reading a few tutorials about this practice with javascript. I will use a silly example to explain my problem.
Let's say John needs to go to school and before knowing if he's ready to go he has to check if he has his bag and his headphones. This would be called with the following function:
john.isReadyToGo;
The implementation of the isReadtToGo() function for a character object is as follows:
characher.isReadyToGo = function() {
return this.hasBag() && this.hasHeadPhones();
}
characher.hasBag = function() {
// return true or false
}
characher.hasHeadPhones = function() {
//return true or false
}
Now, let's say I want to test this function. In unit testing it is recommended to test functions without them being affected by other functions. This means that in this case I would have to test the three functions but the character.isReadyToGo() function would need to have mock values for this.hasBag() and this.hasHeadPhones(). Am I right?
If so, could you give me a hint on how I can mock these two values?
Here's an example:
let character = {};
character.isReadyToGo = function() {
return this.hasBag() && this.hasHeadPhones();
}
character.hasBag = function() {
// return true or false
}
character.hasHeadPhones = function() {
//return true or false
}
const sinon = require('sinon');
const expect = require('chai').expect;
describe('Is character ready?', () => {
beforeEach(() => {
sinon.stub(character, 'hasBag');
sinon.stub(character, 'hasHeadPhones');
});
afterEach(() => {
character.hasBag.restore();
character.hasHeadPhones.restore();
});
it("Not if they don't have a bag or headphones", () => {
character.hasBag.returns(false);
character.hasHeadPhones.returns(false);
expect(character.isReadyToGo()).to.be.false;
});
it("Not if they have headphones but no bag", () => {
character.hasBag.returns(false);
character.hasHeadPhones.returns(true);
expect(character.isReadyToGo()).to.be.false;
});
it("Not if they have a bag but no headphones", () => {
character.hasBag.returns(true);
character.hasHeadPhones.returns(false);
expect(character.isReadyToGo()).to.be.false;
});
it("Yes, if they have a bag and headphones", () => {
character.hasBag.returns(true);
character.hasHeadPhones.returns(true);
expect(character.isReadyToGo()).to.be.true;
});
});
For each test, this stubs character.hasBag and character.hadHeadphones (this is done in beforeEach). This basically replaces the original with a new function (the stub) that you can control.
Depending on the test, the stub is "told" what to return for each function (using .returns()), isReadyToGo is called, and its result is checked against the expectation.
After each test, the stub is restored (meaning that the original function is restored).

Resources