Тестирование Sentry с помощью Jest

Я тестирую свои границы ошибок для 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)

person Charklewis    schedule 24.05.2019    source источник
comment
Поскольку это сторонняя функция, я бы предложил использовать spyOn для объекта Sentry и метода withScope.   -  person Rikin    schedule 24.05.2019


Ответы (2)


Непроверенные строки - это функция обратного вызова, передаваемая в Sentry.withScope:

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

Поскольку 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!
});

Обратите внимание, что эта строка:

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

... получает первый аргумент первого вызова Sentry.withScope, который является функцией обратного вызова.

person Brian Adams    schedule 25.05.2019
comment
Идеально - это сработало как шарм. Раньше я не использовал mock.calls, это была недостающая часть моих знаний, чтобы заставить это работать. - person Charklewis; 25.05.2019
comment
Ты спас меня этим ответом. Я потратил немало времени на то, чтобы почесать голову, размышляя, как проверить эту точную ситуацию. Спасибо за ответ! - person jaimefps; 10.09.2019
comment
Для меня это тоже было очень полезно! - person crimson_penguin; 23.06.2020

Дополнение к принятому ответу. Решение там требует ручного вызова обратного вызова (см. Строку 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)
})

И тогда тестовый код становится:

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

  expect(SentryMockScope.setExtras).toHaveBeenCalledWith('the error info');
  expect(Sentry.captureException).toHaveBeenCalledWith('the error');
});
person Boris Serebrov    schedule 09.05.2020