Skip to content
Snippets Groups Projects
Commit 654836ec authored by Miguel Rincon's avatar Miguel Rincon Committed by Mike Greiling
Browse files

Install two versions of Sentry

This change installs two versions of sentry that can report errors to
two Sentry instances respectively.

Both integrations are gated behind feature flags, so administrators can
flip either one independently.

Changelog: changed
parent 725e7136
No related branches found
No related tags found
1 merge request!102790Install two versions of Sentry Client SDK
Showing
with 615 additions and 191 deletions
......@@ -75,6 +75,8 @@ rules:
- sibling
- index
pathGroups:
- pattern: '@sentry/browser'
group: external
- pattern: ~/**
group: internal
- pattern: emojis/**
......
import { __ } from '~/locale';
// TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
export const IGNORE_ERRORS = [
// Random plugins/extensions
'top.GLOBALS',
......
import '../webpack';
import * as Sentry from 'sentrybrowser7';
import SentryConfig from './sentry_config';
const index = function index() {
// Configuration for newer versions of Sentry SDK (v7)
SentryConfig.init({
dsn: gon.sentry_dsn,
environment: gon.sentry_environment,
currentUserId: gon.current_user_id,
whitelistUrls:
allowUrls:
process.env.NODE_ENV === 'production'
? [gon.gitlab_url]
: [gon.gitlab_url, 'webpack-internal://'],
environment: gon.sentry_environment,
release: gon.revision,
tags: {
revision: gon.revision,
feature_category: gon.feature_category,
},
});
return SentryConfig;
};
index();
// The _Sentry object is globally exported so it can be used by
// ./sentry_browser_wrapper.js
// This hack allows us to load a single version of `@sentry/browser`
// in the browser, see app/views/layouts/_head.html.haml to find how it is imported.
// eslint-disable-next-line no-underscore-dangle
window._Sentry = Sentry;
export default index;
import '../webpack';
import * as Sentry5 from 'sentrybrowser5';
import LegacySentryConfig from './legacy_sentry_config';
const index = function index() {
// Configuration for legacy versions of Sentry SDK (v5)
LegacySentryConfig.init({
dsn: gon.sentry_dsn,
currentUserId: gon.current_user_id,
whitelistUrls:
process.env.NODE_ENV === 'production'
? [gon.gitlab_url]
: [gon.gitlab_url, 'webpack-internal://'],
environment: gon.sentry_environment,
release: gon.revision,
tags: {
revision: gon.revision,
feature_category: gon.feature_category,
},
});
};
index();
// The _Sentry object is globally exported so it can be used by
// ./sentry_browser_wrapper.js
// This hack allows us to load a single version of `@sentry/browser`
// in the browser, see app/views/layouts/_head.html.haml to find how it is imported.
// eslint-disable-next-line no-underscore-dangle
window._Sentry = Sentry5;
export default index;
import * as Sentry5 from 'sentrybrowser5';
import $ from 'jquery';
import { __ } from '~/locale';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
const SentryConfig = {
IGNORE_ERRORS,
BLACKLIST_URLS: DENY_URLS,
SAMPLE_RATE,
init(options = {}) {
this.options = options;
this.configure();
this.bindSentryErrors();
if (this.options.currentUserId) this.setUser();
},
configure() {
const { dsn, release, tags, whitelistUrls, environment } = this.options;
Sentry5.init({
dsn,
release,
whitelistUrls,
environment,
ignoreErrors: this.IGNORE_ERRORS, // TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
blacklistUrls: this.BLACKLIST_URLS,
sampleRate: SAMPLE_RATE,
});
Sentry5.setTags(tags);
},
setUser() {
Sentry5.setUser({
id: this.options.currentUserId,
});
},
bindSentryErrors() {
$(document).on('ajaxError.sentry', this.handleSentryErrors);
},
handleSentryErrors(event, req, config, err) {
const error = err || req.statusText;
const { responseText = __('Unknown response text') } = req;
const { type, url, data } = config;
const { status } = req;
Sentry5.captureMessage(error, {
extra: {
type,
url,
data,
status,
response: responseText,
error,
event,
},
});
},
};
export default SentryConfig;
// The _Sentry object is globally exported so it can be used here
// This hack allows us to load a single version of `@sentry/browser`
// in the browser (or none). See app/views/layouts/_head.html.haml
// to find how it is imported.
// This module wraps methods used by our production code.
// Each export is names as we cannot export the entire namespace from *.
export const captureException = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
Sentry?.captureException(...args);
};
export const captureMessage = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
Sentry?.captureMessage(...args);
};
export const withScope = (...args) => {
// eslint-disable-next-line no-underscore-dangle
const Sentry = window._Sentry;
Sentry?.withScope(...args);
};
import * as Sentry from '@sentry/browser';
import $ from 'jquery';
import { __ } from '~/locale';
import * as Sentry from 'sentrybrowser7';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
const SentryConfig = {
IGNORE_ERRORS,
BLACKLIST_URLS: DENY_URLS,
SAMPLE_RATE,
init(options = {}) {
this.options = options;
this.configure();
this.bindSentryErrors();
if (this.options.currentUserId) this.setUser();
},
configure() {
const { dsn, release, tags, whitelistUrls, environment } = this.options;
const { dsn, release, tags, allowUrls, environment } = this.options;
Sentry.init({
dsn,
release,
whitelistUrls,
allowUrls,
environment,
ignoreErrors: this.IGNORE_ERRORS, // TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
blacklistUrls: this.BLACKLIST_URLS,
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
sampleRate: SAMPLE_RATE,
});
......@@ -36,29 +30,6 @@ const SentryConfig = {
id: this.options.currentUserId,
});
},
bindSentryErrors() {
$(document).on('ajaxError.sentry', this.handleSentryErrors);
},
handleSentryErrors(event, req, config, err) {
const error = err || req.statusText;
const { responseText = __('Unknown response text') } = req;
const { type, url, data } = config;
const { status } = req;
Sentry.captureMessage(error, {
extra: {
type,
url,
data,
status,
response: responseText,
error,
event,
},
});
},
};
export default SentryConfig;
......@@ -47,7 +47,10 @@
= Gon::Base.render_data(nonce: content_security_policy_nonce)
= render_if_exists 'layouts/header/translations'
= webpack_bundle_tag "sentry" if Gitlab.config.sentry.enabled
- if Feature.enabled?(:enable_new_sentry_clientside_integration, current_user) && Gitlab::CurrentSettings.sentry_enabled
= webpack_bundle_tag 'sentry'
- elsif Gitlab.config.sentry.enabled
= webpack_bundle_tag 'legacy_sentry'
= webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
= yield :page_specific_javascripts
......
......@@ -160,6 +160,7 @@ function generateEntries() {
*/
const manualEntries = {
default: defaultEntries,
legacy_sentry: './sentry/legacy_index.js',
sentry: './sentry/index.js',
performance_bar: './performance_bar/index.js',
jira_connect_app: './jira_connect/subscriptions/index.js',
......@@ -174,6 +175,11 @@ function generateEntries() {
const alias = {
// Map Apollo client to apollo/client/core to prevent react related imports from being loaded
'@apollo/client$': '@apollo/client/core',
// Map Sentry calls to use local wrapper
'@sentry/browser$': path.join(
ROOT_PATH,
'app/assets/javascripts/sentry/sentry_browser_wrapper.js',
),
'~': path.join(ROOT_PATH, 'app/assets/javascripts'),
emojis: path.join(ROOT_PATH, 'fixtures/emojis'),
empty_states: path.join(ROOT_PATH, 'app/views/shared/empty_states'),
......
......@@ -63,6 +63,7 @@ module.exports = (path, options = {}) => {
'^jest/(.*)$': '<rootDir>/spec/frontend/$1',
'^ee_else_ce_jest/(.*)$': '<rootDir>/spec/frontend/$1',
'^jquery$': '<rootDir>/node_modules/jquery/dist/jquery.slim.js',
'^@sentry/browser$': '<rootDir>/app/assets/javascripts/sentry/sentry_browser_wrapper.js',
...extModuleNameMapper,
};
......
......@@ -43,7 +43,10 @@ def self.default_directives
allow_websocket_connections(directives)
allow_cdn(directives, Settings.gitlab.cdn_host) if Settings.gitlab.cdn_host.present?
allow_sentry(directives) if Gitlab.config.sentry&.enabled && Gitlab.config.sentry&.clientside_dsn
# Support for Sentry setup via configuration files will be removed in 16.0
# in favor of Gitlab::CurrentSettings.
allow_legacy_sentry(directives) if Gitlab.config.sentry&.enabled && Gitlab.config.sentry&.clientside_dsn
allow_sentry(directives) if Gitlab::CurrentSettings.sentry_enabled && Gitlab::CurrentSettings.sentry_clientside_dsn
allow_framed_gitlab_paths(directives)
allow_customersdot(directives) if ENV['CUSTOMER_PORTAL_URL'].present?
allow_review_apps(directives) if ENV['REVIEW_APPS_ENABLED']
......@@ -135,13 +138,22 @@ def self.allow_customersdot(directives)
append_to_directive(directives, 'frame_src', customersdot_host)
end
def self.allow_sentry(directives)
def self.allow_legacy_sentry(directives)
# Support for Sentry setup via configuration files will be removed in 16.0
# in favor of Gitlab::CurrentSettings.
sentry_dsn = Gitlab.config.sentry.clientside_dsn
sentry_uri = URI(sentry_dsn)
append_to_directive(directives, 'connect_src', "#{sentry_uri.scheme}://#{sentry_uri.host}")
end
def self.allow_sentry(directives)
sentry_dsn = Gitlab::CurrentSettings.sentry_clientside_dsn
sentry_uri = URI(sentry_dsn)
append_to_directive(directives, 'connect_src', "#{sentry_uri.scheme}://#{sentry_uri.host}")
end
def self.allow_letter_opener(directives)
append_to_directive(directives, 'frame_src', Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/rails/letter_opener/'))
end
......
......@@ -3,26 +3,61 @@
require 'spec_helper'
RSpec.describe 'Sentry' do
let(:sentry_regex_path) { '\/sentry.*\.chunk\.js' }
context 'when enable_new_sentry_clientside_integration is disabled' do
before do
stub_feature_flags(enable_new_sentry_clientside_integration: false)
end
it 'does not load sentry if sentry is disabled' do
allow(Gitlab.config.sentry).to receive(:enabled).and_return(false)
visit new_user_session_path
expect(has_requested_legacy_sentry).to eq(false)
end
it 'does not load sentry if sentry is disabled' do
allow(Gitlab.config.sentry).to receive(:enabled).and_return(false)
visit new_user_session_path
it 'loads legacy sentry if sentry config is enabled', :js do
allow(Gitlab.config.sentry).to receive(:enabled).and_return(true)
expect(has_requested_sentry).to eq(false)
visit new_user_session_path
expect(has_requested_legacy_sentry).to eq(true)
expect(evaluate_script('window._Sentry.SDK_VERSION')).to match(%r{^5\.})
end
end
it 'loads sentry if sentry is enabled' do
stub_sentry_settings
context 'when enable_new_sentry_clientside_integration is enabled' do
before do
stub_feature_flags(enable_new_sentry_clientside_integration: true)
end
it 'does not load sentry if sentry settings are disabled' do
allow(Gitlab::CurrentSettings).to receive(:sentry_enabled).and_return(false)
visit new_user_session_path
visit new_user_session_path
expect(has_requested_sentry).to eq(true)
expect(has_requested_sentry).to eq(false)
end
it 'loads sentry if sentry settings are enabled', :js do
allow(Gitlab::CurrentSettings).to receive(:sentry_enabled).and_return(true)
visit new_user_session_path
expect(has_requested_sentry).to eq(true)
expect(evaluate_script('window._Sentry.SDK_VERSION')).to match(%r{^7\.})
end
end
def has_requested_legacy_sentry
page.all('script', visible: false).one? do |elm|
elm[:src] =~ %r{/legacy_sentry.*\.chunk\.js\z}
end
end
def has_requested_sentry
page.all('script', visible: false).one? do |elm|
elm[:src] =~ /#{sentry_regex_path}$/
elm[:src] =~ %r{/sentry.*\.chunk\.js\z}
end
end
end
......@@ -61,6 +61,10 @@ describe('Clusters', () => {
let captureException;
beforeEach(() => {
jest.spyOn(Sentry, 'withScope').mockImplementation((fn) => {
const mockScope = { setTag: () => {} };
fn(mockScope);
});
captureException = jest.spyOn(Sentry, 'captureException');
mock = new MockAdapter(axios);
......
......@@ -17,6 +17,10 @@ describe('Clusters store actions', () => {
describe('reportSentryError', () => {
beforeEach(() => {
jest.spyOn(Sentry, 'withScope').mockImplementation((fn) => {
const mockScope = { setTag: () => {} };
fn(mockScope);
});
captureException = jest.spyOn(Sentry, 'captureException');
});
......
import index from '~/sentry/index';
import LegacySentryConfig from '~/sentry/legacy_sentry_config';
import SentryConfig from '~/sentry/sentry_config';
describe('SentryConfig options', () => {
describe('Sentry init', () => {
let originalGon;
const dsn = 'https://123@sentry.gitlab.test/123';
const currentUserId = 'currentUserId';
const gitlabUrl = 'gitlabUrl';
const environment = 'test';
const currentUserId = '1';
const gitlabUrl = 'gitlabUrl';
const revision = 'revision';
const featureCategory = 'my_feature_category';
let indexReturnValue;
beforeEach(() => {
originalGon = window.gon;
window.gon = {
sentry_dsn: dsn,
sentry_environment: environment,
......@@ -21,28 +24,41 @@ describe('SentryConfig options', () => {
feature_category: featureCategory,
};
process.env.HEAD_COMMIT_SHA = revision;
jest.spyOn(LegacySentryConfig, 'init').mockImplementation();
jest.spyOn(SentryConfig, 'init').mockImplementation();
});
indexReturnValue = index();
afterEach(() => {
window.gon = originalGon;
});
it('should init with .sentryDsn, .currentUserId, .whitelistUrls and environment', () => {
expect(SentryConfig.init).toHaveBeenCalledWith({
dsn,
currentUserId,
whitelistUrls: [gitlabUrl, 'webpack-internal://'],
environment,
release: revision,
tags: {
revision,
feature_category: featureCategory,
},
});
it('exports new version of Sentry in the global object', () => {
// eslint-disable-next-line no-underscore-dangle
expect(window._Sentry.SDK_VERSION).not.toMatch(/^5\./);
});
it('should return SentryConfig', () => {
expect(indexReturnValue).toBe(SentryConfig);
describe('when called', () => {
beforeEach(() => {
index();
});
it('configures sentry', () => {
expect(SentryConfig.init).toHaveBeenCalledTimes(1);
expect(SentryConfig.init).toHaveBeenCalledWith({
dsn,
currentUserId,
allowUrls: [gitlabUrl, 'webpack-internal://'],
environment,
release: revision,
tags: {
revision,
feature_category: featureCategory,
},
});
});
it('does not configure legacy sentry', () => {
expect(LegacySentryConfig.init).not.toHaveBeenCalled();
});
});
});
import index from '~/sentry/legacy_index';
import LegacySentryConfig from '~/sentry/legacy_sentry_config';
import SentryConfig from '~/sentry/sentry_config';
describe('Sentry init', () => {
let originalGon;
const dsn = 'https://123@sentry.gitlab.test/123';
const environment = 'test';
const currentUserId = '1';
const gitlabUrl = 'gitlabUrl';
const revision = 'revision';
const featureCategory = 'my_feature_category';
beforeEach(() => {
originalGon = window.gon;
window.gon = {
sentry_dsn: dsn,
sentry_environment: environment,
current_user_id: currentUserId,
gitlab_url: gitlabUrl,
revision,
feature_category: featureCategory,
};
jest.spyOn(LegacySentryConfig, 'init').mockImplementation();
jest.spyOn(SentryConfig, 'init').mockImplementation();
});
afterEach(() => {
window.gon = originalGon;
});
it('exports legacy version of Sentry in the global object', () => {
// eslint-disable-next-line no-underscore-dangle
expect(window._Sentry.SDK_VERSION).toMatch(/^5\./);
});
describe('when called', () => {
beforeEach(() => {
index();
});
it('configures legacy sentry', () => {
expect(LegacySentryConfig.init).toHaveBeenCalledTimes(1);
expect(LegacySentryConfig.init).toHaveBeenCalledWith({
dsn,
currentUserId,
whitelistUrls: [gitlabUrl, 'webpack-internal://'],
environment,
release: revision,
tags: {
revision,
feature_category: featureCategory,
},
});
});
it('does not configure new sentry', () => {
expect(SentryConfig.init).not.toHaveBeenCalled();
});
});
});
import * as Sentry5 from 'sentrybrowser5';
import LegacySentryConfig from '~/sentry/legacy_sentry_config';
describe('LegacySentryConfig', () => {
describe('IGNORE_ERRORS', () => {
it('should be an array of strings', () => {
const areStrings = LegacySentryConfig.IGNORE_ERRORS.every(
(error) => typeof error === 'string',
);
expect(areStrings).toBe(true);
});
});
describe('BLACKLIST_URLS', () => {
it('should be an array of regexps', () => {
const areRegExps = LegacySentryConfig.BLACKLIST_URLS.every((url) => url instanceof RegExp);
expect(areRegExps).toBe(true);
});
});
describe('SAMPLE_RATE', () => {
it('should be a finite number', () => {
expect(typeof LegacySentryConfig.SAMPLE_RATE).toEqual('number');
});
});
describe('init', () => {
const options = {
currentUserId: 1,
};
beforeEach(() => {
jest.spyOn(LegacySentryConfig, 'configure');
jest.spyOn(LegacySentryConfig, 'bindSentryErrors');
jest.spyOn(LegacySentryConfig, 'setUser');
LegacySentryConfig.init(options);
});
it('should set the options property', () => {
expect(LegacySentryConfig.options).toEqual(options);
});
it('should call the configure method', () => {
expect(LegacySentryConfig.configure).toHaveBeenCalled();
});
it('should call the error bindings method', () => {
expect(LegacySentryConfig.bindSentryErrors).toHaveBeenCalled();
});
it('should call setUser', () => {
expect(LegacySentryConfig.setUser).toHaveBeenCalled();
});
it('should not call setUser if there is no current user ID', () => {
LegacySentryConfig.setUser.mockClear();
options.currentUserId = undefined;
LegacySentryConfig.init(options);
expect(LegacySentryConfig.setUser).not.toHaveBeenCalled();
});
});
describe('configure', () => {
const sentryConfig = {};
const options = {
dsn: 'https://123@sentry.gitlab.test/123',
whitelistUrls: ['//gitlabUrl', 'webpack-internal://'],
environment: 'test',
release: 'revision',
tags: {
revision: 'revision',
feature_category: 'my_feature_category',
},
};
beforeEach(() => {
jest.spyOn(Sentry5, 'init').mockImplementation();
jest.spyOn(Sentry5, 'setTags').mockImplementation();
sentryConfig.options = options;
sentryConfig.IGNORE_ERRORS = 'ignore_errors';
sentryConfig.BLACKLIST_URLS = 'blacklist_urls';
LegacySentryConfig.configure.call(sentryConfig);
});
it('should call Sentry5.init', () => {
expect(Sentry5.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: 0.95,
whitelistUrls: options.whitelistUrls,
environment: 'test',
ignoreErrors: sentryConfig.IGNORE_ERRORS,
blacklistUrls: sentryConfig.BLACKLIST_URLS,
});
});
it('should call Sentry5.setTags', () => {
expect(Sentry5.setTags).toHaveBeenCalledWith(options.tags);
});
it('should set environment from options', () => {
sentryConfig.options.environment = 'development';
LegacySentryConfig.configure.call(sentryConfig);
expect(Sentry5.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: 0.95,
whitelistUrls: options.whitelistUrls,
environment: 'development',
ignoreErrors: sentryConfig.IGNORE_ERRORS,
blacklistUrls: sentryConfig.BLACKLIST_URLS,
});
});
});
describe('setUser', () => {
let sentryConfig;
beforeEach(() => {
sentryConfig = { options: { currentUserId: 1 } };
jest.spyOn(Sentry5, 'setUser');
LegacySentryConfig.setUser.call(sentryConfig);
});
it('should call .setUser', () => {
expect(Sentry5.setUser).toHaveBeenCalledWith({
id: sentryConfig.options.currentUserId,
});
});
});
describe('handleSentryErrors', () => {
let event;
let req;
let config;
let err;
beforeEach(() => {
event = {};
req = { status: 'status', responseText: 'Unknown response text', statusText: 'statusText' };
config = { type: 'type', url: 'url', data: 'data' };
err = {};
jest.spyOn(Sentry5, 'captureMessage');
LegacySentryConfig.handleSentryErrors(event, req, config, err);
});
it('should call Sentry5.captureMessage', () => {
expect(Sentry5.captureMessage).toHaveBeenCalledWith(err, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: req.responseText,
error: err,
event,
},
});
});
describe('if no err is provided', () => {
beforeEach(() => {
LegacySentryConfig.handleSentryErrors(event, req, config);
});
it('should use req.statusText as the error value', () => {
expect(Sentry5.captureMessage).toHaveBeenCalledWith(req.statusText, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: req.responseText,
error: req.statusText,
event,
},
});
});
});
describe('if no req.responseText is provided', () => {
beforeEach(() => {
req.responseText = undefined;
LegacySentryConfig.handleSentryErrors(event, req, config, err);
});
it('should use `Unknown response text` as the response', () => {
expect(Sentry5.captureMessage).toHaveBeenCalledWith(err, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: 'Unknown response text',
error: err,
event,
},
});
});
});
});
});
import * as Sentry from '~/sentry/sentry_browser_wrapper';
const mockError = new Error('error!');
const mockMsg = 'msg!';
const mockFn = () => {};
describe('SentryBrowserWrapper', () => {
afterEach(() => {
// eslint-disable-next-line no-underscore-dangle
delete window._Sentry;
});
describe('when _Sentry is not defined', () => {
it('methods fail silently', () => {
expect(() => {
Sentry.captureException(mockError);
Sentry.captureMessage(mockMsg);
Sentry.withScope(mockFn);
}).not.toThrow();
});
});
describe('when _Sentry is defined', () => {
let mockCaptureException;
let mockCaptureMessage;
let mockWithScope;
beforeEach(async () => {
mockCaptureException = jest.fn();
mockCaptureMessage = jest.fn();
mockWithScope = jest.fn();
// eslint-disable-next-line no-underscore-dangle
window._Sentry = {
captureException: mockCaptureException,
captureMessage: mockCaptureMessage,
withScope: mockWithScope,
};
});
it('captureException is called', () => {
Sentry.captureException(mockError);
expect(mockCaptureException).toHaveBeenCalledWith(mockError);
});
it('captureMessage is called', () => {
Sentry.captureMessage(mockMsg);
expect(mockCaptureMessage).toHaveBeenCalledWith(mockMsg);
});
it('withScope is called', () => {
Sentry.withScope(mockFn);
expect(mockWithScope).toHaveBeenCalledWith(mockFn);
});
});
});
import * as Sentry from '@sentry/browser';
import * as Sentry from 'sentrybrowser7';
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from '~/sentry/constants';
import SentryConfig from '~/sentry/sentry_config';
describe('SentryConfig', () => {
describe('IGNORE_ERRORS', () => {
it('should be an array of strings', () => {
const areStrings = SentryConfig.IGNORE_ERRORS.every((error) => typeof error === 'string');
expect(areStrings).toBe(true);
});
});
describe('BLACKLIST_URLS', () => {
it('should be an array of regexps', () => {
const areRegExps = SentryConfig.BLACKLIST_URLS.every((url) => url instanceof RegExp);
expect(areRegExps).toBe(true);
});
});
describe('SAMPLE_RATE', () => {
it('should be a finite number', () => {
expect(typeof SentryConfig.SAMPLE_RATE).toEqual('number');
});
});
describe('init', () => {
const options = {
currentUserId: 1,
......@@ -31,7 +11,6 @@ describe('SentryConfig', () => {
beforeEach(() => {
jest.spyOn(SentryConfig, 'configure');
jest.spyOn(SentryConfig, 'bindSentryErrors');
jest.spyOn(SentryConfig, 'setUser');
SentryConfig.init(options);
......@@ -45,19 +24,13 @@ describe('SentryConfig', () => {
expect(SentryConfig.configure).toHaveBeenCalled();
});
it('should call the error bindings method', () => {
expect(SentryConfig.bindSentryErrors).toHaveBeenCalled();
});
it('should call setUser', () => {
expect(SentryConfig.setUser).toHaveBeenCalled();
});
it('should not call setUser if there is no current user ID', () => {
SentryConfig.setUser.mockClear();
options.currentUserId = undefined;
SentryConfig.init(options);
SentryConfig.init({ currentUserId: undefined });
expect(SentryConfig.setUser).not.toHaveBeenCalled();
});
......@@ -67,7 +40,7 @@ describe('SentryConfig', () => {
const sentryConfig = {};
const options = {
dsn: 'https://123@sentry.gitlab.test/123',
whitelistUrls: ['//gitlabUrl', 'webpack-internal://'],
allowUrls: ['//gitlabUrl', 'webpack-internal://'],
environment: 'test',
release: 'revision',
tags: {
......@@ -81,8 +54,6 @@ describe('SentryConfig', () => {
jest.spyOn(Sentry, 'setTags').mockImplementation();
sentryConfig.options = options;
sentryConfig.IGNORE_ERRORS = 'ignore_errors';
sentryConfig.BLACKLIST_URLS = 'blacklist_urls';
SentryConfig.configure.call(sentryConfig);
});
......@@ -91,11 +62,11 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: 0.95,
whitelistUrls: options.whitelistUrls,
environment: 'test',
ignoreErrors: sentryConfig.IGNORE_ERRORS,
blacklistUrls: sentryConfig.BLACKLIST_URLS,
sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: options.environment,
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
});
});
......@@ -111,11 +82,11 @@ describe('SentryConfig', () => {
expect(Sentry.init).toHaveBeenCalledWith({
dsn: options.dsn,
release: options.release,
sampleRate: 0.95,
whitelistUrls: options.whitelistUrls,
sampleRate: SAMPLE_RATE,
allowUrls: options.allowUrls,
environment: 'development',
ignoreErrors: sentryConfig.IGNORE_ERRORS,
blacklistUrls: sentryConfig.BLACKLIST_URLS,
ignoreErrors: IGNORE_ERRORS,
denyUrls: DENY_URLS,
});
});
});
......@@ -136,78 +107,4 @@ describe('SentryConfig', () => {
});
});
});
describe('handleSentryErrors', () => {
let event;
let req;
let config;
let err;
beforeEach(() => {
event = {};
req = { status: 'status', responseText: 'Unknown response text', statusText: 'statusText' };
config = { type: 'type', url: 'url', data: 'data' };
err = {};
jest.spyOn(Sentry, 'captureMessage');
SentryConfig.handleSentryErrors(event, req, config, err);
});
it('should call Sentry.captureMessage', () => {
expect(Sentry.captureMessage).toHaveBeenCalledWith(err, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: req.responseText,
error: err,
event,
},
});
});
describe('if no err is provided', () => {
beforeEach(() => {
SentryConfig.handleSentryErrors(event, req, config);
});
it('should use req.statusText as the error value', () => {
expect(Sentry.captureMessage).toHaveBeenCalledWith(req.statusText, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: req.responseText,
error: req.statusText,
event,
},
});
});
});
describe('if no req.responseText is provided', () => {
beforeEach(() => {
req.responseText = undefined;
SentryConfig.handleSentryErrors(event, req, config, err);
});
it('should use `Unknown response text` as the response', () => {
expect(Sentry.captureMessage).toHaveBeenCalledWith(err, {
extra: {
type: config.type,
url: config.url,
data: config.data,
status: req.status,
response: 'Unknown response text',
error: err,
event,
},
});
});
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment