Skip to content

Commit 4bc2c43

Browse files
fix(hint): Missing original exception in beforeSend for events from react native error handler (#2706)
1 parent a42fc11 commit 4bc2c43

File tree

3 files changed

+39
-38
lines changed

3 files changed

+39
-38
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Fixes
6+
7+
- Missing `originalException` in `beforeSend` for events from react native error handler ([#2706](https://github.com/getsentry/sentry-react-native/pull/2706))
8+
59
### Dependencies
610

711
- Bump Cocoa SDK from v7.31.3 to v7.31.4 ([#2699](https://github.com/getsentry/sentry-react-native/pull/2699))

src/js/integrations/reactnativeerrorhandlers.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getCurrentHub } from '@sentry/core';
2-
import { Integration, SeverityLevel } from '@sentry/types';
2+
import { EventHint, Integration, SeverityLevel } from '@sentry/types';
33
import { addExceptionMechanism, logger } from '@sentry/utils';
44

55
import { ReactNativeClient } from '../client';
@@ -200,10 +200,11 @@ export class ReactNativeErrorHandlers implements Integration {
200200

201201
const options = client.getOptions();
202202

203-
const event = await client.eventFromException(error, {
203+
const hint: EventHint = {
204204
originalException: error,
205205
attachments: scope?.getAttachments(),
206-
});
206+
};
207+
const event = await client.eventFromException(error, hint);
207208

208209
if (isFatal) {
209210
event.level = 'fatal' as SeverityLevel;
@@ -214,7 +215,7 @@ export class ReactNativeErrorHandlers implements Integration {
214215
});
215216
}
216217

217-
currentHub.captureEvent(event);
218+
currentHub.captureEvent(event, hint);
218219

219220
if (!__DEV__) {
220221
void client.flush(options.shutdownTimeout || 2000).then(() => {

test/integrations/reactnativeerrorhandlers.test.ts

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,62 +59,58 @@ afterEach(() => {
5959

6060
describe('ReactNativeErrorHandlers', () => {
6161
describe('onError', () => {
62-
test('Sets handled:false on a fatal error', async () => {
63-
// eslint-disable-next-line @typescript-eslint/no-empty-function
64-
let callback: (error: Error, isFatal: boolean) => Promise<void> = () =>
65-
Promise.resolve();
62+
let errorHandlerCallback: (error: Error, isFatal: boolean) => Promise<void>;
63+
64+
beforeEach(() => {
65+
errorHandlerCallback = () => Promise.resolve();
6666

6767
ErrorUtils.setGlobalHandler = jest.fn((_callback) => {
68-
callback = _callback as typeof callback;
68+
errorHandlerCallback = _callback as typeof errorHandlerCallback;
6969
});
7070

7171
const integration = new ReactNativeErrorHandlers();
7272

7373
integration.setupOnce();
7474

75-
expect(ErrorUtils.setGlobalHandler).toHaveBeenCalledWith(callback);
75+
expect(ErrorUtils.setGlobalHandler).toHaveBeenCalledWith(errorHandlerCallback);
76+
});
7677

77-
await callback(new Error('Test Error'), true);
78+
test('Sets handled:false on a fatal error', async () => {
79+
await errorHandlerCallback(new Error('Test Error'), true);
7880

79-
const hub = getCurrentHub();
80-
// eslint-disable-next-line @typescript-eslint/unbound-method
81-
const mockCall = (hub.captureEvent as jest.MockedFunction<
82-
typeof hub.captureEvent
83-
>).mock.calls[0];
84-
const event = mockCall[0];
81+
const [event] = getActualCaptureEventArgs();
8582

8683
expect(event.level).toBe('fatal' as SeverityLevel);
8784
expect(event.exception?.values?.[0].mechanism?.handled).toBe(false);
8885
expect(event.exception?.values?.[0].mechanism?.type).toBe('onerror');
8986
});
9087

9188
test('Does not set handled:false on a non-fatal error', async () => {
92-
// eslint-disable-next-line @typescript-eslint/no-empty-function
93-
let callback: (error: Error, isFatal: boolean) => Promise<void> = () =>
94-
Promise.resolve();
95-
96-
ErrorUtils.setGlobalHandler = jest.fn((_callback) => {
97-
callback = _callback as typeof callback;
98-
});
89+
await errorHandlerCallback(new Error('Test Error'), false);
9990

100-
const integration = new ReactNativeErrorHandlers();
101-
102-
integration.setupOnce();
103-
104-
expect(ErrorUtils.setGlobalHandler).toHaveBeenCalledWith(callback);
105-
106-
await callback(new Error('Test Error'), false);
107-
108-
const hub = getCurrentHub();
109-
// eslint-disable-next-line @typescript-eslint/unbound-method
110-
const mockCall = (hub.captureEvent as jest.MockedFunction<
111-
typeof hub.captureEvent
112-
>).mock.calls[0];
113-
const event = mockCall[0];
91+
const [event] = getActualCaptureEventArgs();
11492

11593
expect(event.level).toBe('error' as SeverityLevel);
11694
expect(event.exception?.values?.[0].mechanism?.handled).toBe(true);
11795
expect(event.exception?.values?.[0].mechanism?.type).toBe('generic');
11896
});
97+
98+
test('Includes original exception in hint', async () => {
99+
await errorHandlerCallback(new Error('Test Error'), false);
100+
101+
const [, hint] = getActualCaptureEventArgs();
102+
103+
expect(hint).toEqual(expect.objectContaining({ originalException: new Error('Test Error') }));
104+
});
119105
});
120106
});
107+
108+
function getActualCaptureEventArgs() {
109+
const hub = getCurrentHub();
110+
// eslint-disable-next-line @typescript-eslint/unbound-method
111+
const mockCall = (hub.captureEvent as jest.MockedFunction<
112+
typeof hub.captureEvent
113+
>).mock.calls[0];
114+
115+
return mockCall;
116+
}

0 commit comments

Comments
 (0)