Can I mock functions with specific arguments using Jest?

I would like to make fun of the function with Jest, but only if it is called with specific arguments, for example:

function sum(x, y) { return x + y; } // mock sum(1, 1) to return 4 sum(1, 1) // returns 4 (mocked) sum(1, 2) // returns 3 (not mocked) 

A similar function is implemented in the Ruby RSpec library:

 class Math def self.sum(x, y) return x + y end end allow(Math).to receive(:sum).with(1, 1).and_return(4) Math.sum(1, 1) # returns 4 (mocked) Math.sum(1, 2) # returns 3 (not mocked) 

What I'm trying to achieve in my tests is better to untie it, say, I want to test a function that relies on sum :

 function sum2(x) { return sum(x, 2); } // I don't want to depend on the sum implementation in my tests, // so I would like to mock sum(1, 2) to be "anything I want", // and so be able to test: expect(sum2(1)).toBe("anything I want"); // If this test passes, I've the guarantee that sum2(x) is returning // sum(x, 2), but I don't have to know what sum(x, 2) should return 

I know that there is a way to implement this by doing something like:

 sum = jest.fn(function (x, y) { if (x === 1 && y === 2) { return "anything I want"; } else { return sum(x, y); } }); expect(sum2(1)).toBe("anything I want"); 

But it would be nice if we had the function of sugar to simplify it.

Does that sound reasonable? Do we already have this feature in Jest?

Thanks for your feedback.

+22
javascript unit-testing jestjs
source share
4 answers

I found this library that my colleague recently wrote: jest-when

 import { when } from 'jest-when'; const fn = jest.fn(); when(fn).calledWith(1).mockReturnValue('yay!'); const result = fn(1); expect(result).toEqual('yay!'); 

Here is the library: https://github.com/timkindberg/jest-when

+15
source share

No, there is no way to do this in Jest yet. You could use sinons stubs for this. from documents:

stub.withArgs (arg1 [, arg2, ...]);

Method stubs are for provided arguments only. This is useful to be more expressive in your statements when you can access a spy using the same call. It is also useful to create a stub that can act differently in response to different arguments.

 "test should stub method differently based on arguments": function () { var callback = sinon.stub(); callback.withArgs(42).returns(1); callback.withArgs(1).throws("TypeError"); callback(); // No return value, no exception callback(42); // Returns 1 callback(1); // Throws TypeError } 
+7
source share

This can help...

I had something similar, as a result of which I had the same method, which is called with different parameters, requiring a different returned result from a cropped / mocked call. I used a variable with a list of functions, when I called the mocked service, I take a function from the top of the queue and execute the function. This requires knowing the execution order that you are testing, and actually does not cope with changing the answer by argument, but it allowed me to bypass the restriction as a joke.

 var mockedQueue = []; mockedQueue.push(() => {return 'A';}) mockedQueue.push(() => {return 'B';}) service.invoke = jest.fn(()=>{ serviceFunctionToCall = mockedQueue.shift(); return serviceFunctionToCall(); }) 
+2
source share

You can use:

 const mockSum = jest.fn(); mockSum.mockImplementation((x, y) => { // Return whatever you want based on x and y... }); 
0
source share

All Articles