I am trying to test the error case for the function removeBuilding(), in which the API call fails. I am mocking the API call to error to enter the catch block, which then calls displayError(). My test is expecting to see displayError getting called and sees none, but the function is running and printing to console, so for some reason jest simply cannot tell it is getting called.
function being tested:
removeBuilding = index => {
let { allBuildings } = this.state;
const buildings = this.state.allBuildings.filter(building => building.campus_id === this.props.selectedCampus);
if (index >= 0 && index <= buildings.length - 1) {
const building = buildings[index];
axios
.delete(`/api/buildings/${building.id}`)
.then(() => {
allBuildings = allBuildings.filter(function(value) {
return value !== building;
});
this.setState({
allBuildings,
});
})
.catch(error => {
// Test successfully reaches this point!
this.props.displayError(error);
});
}
};
test:
it.only('fails to make axios delete call, and displays error', () => {
let displayErrorMock = jest.fn(console.log("testing"));
wrapper = shallowWithIntl(
<AddBuildingList
displayError={displayErrorMock}
/>
);
deleteSpy = jest.spyOn(axios, 'delete').mockRejectedValueOnce(error);
wrapper.instance().setState({ allBuildings : [newBuilding] });
wrapper.instance().removeBuilding(0);
expect(displayErrorMock).toHaveBeenCalled();
});
});
failed test output:
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
184 | wrapper.instance().setState({ allBuildings : [newBuilding] });
185 | wrapper.instance().removeBuilding(0);
> 186 | expect(displayErrorMock).toHaveBeenCalled();
| ^
187 | });
188 | });
189 | });
at Object.<anonymous> (tests/Components/AddBuildingList/AddBuildingList.test.js:186:32)
console.log tests/Components/AddBuildingList/AddBuildingList.test.js:177
testing
EDIT I figured out the problem using this answer. Basically, since the axios call returns a promise, the code in the .then and .catch doesnt execute until the promise is resolved(or rejected), So the expect(..) was happening before the function call it was expecting. It was solved by defining
const flushPromises = () => new Promise(setImmediate)
and putting
await flushPromises();
right before expect statements that were testing for a function getting called in .then and .catch
The reason this works this way has to do with the setImmediate behavior, and the way multiple promises are handled in the javascript microtasks queue