Skip to content
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Add App Context `in_foreground` ([#2826](https://github.com/getsentry/sentry-react-native/pull/2826))

## 5.0.0

The React Native SDK version 5 supports both Legacy (from RN 0.65 and above) and New Architecture (from RN 0.69 and above) as well as the new React Native Gradle Plugin (introduced in RN 0.71). For detailed [migration guide visit our docs](https://docs.sentry.io/platforms/react-native/migration/#from-4x-to-5x).
Expand Down
10 changes: 9 additions & 1 deletion src/js/integrations/devicecontext.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable complexity */
import type { Event, EventProcessor, Hub, Integration } from '@sentry/types';
import { logger, severityLevelFromString } from '@sentry/utils';
import { AppState } from 'react-native';

import { breadcrumbFromObject } from '../breadcrumb';
import type { NativeDeviceContextsResponse } from '../NativeRNSentry';
Expand Down Expand Up @@ -47,7 +48,14 @@ export class DeviceContext implements Integration {
event.user = nativeUser;
}

const nativeContext = native.context;
let nativeContext = native.context;
if (AppState.currentState !== 'unknown') {
nativeContext = nativeContext || {};
nativeContext.app = {
...nativeContext.app,
in_foreground: AppState.currentState === 'active',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it need to be set to "false" at some point too? Or are you passing the nativeContext to the native SDKs and they set it for you?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The in_foreground is merged into what I get from native SDKs. As I think the value that RN reports is important for RN devs.

If the AppState.currentState === 'active' => true, else false.

Thanks for the comment I've added a test to make it clear how it works.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I see now, gotcha. Thanks!

}
}
if (nativeContext) {
event.contexts = { ...nativeContext, ...event.contexts };
}
Expand Down
51 changes: 51 additions & 0 deletions test/integrations/devicecontext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import { DeviceContext } from '../../src/js/integrations';
import type { NativeDeviceContextsResponse } from '../../src/js/NativeRNSentry';
import { NATIVE } from '../../src/js/wrapper';

let mockCurrentAppState: string = 'unknown';

jest.mock('../../src/js/wrapper');
jest.mock('react-native', () => ({
AppState: new Proxy({}, { get: () => mockCurrentAppState }),
NativeModules: {},
Platform: {},
}));

describe('Device Context Integration', () => {
let integration: DeviceContext;
Expand Down Expand Up @@ -122,6 +129,50 @@ describe('Device Context Integration', () => {
});
});

it('adds in_foreground false to native app contexts', async () => {
mockCurrentAppState = 'background';
const { processedEvent } = await executeIntegrationWith({
nativeContexts: { context: { app: { native: 'value' } } },
});
expect(processedEvent).toStrictEqual({
contexts: {
app: {
native: 'value',
in_foreground: false,
},
},
});
});

it('adds in_foreground to native app contexts', async () => {
mockCurrentAppState = 'active';
const { processedEvent } = await executeIntegrationWith({
nativeContexts: { context: { app: { native: 'value' } } },
});
expect(processedEvent).toStrictEqual({
contexts: {
app: {
native: 'value',
in_foreground: true,
},
},
});
});

it('do not add in_foreground if unknown', async () => {
mockCurrentAppState = 'unknown';
const { processedEvent } = await executeIntegrationWith({
nativeContexts: { context: { app: { native: 'value' } } },
});
expect(processedEvent).toStrictEqual({
contexts: {
app: {
native: 'value',
},
},
});
});

async function executeIntegrationWith({ nativeContexts, mockEvent }: {
nativeContexts: Record<string, unknown>;
mockEvent?: Event;
Expand Down