diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dbba68c2f..44acf428f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ > make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first. +## Unreleased + +### Features + +- Adds tags with Expo Updates context variables to make them searchable and filterable ([#5788](https://github.com/getsentry/sentry-react-native/pull/5788)) + ## 8.3.0 ### Features diff --git a/packages/core/src/js/integrations/expocontext.ts b/packages/core/src/js/integrations/expocontext.ts index 4040a7ebe0..e3d9e1630d 100644 --- a/packages/core/src/js/integrations/expocontext.ts +++ b/packages/core/src/js/integrations/expocontext.ts @@ -48,10 +48,14 @@ export const expoContextIntegration = (): Integration => { } function addExpoUpdatesContext(event: Event): void { + const updatesContext = getExpoUpdatesContextCached(); + event.contexts = event.contexts || {}; event.contexts[OTA_UPDATES_CONTEXT_KEY] = { - ...getExpoUpdatesContextCached(), + ...updatesContext, }; + + addExpoUpdatesTags(event, updatesContext); } function getExpoUpdatesContextCached(): ExpoUpdatesContext { @@ -111,6 +115,20 @@ export function getExpoUpdatesContext(): ExpoUpdatesContext { return updatesContext; } +function addExpoUpdatesTags(event: Event, updatesContext: ExpoUpdatesContext): void { + event.tags = event.tags || {}; + + if (updatesContext.update_id) { + event.tags['expo.updates.update_id'] = updatesContext.update_id; + } + if (updatesContext.channel) { + event.tags['expo.updates.channel'] = updatesContext.channel; + } + if (updatesContext.runtime_version) { + event.tags['expo.updates.runtime_version'] = updatesContext.runtime_version; + } +} + function addExpoGoContext(event: Event): void { if (!isExpoGo()) { return; diff --git a/packages/core/test/integrations/expocontext.test.ts b/packages/core/test/integrations/expocontext.test.ts index 47381e8926..1b9a79c014 100644 --- a/packages/core/test/integrations/expocontext.test.ts +++ b/packages/core/test/integrations/expocontext.test.ts @@ -90,6 +90,14 @@ describe('Expo Context Integration', () => { expect(actualEvent.contexts?.[OTA_UPDATES_CONTEXT_KEY]).toBeUndefined(); }); + + it('does not add expo updates tags', () => { + const actualEvent = executeIntegrationFor({}); + + expect(actualEvent.tags?.['expo.updates.update_id']).toBeUndefined(); + expect(actualEvent.tags?.['expo.updates.channel']).toBeUndefined(); + expect(actualEvent.tags?.['expo.updates.runtime_version']).toBeUndefined(); + }); }); describe('In Expo App', () => { @@ -169,6 +177,57 @@ describe('Expo Context Integration', () => { }); }); + it('adds expo updates tags for searchable fields', () => { + jest.spyOn(expoModules, 'getExpoUpdates').mockReturnValue({ + updateId: '123', + channel: 'default', + runtimeVersion: '1.0.0', + }); + + const actualEvent = executeIntegrationFor({}); + + expect(actualEvent.tags).toEqual( + expect.objectContaining({ + 'expo.updates.update_id': '123', + 'expo.updates.channel': 'default', + 'expo.updates.runtime_version': '1.0.0', + }), + ); + }); + + it('does not add expo updates tags when values are missing', () => { + jest.spyOn(expoModules, 'getExpoUpdates').mockReturnValue({}); + + const actualEvent = executeIntegrationFor({}); + + expect(actualEvent.tags?.['expo.updates.update_id']).toBeUndefined(); + expect(actualEvent.tags?.['expo.updates.channel']).toBeUndefined(); + expect(actualEvent.tags?.['expo.updates.runtime_version']).toBeUndefined(); + }); + + it('does not overwrite existing tags', () => { + jest.spyOn(expoModules, 'getExpoUpdates').mockReturnValue({ + updateId: '123', + channel: 'default', + runtimeVersion: '1.0.0', + }); + + const actualEvent = executeIntegrationFor({ + tags: { + existing_tag: 'existing_value', + }, + }); + + expect(actualEvent.tags).toEqual( + expect.objectContaining({ + existing_tag: 'existing_value', + 'expo.updates.update_id': '123', + 'expo.updates.channel': 'default', + 'expo.updates.runtime_version': '1.0.0', + }), + ); + }); + it('avoids adding values of unexpected types', () => { jest.spyOn(expoModules, 'getExpoUpdates').mockReturnValue({ updateId: {},