diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index abe356580..22e46eec6 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -466,4 +466,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 0c7eb82d495ca56953c50916b7b49e7512632eb6 -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/packages/core/package.json b/packages/core/package.json index 4cdf8c44d..ffd9383dc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -47,6 +47,7 @@ "dependencies": { "@react-native-async-storage/async-storage": "^1.15.17", "@segment/sovran-react-native": "^0.2.6", + "deepmerge": "^4.2.2", "js-base64": "^3.7.2", "nanoid": "^3.1.25" }, diff --git a/packages/core/src/__tests__/internal/checkInstalledVersion.test.ts b/packages/core/src/__tests__/internal/checkInstalledVersion.test.ts index 5e3b2af95..b749fca0c 100644 --- a/packages/core/src/__tests__/internal/checkInstalledVersion.test.ts +++ b/packages/core/src/__tests__/internal/checkInstalledVersion.test.ts @@ -3,6 +3,7 @@ import { getMockLogger } from '../__helpers__/mockLogger'; import * as context from '../../context'; import { MockSegmentStore } from '../__helpers__/mockSegmentStore'; import { Context, EventType } from '../../types'; +import deepmerge from 'deepmerge'; jest .spyOn(Date.prototype, 'toISOString') @@ -161,4 +162,47 @@ describe('internal #checkInstalledVersion', () => { type: EventType.TrackEvent, }); }); + + it('merges context and preserves context injected by plugins during configure', async () => { + const injectedContextByPlugins = { + device: { + adTrackingEnabled: true, + advertisingId: 'mock-advertising-id', + }, + }; + + const store = new MockSegmentStore({ + context: { + ...currentContext, + ...injectedContextByPlugins, + }, + }); + + client = new SegmentClient({ + ...clientArgs, + store, + }); + + const newContext = { + ...currentContext, // Just adding the full object to prevent TS complaining about missing properties + app: { + version: '1.5', + build: '2', + name: 'Test', + namespace: 'Test', + }, + device: { + manufacturer: 'Apple', + model: 'iPhone', + name: 'iPhone', + type: 'iOS', + }, + }; + jest.spyOn(context, 'getContext').mockResolvedValueOnce(newContext); + await client.init(); + + expect(store.context.get()).toEqual( + deepmerge(newContext, injectedContextByPlugins) + ); + }); }); diff --git a/packages/core/src/analytics.ts b/packages/core/src/analytics.ts index f8c9b0c4f..549e88fb0 100644 --- a/packages/core/src/analytics.ts +++ b/packages/core/src/analytics.ts @@ -1,7 +1,7 @@ -import { AppState, AppStateStatus } from 'react-native'; import type { Unsubscribe } from '@segment/sovran-react-native'; +import deepmerge from 'deepmerge'; +import { AppState, AppStateStatus } from 'react-native'; import { getContext } from './context'; - import { applyRawEventData, createAliasEvent, @@ -566,7 +566,8 @@ export class SegmentClient { const previousContext = this.store.context.get(); - this.store.context.set(context); + // Only overwrite the previous context values to preserve any values that are added by enrichment plugins like IDFA + this.store.context.set(deepmerge(previousContext ?? {}, context)); if (!this.config.trackAppLifecycleEvents) { return;