Search code examples
reactjsjestjscreate-react-appsentry

Testing Sentry with Jest


I am testing my error boundaries to React and noticed in Codecov that there is a particular part of my Sentry function that hasn't been tested.

enter image description here

I have tried to use jest.mock("@sentry/browser") and mocking Sentry, however, can't seem to get the lines tested. The Sentry import is mocking correctly but not scope.

Here is an example of my attempt at mocking.

import * as Sentry from "@sentry/browser"
const mock_scope = jest.fn(() => {
  return { setExtras: null }
})
Sentry.withScope = jest.fn().mockImplementation(mock_scope)

Solution

  • The untested lines are this callback function being passed to Sentry.withScope:

    scope => {
      scope.setExtras(errorInfo);
      Sentry.captureException(error);
    }
    

    Since Sentry.withScope has been mocked you can use mockFn.mock.calls to retrieve the callback function passed to it.

    Once you have retrieved the callback function, you can call it directly to test it.

    Here is a slightly simplified working example:

    import * as Sentry from '@sentry/browser';
    
    jest.mock('@sentry/browser');  // <= auto-mock @sentry/browser
    
    const componentDidCatch = (error, errorInfo) => {
      Sentry.withScope(scope => {
        scope.setExtras(errorInfo);
        Sentry.captureException(error);
      });
    };
    
    test('componentDidCatch', () => {
      componentDidCatch('the error', 'the error info');
    
      const callback = Sentry.withScope.mock.calls[0][0];  // <= get the callback passed to Sentry.withScope
      const scope = { setExtras: jest.fn() };
      callback(scope);  // <= call the callback
    
      expect(scope.setExtras).toHaveBeenCalledWith('the error info');  // Success!
      expect(Sentry.captureException).toHaveBeenCalledWith('the error');  // Success!
    });
    

    Note that this line:

    const callback = Sentry.withScope.mock.calls[0][0];
    

    ...is getting the first argument of the first call to Sentry.withScope, which is the callback function.