Skip to content

Commit e9b715e

Browse files
committed
feat(tracing): Track wrapExpoRouterErrorBoundary adoption
Register a no-op `ExpoRouterErrorBoundary` integration when the wrapped Expo Router error boundary mounts so the name flows through to `event.sdk.integrations`. Refs: #6415
1 parent b8e6cc6 commit e9b715e

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

packages/core/src/js/tracing/expoRouterErrorBoundary.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ import {
1313
} from '@sentry/core';
1414
import * as React from 'react';
1515

16+
import { registerFeatureMarker } from '../utils/featureMarkers';
1617
import { getCurrentExpoRouterRouteInfo } from './expoRouterStore';
1718

19+
export const EXPO_ROUTER_ERROR_BOUNDARY_INTEGRATION_NAME = 'ExpoRouterErrorBoundary';
20+
1821
/**
1922
* Errors we have already reported. Module-scoped (rather than a per-instance
2023
* `useRef`) so that an unmount → remount cycle with the same error instance —
@@ -65,6 +68,10 @@ export function wrapExpoRouterErrorBoundary<P extends ExpoRouterErrorBoundaryPro
6568
OriginalErrorBoundary: React.ComponentType<P>,
6669
): React.ComponentType<P> {
6770
const Wrapped: React.FC<P> = props => {
71+
React.useEffect(() => {
72+
registerFeatureMarker(EXPO_ROUTER_ERROR_BOUNDARY_INTEGRATION_NAME);
73+
}, []);
74+
6875
// Reporting is intentionally done in `useEffect` (commit phase) rather than
6976
// during render: render must be pure, and in Concurrent Mode an in-progress
7077
// render can be discarded — we only want to report errors that React

packages/core/test/tracing/expoRouterErrorBoundary.test.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@ import { render } from '@testing-library/react-native';
33
import * as React from 'react';
44
import { Text } from 'react-native';
55

6-
import { wrapExpoRouterErrorBoundary } from '../../src/js/tracing/expoRouterErrorBoundary';
6+
import {
7+
EXPO_ROUTER_ERROR_BOUNDARY_INTEGRATION_NAME,
8+
wrapExpoRouterErrorBoundary,
9+
} from '../../src/js/tracing/expoRouterErrorBoundary';
710

811
const mockCaptureException = jest.fn();
912
const mockAddBreadcrumb = jest.fn();
1013
const mockAddExceptionMechanism = jest.fn();
14+
const mockAddIntegration = jest.fn();
15+
const mockGetIntegrationByName = jest.fn().mockReturnValue(undefined);
1116
let mockSendDefaultPii = false;
1217
let mockActiveSpan: { setStatus: jest.Mock; __origin?: string } | undefined;
1318

@@ -18,7 +23,11 @@ jest.mock('@sentry/core', () => {
1823
captureException: (...args: unknown[]) => mockCaptureException(...args),
1924
addBreadcrumb: (...args: unknown[]) => mockAddBreadcrumb(...args),
2025
addExceptionMechanism: (...args: unknown[]) => mockAddExceptionMechanism(...args),
21-
getClient: () => ({ getOptions: () => ({ sendDefaultPii: mockSendDefaultPii }) }),
26+
getClient: () => ({
27+
getOptions: () => ({ sendDefaultPii: mockSendDefaultPii }),
28+
getIntegrationByName: mockGetIntegrationByName,
29+
addIntegration: mockAddIntegration,
30+
}),
2231
getActiveSpan: () => mockActiveSpan,
2332
getRootSpan: (span: unknown) => span,
2433
spanToJSON: (span: { __origin?: string } | undefined) => ({ origin: span?.__origin }),
@@ -80,6 +89,12 @@ describe('wrapExpoRouterErrorBoundary', () => {
8089
expect(getByTestId('fallback').props.children).toBe('boom');
8190
});
8291

92+
it('registers the ExpoRouterErrorBoundary marker on mount', () => {
93+
const Wrapped = wrapExpoRouterErrorBoundary(OriginalErrorBoundary);
94+
render(<Wrapped error={new Error('boom')} retry={jest.fn()} />);
95+
expect(mockAddIntegration).toHaveBeenCalledWith({ name: EXPO_ROUTER_ERROR_BOUNDARY_INTEGRATION_NAME });
96+
});
97+
8398
it('captures the error to Sentry once per error instance', () => {
8499
const Wrapped = wrapExpoRouterErrorBoundary(OriginalErrorBoundary);
85100
const err = new Error('boom');

0 commit comments

Comments
 (0)