Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

### Fixes

- Retry native module resolution to prevent silent event drops in production Hermes builds ([#5981](https://github.com/getsentry/sentry-react-native/pull/5981))
- Lazy-load Metro internal modules to prevent Expo 55 import errors ([#5958](https://github.com/getsentry/sentry-react-native/pull/5958))
- Fix app start transaction profile offset by using the actual profiling start timestamp instead of the adjusted app start time ([#5962](https://github.com/getsentry/sentry-react-native/issues/5962))
- Use React `componentStack` as fallback when error has no stack trace on Android ([#5965](https://github.com/getsentry/sentry-react-native/pull/5965))
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/js/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function getRNSentryModule(): Spec | undefined {
: NativeModules.RNSentry;
}

const RNSentry: Spec | undefined = getRNSentryModule();
let RNSentry: Spec | undefined = getRNSentryModule();

export interface Screenshot {
data: Uint8Array;
Expand Down Expand Up @@ -649,6 +649,9 @@ export const NATIVE: SentryNativeWrapper = {
},

isNativeAvailable(): boolean {
if (!RNSentry) {
RNSentry = getRNSentryModule();
}
return this._isModuleLoaded(RNSentry);
},

Expand Down
34 changes: 34 additions & 0 deletions packages/core/test/wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1208,4 +1208,38 @@ describe('Tests Native Wrapper', () => {
});
});
});

describe('isNativeAvailable', () => {
test('retries module resolution if initially undefined', () => {
// Simulate the race condition: RNSentry was undefined at module load time
// but becomes available when isNativeAvailable() is called during init()
let mockModule: Spec | undefined = undefined;

jest.resetModules();
jest.doMock('react-native', () => ({
NativeModules: {
get RNSentry() {
return mockModule;
},
},
Platform: { OS: 'ios' },
}));
// Ensure TurboModules path is not used so NativeModules.RNSentry is checked
jest.doMock('../src/js/utils/environment', () => ({
isTurboModuleEnabled: () => false,
}));

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { NATIVE: isolatedNATIVE } = require('../src/js/wrapper');

// Initially unavailable (simulates race condition)
expect(isolatedNATIVE.isNativeAvailable()).toBe(false);

// Native module becomes available (TurboModule registered)
mockModule = RNSentry;

// isNativeAvailable retries and finds it
expect(isolatedNATIVE.isNativeAvailable()).toBe(true);
});
});
});
Loading