Function declared within mock is undefined - javascript

I have the following code in Jest:
const mockOnNextAction = jest.fn(() => {
then: jest.fn();
});
jest.mock('NativeModules', () => {
return {
MyNativeModule: {
onNextAction: mockOnNextAction
}
};
});
MyNativeModule.executeSomeChecks();
expect(NativeModules.MyNativeModule.onNextAction).toHaveBeenCalled();
expect(NativeModules.MyNativeModule.onNextAction().then).toHaveBeenCalled();
In the code I am testing, I would like to make a call like this one:
NativeModules.MyNativeModule.onNextAction().then(() => {
//contents of callback function
});
The problem is that in the code under test I am getting this error:
TypeError: Cannot read property 'then' of undefined
Also, the following print statement:
console.log("NativeModules.MyNativeModule.onNextAction: " + JSON.stringify(NativeModules.MyNativeModule.onNextAction));
has the result undefined
So why is onNextAction undefined? I am mocking it with Jest so it should exist.

There were two problems with my mock.
1.I was not respecting ES6 lambda function syntax, so I changed to: () => ({...}) and I removed the ; inside the object.
2.I made the then field reference the same variable, otherwise NativeModules.MyNativeModule.onNextAction().then would always be a new object which was not called.
Finally, my code looks like this:
const mockThen = jest.fn();
const mockOnNextAction = jest.fn(() => ({
then: mockThen
}));
jest.mock('NativeModules', () => ({
MyNativeModule: {
onNextAction: mockOnNextAction
}
}));

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

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.

Access jest.fn function inside another one

I have following case while writing jest unit test cases:
elasticsearch.Client = jest.fn().mockImplementation(() => {
return {
update: jest.fn().mockImplementation(() => {
return {}
})
}
});
Now, I want to do some expect on update function call. How can I access update function here in test case.
I can access elasticsearch.Client and its mock variable as elasticsearch.Client.mock. But how can I access similarly the update function?
You can try moving the mock function for update to the outer scope:
const updateMock = jest.fn().mockImplementation(() => {
return {}
});
elasticsearch.Client = jest.fn().mockImplementation(() => {
return {
update: updateMock
}
});
Then you can use updateMock in your assertions. For example:
expect(updateMock).toHaveBeenCalled()

Test then() inside of a promise API call jest

I am trying to test a function which is an api call / promise so I can check state inside then using jest but cant seem to figure out what to do. I have tried mocking the file and the function to return a promise but getting an error TypeError: (0 , _dataAccess.fetchBundlesFromApi) is not a function I've tried following the docs on jests website and also the many different answers from stack overflow but none seem to work. Here is the code I want to test. I want to be able to call that and then say if okay check state or if error do something else. below is the code i am trying to do and the mocking that I have tried.
getLatestPrices = params => {
const { updateBundles } = this.props;
fetchBundlesFromApi(params)
.then(({ data: { bundles } }) => {
updateBundles(bundles);
this.setState({ showUpdatingPrices: false });
window.TemplateCalculator.reload();
})
.catch(() => goToUrl(bundlesUrl));
};`
fetchBundlesFromApi is import { fetchBundlesFromApi } from '../../../../dataAccess'; which is an axios call:
const fetchBundlesFromApi = params => axios(`${bundleRoute}/bundles${params}`);
export { fetchBundlesFromApi };
This is the mocking I have tried.
jest.mock('../../../../dataAccess', () => ({
fetchBundlesFromApi: new Promise(resolve => resolve({ data: mockBundles })),
}));
I have also tried these websites:
https://binarapps.com/blog/test-ajax-calls-in-react-component-lifecycle.
Jest/Enzyme Error: "Method 'setState' is only meant to run on a single node. 3 found instead."
https://jestjs.io/docs/en/asynchronous
I worked out I had to import my api call function like so:
import { fetchBundlesFromApi } from '../../../../dataAccess';
As that function was using axios I had to mock that. I did that like so:
jest.mock('axios', () => jest.fn(() => Promise.resolve({ data: mockBundles })));
The in my test I made it async and I could await that function response.
const fetchedBundles = await fetchBundlesFromApi(
'params',
);

Categories

Resources