Reputation: 3860
I am trying to write a test to make sure that, when appropriate, a particular function (in this case, a sentry function) is called with a particular message. However, when I write this test, it fails, and I get the following message. How to I properly mock the captureMessage
function in handleError.test.js
to make sure that it is properly called with the "this is an error message."
string in handleError.js
? Thanks!
error message:
Error: expect(jest.fn())[.not].toHaveBeenCalledWith()
jest.fn() value must be a mock function or spy. Received: function: [Function captureMessage]
handleError.js:
import {captureMessage} from '@sentry/browser';
const handleError = (error) => {
if (error.name === "ApiError") {
captureMessage('this is an error message.');
}
};
export default handleError;
handleError.test.js:
import {captureMessage} from '@sentry/browser';
import handleError from '../handleError';
class ApiError extends Error {
constructor() {
super();
this.name = 'ApiError';
}
}
test('When an ApiError is returned with no action type, sentry is notified', () => {
const sampleError = new ApiError();
handleError(sampleError);
expect(captureMessage).toHaveBeenCalledWith('this is an error message.');
});
Upvotes: 2
Views: 11123
Reputation: 38121
As @balzee mentioned, you have to actually spy on the method you want to make assertions about. That causes Jest to replace the method with a special spy function that keeps track of the parameters it is called with, how many times it was called, and so on.
You should also provide a mock implementation for that function, so that you don't actually call out to Sentry when running your unit tests.
Finally, when spying on a method, you first pass the object the method is on, and then the name of the method as a string. Jest then replaces that property on the object with a spy function, that will call the original function if no mock implementation is given.
Without referencing the object the function exists on, you would just be changing what a local function variable points to, from the original/real function to a jest spy function. That won't change the function that the code you are testing invokes, so the test will fail.
So the final test should be:
handleError.test.js:
import * as sentry from '@sentry/browser'; // CHANGED
import handleError from '../handleError';
class ApiError extends Error {
constructor() {
super();
this.name = 'ApiError';
}
}
// added this to remove any spies/mocks after the test
afterEach(() => {
jest.restoreAllMocks();
});
test('When an ApiError is returned with no action type, sentry is notified', () => {
const sampleError = new ApiError();
// added next line
jest.spyOn(sentry, 'captureMessage').mockImplementation(() => {});
handleError(sampleError);
// note the use of `sentry.captureMessage`, which is now a jest spy fn
expect(sentry.captureMessage).toHaveBeenCalledWith('this is an error message.');
});
Upvotes: 5