Skip to content

Commit 1652677

Browse files
Add expo, hermes version, react_native_version to react_native_context (#3050)
1 parent c882ec1 commit 1652677

File tree

8 files changed

+82
-8
lines changed

8 files changed

+82
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Features
6+
7+
- Add `expo`, `react_native_version` and `hermes_version` to React Native Context ([#3050](https://github.com/getsentry/sentry-react-native/pull/3050))
8+
39
## 5.4.2
410

511
### Fixes

src/js/integrations/reactnativeinfo.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import type { Context, Event, EventHint, EventProcessor, Integration } from '@sentry/types';
22

3-
import { isFabricEnabled, isHermesEnabled, isTurboModuleEnabled } from '../utils/environment';
3+
import {
4+
getHermesVersion,
5+
getReactNativeVersion,
6+
isExpo,
7+
isFabricEnabled,
8+
isHermesEnabled,
9+
isTurboModuleEnabled,
10+
} from '../utils/environment';
411
import type { ReactNativeError } from './debugsymbolicator';
512

613
export interface ReactNativeContext extends Context {
714
js_engine?: string;
815
turbo_module: boolean;
916
fabric: boolean;
17+
expo: boolean;
18+
hermes_version?: string;
19+
react_native_version: string;
1020
component_stack?: string;
1121
}
1222

@@ -32,10 +42,16 @@ export class ReactNativeInfo implements Integration {
3242
const reactNativeContext: ReactNativeContext = {
3343
turbo_module: isTurboModuleEnabled(),
3444
fabric: isFabricEnabled(),
45+
react_native_version: getReactNativeVersion(),
46+
expo: isExpo(),
3547
};
3648

3749
if (isHermesEnabled()) {
3850
reactNativeContext.js_engine = 'hermes';
51+
const hermesVersion = getHermesVersion();
52+
if (hermesVersion) {
53+
reactNativeContext.hermes_version = getHermesVersion();
54+
}
3955
} else if (reactNativeError?.jsEngine) {
4056
reactNativeContext.js_engine = reactNativeError.jsEngine;
4157
}

src/js/utils/environment.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { version as RNV } from 'react-native/Libraries/Core/ReactNativeVersion';
2+
13
import { RN_GLOBAL_OBJ } from '../utils/worldwide';
24

35
/** Checks if the React Native Hermes engine is running */
@@ -14,3 +16,22 @@ export function isTurboModuleEnabled(): boolean {
1416
export function isFabricEnabled(): boolean {
1517
return RN_GLOBAL_OBJ.nativeFabricUIManager != null;
1618
}
19+
20+
/** Returns React Native Version as semver string */
21+
export function getReactNativeVersion(): string {
22+
return `${RNV.major}.${RNV.minor}.${RNV.patch}${RNV.prerelease != null ? `-${RNV.prerelease}` : ''}`;
23+
}
24+
25+
/** Checks if Expo is present in the runtime */
26+
export function isExpo(): boolean {
27+
return RN_GLOBAL_OBJ.expo != null;
28+
}
29+
30+
/** Returns Hermes Version if hermes is present in the runtime */
31+
export function getHermesVersion(): string | undefined {
32+
return (
33+
RN_GLOBAL_OBJ.HermesInternal &&
34+
RN_GLOBAL_OBJ.HermesInternal.getRuntimeProperties &&
35+
RN_GLOBAL_OBJ.HermesInternal.getRuntimeProperties()['OSS Release Version']
36+
);
37+
}

src/js/utils/worldwide.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import type { ErrorUtils } from 'react-native/types';
66
export interface ReactNativeInternalGlobal extends InternalGlobal {
77
__sentry_rn_v4_registered?: boolean;
88
__sentry_rn_v5_registered?: boolean;
9-
HermesInternal: unknown;
9+
HermesInternal?: {
10+
getRuntimeProperties?: () => Record<string, string | undefined>;
11+
};
1012
Promise: unknown;
1113
__turboModuleProxy: unknown;
1214
nativeFabricUIManager: unknown;
1315
ErrorUtils?: ErrorUtils;
16+
expo: unknown;
1417
}
1518

1619
/** Get's the global object for the current JavaScript runtime */

test/integrations/reactnativeinfo.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,27 @@ import { ReactNativeInfo } from '../../src/js/integrations/reactnativeinfo';
77
let mockedIsHermesEnabled: jest.Mock<boolean, []>;
88
let mockedIsTurboModuleEnabled: jest.Mock<boolean, []>;
99
let mockedIsFabricEnabled: jest.Mock<boolean, []>;
10+
let mockedGetReactNativeVersion: jest.Mock<string, []>;
11+
let mockedGetHermesVersion: jest.Mock<string | undefined, []>;
12+
let mockedIsExpo: jest.Mock<boolean, []>;
1013

1114
jest.mock('../../src/js/utils/environment', () => ({
1215
isHermesEnabled: () => mockedIsHermesEnabled(),
1316
isTurboModuleEnabled: () => mockedIsTurboModuleEnabled(),
1417
isFabricEnabled: () => mockedIsFabricEnabled(),
18+
getReactNativeVersion: () => mockedGetReactNativeVersion(),
19+
getHermesVersion: () => mockedGetHermesVersion(),
20+
isExpo: () => mockedIsExpo(),
1521
}));
1622

1723
describe('React Native Info', () => {
1824
beforeEach(() => {
19-
mockedIsHermesEnabled = jest.fn().mockReturnValue(false);
25+
mockedIsHermesEnabled = jest.fn().mockReturnValue(true);
2026
mockedIsTurboModuleEnabled = jest.fn().mockReturnValue(false);
2127
mockedIsFabricEnabled = jest.fn().mockReturnValue(false);
28+
mockedGetReactNativeVersion = jest.fn().mockReturnValue('1000.0.0-test');
29+
mockedGetHermesVersion = jest.fn().mockReturnValue(undefined);
30+
mockedIsExpo = jest.fn().mockReturnValue(false);
2231
});
2332

2433
afterEach(() => {
@@ -39,20 +48,28 @@ describe('React Native Info', () => {
3948
react_native_context: <ReactNativeContext>{
4049
turbo_module: false,
4150
fabric: false,
51+
js_engine: 'hermes',
52+
react_native_version: '1000.0.0-test',
53+
expo: false,
4254
},
4355
},
56+
tags: {
57+
hermes: 'true',
58+
},
4459
});
4560
});
4661

4762
it('adds hermes tag and js_engine to context if hermes enabled', async () => {
4863
mockedIsHermesEnabled = jest.fn().mockReturnValue(true);
64+
mockedGetHermesVersion = jest.fn().mockReturnValue('for RN 999.0.0');
4965
const actualEvent = await executeIntegrationFor({}, {});
5066

5167
expectMocksToBeCalledOnce();
5268
expect(actualEvent?.tags?.hermes).toEqual('true');
53-
expect((actualEvent?.contexts?.react_native_context as ReactNativeContext | undefined)?.js_engine).toEqual(
54-
'hermes',
55-
);
69+
expect(actualEvent?.contexts?.react_native_context).toEqual(expect.objectContaining({
70+
js_engine: 'hermes',
71+
hermes_version: 'for RN 999.0.0',
72+
}));
5673
});
5774

5875
it('does not override existing hermes tag', async () => {
@@ -69,6 +86,7 @@ describe('React Native Info', () => {
6986
});
7087

7188
it('adds engine from rn error', async () => {
89+
mockedIsHermesEnabled = jest.fn().mockReturnValue(false);
7290
const mockedHint: EventHint = {
7391
originalException: <ReactNativeError>{
7492
jsEngine: 'test_engine',

tsconfig.build.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"extends": "./node_modules/@sentry/typescript/tsconfig.json",
33
"include": [
4-
"src/js/*.ts"
4+
"src/js/*.ts",
5+
"typings/*.d.ts"
56
],
67
"exclude": [
78
"node_modules"

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"src/js/*.ts",
66
"src/js/*.tsx",
77
"test/**/*.ts",
8-
"test/**/*.tsx"
8+
"test/**/*.tsx",
9+
"typings/*.d.ts"
910
],
1011
"exclude": [
1112
"dist"

typings/react-native.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
declare module 'react-native/Libraries/Core/ReactNativeVersion' {
2+
export const version: {
3+
major: number;
4+
minor: number;
5+
patch: number;
6+
prerelease: string | null;
7+
};
8+
};

0 commit comments

Comments
 (0)