用 Jest 测试 Sentry

Cha*_*wis 2 sentry reactjs jestjs create-react-app

我正在测试 React 的错误边界,并在 Codecov 中注意到我的 Sentry 函数的特定部分尚未经过测试。

在此处输入图片说明

我曾尝试使用 jest.mock("@sentry/browser") 并嘲笑 Sentry,但是,似乎无法测试这些行。Sentry 导入正确模拟但不是scope.

这是我尝试嘲笑的一个例子。

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

Bri*_*ams 7

未经测试的行是这个回调函数被传递给Sentry.withScope

scope => {
  scope.setExtras(errorInfo);
  Sentry.captureException(error);
}
Run Code Online (Sandbox Code Playgroud)

由于Sentry.withScope已被模拟,您可以使用它mockFn.mock.calls来检索传递给它的回调函数。

一旦检索到回调函数,就可以直接调用它进行测试。

这是一个稍微简化的工作示例:

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!
});
Run Code Online (Sandbox Code Playgroud)

请注意这一行:

const callback = Sentry.withScope.mock.calls[0][0];
Run Code Online (Sandbox Code Playgroud)

...正在获取第一次调用的第一个参数Sentry.withScope,即回调函数。


Bor*_*rov 5

对已接受答案的补充。那里的解决方案需要手动调用回调(请参阅callback(scope); // <= call the callback测试代码中的行)。

以下是让它自动工作的方法:

import * as Sentry from '@sentry/browser'
jest.mock('@sentry/browser')

// Update the default mock implementation for `withScope` to invoke the callback
const SentryMockScope = { setExtras: jest.fn() }
Sentry.withScope.mockImplementation((callback) => {
  callback(SentryMockScope)
})

Run Code Online (Sandbox Code Playgroud)

然后测试代码就变成:

test('componentDidCatch', () => {
  componentDidCatch('the error', 'the error info');

  expect(SentryMockScope.setExtras).toHaveBeenCalledWith('the error info');
  expect(Sentry.captureException).toHaveBeenCalledWith('the error');
});
Run Code Online (Sandbox Code Playgroud)