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

Я тестирую свои границы ошибок для React и заметил в Codecov, что есть определенная часть моей функции Sentry, которая не была протестирована.

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

Я пытался использовать 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)

Поскольку это сторонняя функция, я бы предложил использовать spyOn для объекта Sentry и метод withScope

Rikin 24.05.2019 22:40
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
1
5 096
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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, который является функцией обратного вызова.

Идеально - это сработало как шарм. Раньше я не использовал mock.call, это была недостающая часть моих знаний, чтобы заставить это работать.

Charklewis 25.05.2019 16:37

Вы спасли меня этим ответом. Я провел немало времени, ломая голову, задаваясь вопросом, как проверить именно эту ситуацию. Спасибо за ответ!

jaimefps 10.09.2019 03:55

Это было очень полезно и для меня!

crimson_penguin 23.06.2020 18:39

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

Другие вопросы по теме