how can I spy on a function with jest - javascript

I have a function that calls another function
const getArtist = (id) => {
// builds params for other function
return otherFuntion(params);
}
I want to verify that when I call getArtist(someValue), otherFunction gets called with the right arguments.
How can I accomplish that with jest ?
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
// how can I get a handle on the mock of otherFunction to see
// if it was called correctly ?
});
});

You could use proxyquire to mock out the imported function at compile time if it's a public function. If it's a private function then you definitely don't want to mock it out.
You should probably just test the return value of otherFuntion instead.

So you are really calling the function otherFuntion(params) so I would rather check if return of your getArtist functions gives the same results as otherFunction called with right params.
describe('getArtist function', () => {
it('should call otherFunction with the right params', () => {
expect(getArtist(id)).toBe(otherFunction(params));
});
});
Or create special function for generate params and test it separatly. Like prepareArtistParams and use it inside:
const getArtist = (id) => {
const params = prepareArtistParams(id);
return otherFuntion(params);
}
describe('otherFuntion function', () => {
it('should create right params', () => {
expect(prepareArtistParams(id)).toBe(params);
});
});

Related

I have a component that I am trying to test, which utilises a hook that exports a function. How to mock the exported function before the test?

I have a hook called useStartGame which exports just 1 function like this:
const useStartGame = () => {
const startGame = (game) => { //Do something }
return { startGame };
}
Now I have a component which uses this hook, however, I want to overwrite what the function does in my test. I tried adding the following code in my test:
jest.mock('#src/hooks/useStartGame', () => ({
useStartGame: () => {
return { startGame: jest.fn() };
},
}));
However, in my test I get this error:
TypeError: (0 , _useStartGame2.default) is not a function

Jest mocking inside the same module

I'm following this thread. Mock a function called by a tested function of the same file with jest
functions.js
export const a = (x) => { a very complicated function };
export const b = (x) => exports.a(x+1);
functions.test.js
import * as functions from './functions';
describe('b', () => {
test('calling b calls a with x+1', () => {
functions.a = jest.fn();
functions.b(1);
expect(functions.a).toHaveBeenCalledWith(2);
});
});
It works for the most part, except that if I have additional unit test after describe(b), that required the original implementation of a(), it will still be treated as mock function, like let's say I want to unit test a(), it won't work because it is an empty function now. e.g
describe('c', () => {
test('unit testing a will call something 3 times', () => {
functions.a()
expect(whatever.get).toHaveBeenCalledWith(3);
});
});
any way to fix this?
Note:
I have tried the following, but it does not work
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
afterEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
The only way I can make it work is this, but this seems like really hacky?
const originalA = functions.a.bind({});
afterEach(() => {
functions.a = originalA;
});
Have you tried using spyOn? It doesn't replace your implementation just chekcing what is happening with that function.
import * as functions from "../functions";
describe("b", () => {
test("calling b calls a with x+1", () => {
const functionASpy = jest.spyOn(functions, 'a');
functions.b(1);
expect(functionASpy).toHaveBeenCalledWith(2);
});
});

Jest spy not working while testing a function within a function

I'm trying to test a function in a class-based entity and trying to spy on another function that is being called inside the one I'm testing. But even though the child function is being called once, Jest fails to spy on it and says it was called 0 times.
Let's say this is my class:
class Example {
function1() {
const data = this.function2();
return data;
}
function2() {
...some code
}
}
So to test function1, I'm doing this:
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const callFunction1 = client.function1();
const function2Spy = jest.spyOn(client, 'function2');
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});
What am I missing here?
You are calling function first then spying on another function.
Try spying before function call
describe('ExampleComponent', () => {
beforeEach(() => {
client = new Example();
});
it('should call function2 once', async() => {
const function2Spy = jest.spyOn(client, 'function2');
client.function1();
expect(function2Spy).toHaveBeenCalledTimes(1);
});
});

Why isn't my jest mock function implementation being called?

I have the following jest test configuration for my collection of AWS JS Node Lambdas. I have a module called dynamoStore I reference in several different lambdas package.json and use within the lambdas. I am trying to get test one of these lambdas by mocking the dynamo store module as it makes calls to dynamoDb. The problem is that the jest.fn implementation never gets called. I confirmed this by sticking a breakpoint in that line as well as logging the value the calling methods returns from it.
When I check lambda1/index.js in the debugger getVehicleMetaKeysFromDeviceId() is a jest object but when it is called it doesn't use my mock implementation
How do I get this implementation to work? Have I set up my mock incorrectly?
dynamoStore/vehicleMetaConstraints
exports.getVehicleMetaKeysFromDeviceId= async (data) => {
return data
};
dynamoStore/index.js
exports.vehicleMetaConstraints = require("./vehicleMetaConstraints");
...
lambda1/index.js
const { vehicleMetaStore } = require("dynamo-store");
exports.handler = async (event, context, callback) => {
const message = event;
let vehicle_ids = await vehicleMetaStore.getVehicleMetaKeysFromDeviceId(message.id);
// vehicle_ids end up undefined when running the test
}
lambda1/index.test.js
const { vehicleMetaStore } = require("dynamo-store");
jest.mock("dynamo-store", () => {
return {
vehicleMetaStore: {
getVehicleMetaKeysFromDeviceId: jest.fn(),
},
};
});
describe("VehicleStorageLambda", () => {
beforeEach(() => {
jest.resetModules();
process.env = { ...env };
});
afterEach(() => {
jest.clearAllMocks();
});
test("Handles first time publish with existing device", async () => {
let functionHandler = require("./index");
vehicleMetaStore.getVehicleMetaKeysFromDeviceId.mockImplementationOnce(() =>
// This never gets called
Promise.resolve({
device_id: "333936303238510e00210022",
})
);
await functionHandler.handler({});
});
});
Remove the call to jest.resetModules() in beforeEach. That's re-importing your modules before each test, and wiping out your mocks.
https://stackoverflow.com/a/59792748/3084820

JS Jest: getting undefined error on simple mock test

I have a simple function that takes a player and calls a nested function setPlayer() on it:
myFunction = (player) => {
player.getData().setPlayer(true)
}
main.test.js
it('expects setPlayer to be called', () => {
player = jest.fn();
// mocking the myFunction
player.getData = jest.fn(() => {
return {
setPlayer: jest.fn().mockReturnValue(true),
}
})
myFunction(player) // calling function
expects(player.getData.setPlayer).toBeCalled();
});
I keep getting this error in my test though but I don't understand why. I seem to have everything mocked unless I am forgetting something:
expect(received).toBeCalled()
Matcher error: received value must be a mock or spy function
Received has value: undefined
I keep getting this error in my test though but I don't understand why.
player.getData is a mock function. That function doesn't have a setPlayer property. You are passing undefined to expects, hence the error.
Calling player.getData would return you an object with a setPlayer function, but you can't just do expects(player.getData().setPlayer) because that would return a different setPlayer mock function than the one called by myFunction.
Instead you simply create the setPlayer mock function up front and reference it directly. I also cleaned up the code a little.
it('expects setPlayer to be called', () => {
const setPlayerMock = jest.fn().mockReturnValue(true);
const player = {
getData: jest.fn(() => {
return {
setPlayer: setPlayerMock,
};
}),
};
myFunction(player); // calling function
expects(setPlayerMock).toBeCalled();
});
FWIW, with the information you have given, it wouldn't be necessary to use a mock function for getData, you could just do
const player = {
getData() {
return {setPlayer: setPlayerMock};
},
}
You only need to use mock functions when you want to make assertions on them.

Categories

Resources