Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 5.4.2

### Features

- Add `expo`, `react_native_version` and `hermes_version` to React Native Context ([#3050](https://github.com/getsentry/sentry-react-native/pull/3050))

### Fixes

- Fix `event.origin` and `event.environment` on unhandled exception ([#3041](https://github.com/getsentry/sentry-react-native/pull/3041))
Expand Down
15 changes: 14 additions & 1 deletion src/js/integrations/reactnativeinfo.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import type { Context, Event, EventHint, EventProcessor, Integration } from '@sentry/types';

import { isFabricEnabled, isHermesEnabled, isTurboModuleEnabled } from '../utils/environment';
import {
getHermesVersion,
getReactNativeVersion,
isExpo,
isFabricEnabled,
isHermesEnabled,
isTurboModuleEnabled,
} from '../utils/environment';
import type { ReactNativeError } from './debugsymbolicator';

export interface ReactNativeContext extends Context {
js_engine?: string;
turbo_module: boolean;
fabric: boolean;
expo: boolean;
hermes_version?: string;
react_native_version: string;
component_stack?: string;
}

Expand All @@ -32,10 +42,13 @@ export class ReactNativeInfo implements Integration {
const reactNativeContext: ReactNativeContext = {
turbo_module: isTurboModuleEnabled(),
fabric: isFabricEnabled(),
react_native_version: getReactNativeVersion(),
expo: isExpo(),
};

if (isHermesEnabled()) {
reactNativeContext.js_engine = 'hermes';
reactNativeContext.hermes_version = getHermesVersion();
} else if (reactNativeError?.jsEngine) {
reactNativeContext.js_engine = reactNativeError.jsEngine;
}
Expand Down
21 changes: 21 additions & 0 deletions src/js/utils/environment.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { version as RNV } from 'react-native/Libraries/Core/ReactNativeVersion';

import { RN_GLOBAL_OBJ } from '../utils/worldwide';

/** Checks if the React Native Hermes engine is running */
Expand All @@ -14,3 +16,22 @@ export function isTurboModuleEnabled(): boolean {
export function isFabricEnabled(): boolean {
return RN_GLOBAL_OBJ.nativeFabricUIManager != null;
}

/** Returns React Native Version as semver string */
export function getReactNativeVersion(): string {
return `${RNV.major}.${RNV.minor}.${RNV.patch}${RNV.prerelease != null ? `-${RNV.prerelease}` : ''}`;
}

/** Checks if Expo is present in the runtime */
export function isExpo(): boolean {
return RN_GLOBAL_OBJ.expo != null;
}

/** Returns Hermes Version if hermes is present in the runtime */
export function getHermesVersion(): string | undefined {
return (
RN_GLOBAL_OBJ.HermesInternal &&
RN_GLOBAL_OBJ.HermesInternal.getRuntimeProperties &&
RN_GLOBAL_OBJ.HermesInternal.getRuntimeProperties()['OSS Release Version']
);
}
5 changes: 4 additions & 1 deletion src/js/utils/worldwide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import type { ErrorUtils } from 'react-native/types';
export interface ReactNativeInternalGlobal extends InternalGlobal {
__sentry_rn_v4_registered?: boolean;
__sentry_rn_v5_registered?: boolean;
HermesInternal: unknown;
HermesInternal?: {
getRuntimeProperties?: () => Record<string, string | undefined>;
};
Promise: unknown;
__turboModuleProxy: unknown;
nativeFabricUIManager: unknown;
ErrorUtils?: ErrorUtils;
expo: unknown;
}

/** Get's the global object for the current JavaScript runtime */
Expand Down
11 changes: 11 additions & 0 deletions test/integrations/reactnativeinfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,27 @@ import { ReactNativeInfo } from '../../src/js/integrations/reactnativeinfo';
let mockedIsHermesEnabled: jest.Mock<boolean, []>;
let mockedIsTurboModuleEnabled: jest.Mock<boolean, []>;
let mockedIsFabricEnabled: jest.Mock<boolean, []>;
let mockedGetReactNativeVersion: jest.Mock<string, []>;
let mockedGetHermesVersion: jest.Mock<string | undefined, []>;
let mockedIsExpo: jest.Mock<boolean, []>;

jest.mock('../../src/js/utils/environment', () => ({
isHermesEnabled: () => mockedIsHermesEnabled(),
isTurboModuleEnabled: () => mockedIsTurboModuleEnabled(),
isFabricEnabled: () => mockedIsFabricEnabled(),
getReactNativeVersion: () => mockedGetReactNativeVersion(),
getHermesVersion: () => mockedGetHermesVersion(),
isExpo: () => mockedIsExpo(),
}));

describe('React Native Info', () => {
beforeEach(() => {
mockedIsHermesEnabled = jest.fn().mockReturnValue(false);
mockedIsTurboModuleEnabled = jest.fn().mockReturnValue(false);
mockedIsFabricEnabled = jest.fn().mockReturnValue(false);
mockedGetReactNativeVersion = jest.fn().mockReturnValue('1000.0.0-test');
mockedGetHermesVersion = jest.fn().mockReturnValue(undefined);
mockedIsExpo = jest.fn().mockReturnValue(false);
});

afterEach(() => {
Expand All @@ -39,6 +48,8 @@ describe('React Native Info', () => {
react_native_context: <ReactNativeContext>{
turbo_module: false,
fabric: false,
react_native_version: '1000.0.0-test',
expo: false,
},
},
});
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"extends": "./node_modules/@sentry/typescript/tsconfig.json",
"include": [
"src/js/*.ts"
"src/js/*.ts",
"typings/*.d.ts"
],
"exclude": [
"node_modules"
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"src/js/*.ts",
"src/js/*.tsx",
"test/**/*.ts",
"test/**/*.tsx"
"test/**/*.tsx",
"typings/*.d.ts"
],
"exclude": [
"dist"
Expand Down
8 changes: 8 additions & 0 deletions typings/react-native.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
declare module 'react-native/Libraries/Core/ReactNativeVersion' {
export const version: {
major: number;
minor: number;
patch: number;
prerelease: string | null;
};
};