From 9a3ca655542f9224aa21b4838b439748a3043b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kry=C5=A1tof=20Wold=C5=99ich?= <31292499+krystofwoldrich@users.noreply.github.com> Date: Thu, 23 Feb 2023 14:07:31 +0100 Subject: [PATCH] feat(sdk): Add `in_foreground` to event app context (#2826) --- CHANGELOG.md | 6 +++ src/js/integrations/devicecontext.ts | 10 ++++- test/integrations/devicecontext.test.ts | 51 +++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7fef15e6..8f6e51a0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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). diff --git a/src/js/integrations/devicecontext.ts b/src/js/integrations/devicecontext.ts index 1b0c193e1..8e79970db 100644 --- a/src/js/integrations/devicecontext.ts +++ b/src/js/integrations/devicecontext.ts @@ -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'; @@ -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', + } + } if (nativeContext) { event.contexts = { ...nativeContext, ...event.contexts }; } diff --git a/test/integrations/devicecontext.test.ts b/test/integrations/devicecontext.test.ts index b3473f54b..b4898f3ab 100644 --- a/test/integrations/devicecontext.test.ts +++ b/test/integrations/devicecontext.test.ts @@ -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; @@ -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; mockEvent?: Event;