diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dacb6cd1..da3a1fd36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Make `configureScope` callback safe [#2510](https://github.com/getsentry/sentry-react-native/pull/2510) + ## 4.6.0 ### Fixes diff --git a/src/js/index.ts b/src/js/index.ts index 31e3ca61f..3ac0c4db0 100644 --- a/src/js/index.ts +++ b/src/js/index.ts @@ -17,7 +17,6 @@ export { captureException, captureEvent, captureMessage, - configureScope, getHubFromCarrier, getCurrentHub, Hub, @@ -66,6 +65,7 @@ export { close, captureUserFeedback, withScope, + configureScope, } from './sdk'; export { TouchEventBoundary, withTouchEventBoundary } from './touchevents'; diff --git a/src/js/sdk.tsx b/src/js/sdk.tsx index 98ee7e5b0..b3e0eafea 100644 --- a/src/js/sdk.tsx +++ b/src/js/sdk.tsx @@ -262,3 +262,18 @@ export function withScope(callback: (scope: Scope) => void): ReturnType void): ReturnType { + const safeCallback = (scope: Scope): void => { + try { + callback(scope); + } catch (e) { + logger.error('Error while running configureScope callback', e); + } + }; + getCurrentHub().configureScope(safeCallback); +} diff --git a/test/client.test.ts b/test/client.test.ts index 694887d08..b744fbf44 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -13,7 +13,6 @@ import { envelopeItemPayload, envelopeItems, firstArg, - flushPromises, getMockSession, getMockUserFeedback, getSyncPromiseRejectOnFirstCall, diff --git a/test/sdk.test.ts b/test/sdk.test.ts index 6b3e49f6b..e788f1f8d 100644 --- a/test/sdk.test.ts +++ b/test/sdk.test.ts @@ -5,6 +5,7 @@ interface MockedClient { } let mockedGetCurrentHubWithScope: jest.Mock; +let mockedGetCurrentHubConfigureScope: jest.Mock; jest.mock('@sentry/react', () => { const actualModule = jest.requireActual('@sentry/react'); @@ -17,10 +18,12 @@ jest.mock('@sentry/react', () => { ...actualModule, getCurrentHub: jest.fn(() => { mockedGetCurrentHubWithScope = jest.fn(); + mockedGetCurrentHubConfigureScope = jest.fn(); return { getClient: jest.fn(() => mockClient), setTag: jest.fn(), withScope: mockedGetCurrentHubWithScope, + configureScope: mockedGetCurrentHubConfigureScope, }; }), defaultIntegrations: [ { name: 'MockedDefaultReactIntegration', setupOnce: jest.fn() } ], @@ -62,7 +65,7 @@ import { getCurrentHub } from '@sentry/react'; import { Integration, Scope } from '@sentry/types'; import { ReactNativeClientOptions } from '../src/js/options'; -import { flush, init, withScope } from '../src/js/sdk'; +import { configureScope,flush, init, withScope } from '../src/js/sdk'; import { ReactNativeTracing, ReactNavigationInstrumentation } from '../src/js/tracing'; import { firstArg, secondArg } from './testutils'; @@ -234,6 +237,19 @@ describe('Tests the SDK functionality', () => { }); }); + describe('configureScope', () => { + test('configureScope callback does not throw', () => { + const mockScopeCallback = jest.fn(() => { throw 'Test error' }); + + configureScope(mockScopeCallback); + + expect(() => { + (mockedGetCurrentHubConfigureScope.mock.calls[0][firstArg] as (scope: Scope) => void)({} as any); + }).not.toThrow(); + expect(mockScopeCallback).toBeCalledTimes(1); + }); + }); + describe('integrations', () => { it('replaces default integrations', () => { const mockDefaultIntegration = getMockedIntegration(); diff --git a/test/testutils.ts b/test/testutils.ts index b987f9486..51962daa0 100644 --- a/test/testutils.ts +++ b/test/testutils.ts @@ -64,5 +64,3 @@ export const getSyncPromiseRejectOnFirstCall = (reason: unknown } }); }; - -export const flushPromises = (): Promise => new Promise(setImmediate);