From 117d38b6bd9b230a83a3c5217a782cba5589dd9a Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:51:55 +0100 Subject: [PATCH 01/10] fix(replay): `browserReplayIntegration` should not be included by default (#4270) --- CHANGELOG.md | 6 +++ src/js/integrations/default.ts | 6 ++- test/sdk.test.ts | 96 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0856bda6d5..b6dd3546c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- `browserReplayIntegration` is no longer included by default on React Native Web ([#4270](https://github.com/getsentry/sentry-react-native/pull/4270), [#4308](https://github.com/getsentry/sentry-react-native/pull/4308)) + ## 5.35.0 ### Fixes diff --git a/src/js/integrations/default.ts b/src/js/integrations/default.ts index bcbac5c2cb..29369b3dad 100644 --- a/src/js/integrations/default.ts +++ b/src/js/integrations/default.ts @@ -10,7 +10,6 @@ import { browserApiErrorsIntegration, browserGlobalHandlersIntegration, browserLinkedErrorsIntegration, - browserReplayIntegration, debugSymbolicatorIntegration, dedupeIntegration, deviceContextIntegration, @@ -120,10 +119,13 @@ export function getDefaultIntegrations(options: ReactNativeClientOptions): Integ (options._experiments && typeof options._experiments.replaysOnErrorSampleRate === 'number') || (options._experiments && typeof options._experiments.replaysSessionSampleRate === 'number') ) { - integrations.push(notWeb() ? mobileReplayIntegration() : browserReplayIntegration()); if (!notWeb()) { + // We can't create and add browserReplayIntegration as it overrides the users supplied one + // The browser replay integration works differently than the rest of default integrations (options as BrowserOptions).replaysOnErrorSampleRate = options._experiments.replaysOnErrorSampleRate; (options as BrowserOptions).replaysSessionSampleRate = options._experiments.replaysSessionSampleRate; + } else { + integrations.push(mobileReplayIntegration()); } } diff --git a/test/sdk.test.ts b/test/sdk.test.ts index 0593ba1667..a007cb7953 100644 --- a/test/sdk.test.ts +++ b/test/sdk.test.ts @@ -648,6 +648,102 @@ describe('Tests the SDK functionality', () => { expect(actualIntegrations).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'ExpoContext' })])); }); + + it('adds mobile replay integration when _experiments.replaysOnErrorSampleRate is set', () => { + init({ + _experiments: { + replaysOnErrorSampleRate: 1.0, + }, + }); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); + }); + + it('adds mobile replay integration when _experiments.replaysSessionSampleRate is set', () => { + init({ + _experiments: { + replaysSessionSampleRate: 1.0, + }, + }); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); + }); + + it('does not add mobile replay integration when no replay sample rates are set', () => { + init({ + _experiments: {}, + }); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); + }); + + it('does not add any replay integration when on web even with on error sample rate', () => { + (notWeb as jest.Mock).mockImplementation(() => false); + init({ + _experiments: { + replaysOnErrorSampleRate: 1.0, + }, + }); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); + expect(actualIntegrations).toEqual( + expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), + ); + }); + + it('does not add any replay integration when on web even with session sample rate', () => { + (notWeb as jest.Mock).mockImplementation(() => false); + init({ + _experiments: { + replaysSessionSampleRate: 1.0, + }, + }); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); + expect(actualIntegrations).toEqual( + expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), + ); + }); + + it('does not add any replay integration when on web', () => { + (notWeb as jest.Mock).mockImplementation(() => false); + init({}); + + const actualOptions = usedOptions(); + const actualIntegrations = actualOptions?.integrations; + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); + expect(actualIntegrations).toEqual( + expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), + ); + }); + + it('converts experimental replay options to standard web options when on web', () => { + (notWeb as jest.Mock).mockImplementation(() => false); + init({ + _experiments: { + replaysOnErrorSampleRate: 0.5, + replaysSessionSampleRate: 0.1, + }, + }); + + const actualOptions = usedOptions(); + expect(actualOptions).toEqual( + expect.objectContaining({ + replaysOnErrorSampleRate: 0.5, + replaysSessionSampleRate: 0.1, + }), + ); + }); }); function createMockedIntegration({ name }: { name?: string } = {}): Integration { From 99c3cd9adb732f162154c46803c6ddbf6b54f903 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 25 Nov 2024 17:55:15 +0100 Subject: [PATCH 02/10] empty, trigger CI in PR --- .github/workflows/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 656492517e..114f943ded 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -7,6 +7,7 @@ on: - v5 pull_request: + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true From f0f316ca213373e160714b352113f6230d63bf6d Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:46:39 +0100 Subject: [PATCH 03/10] Update client.ts --- src/js/client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/client.ts b/src/js/client.ts index 278c9e0cb2..b9e954e1cd 100644 --- a/src/js/client.ts +++ b/src/js/client.ts @@ -26,6 +26,7 @@ import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs'; import { mergeOutcomes } from './utils/outcome'; import { NATIVE } from './wrapper'; + /** * The Sentry React Native SDK Client. * From 444a356ed43482490ffbae4715d334b4d25c61c5 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 2 Dec 2024 15:19:16 +0100 Subject: [PATCH 04/10] fix ci --- .github/workflows/e2e.yml | 18 ++++++------------ .github/workflows/native-tests.yml | 4 ++-- .github/workflows/sample-application.yml | 9 ++++----- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 114f943ded..db580edb75 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -14,6 +14,8 @@ concurrency: env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + IOS_DEVICE: 'iPhone 16' + IOS_RUNTIME: '18.1' jobs: diff_check: @@ -43,7 +45,7 @@ jobs: platform: ["ios", "android"] include: - platform: ios - runs-on: macos-12 + runs-on: macos-13 name: iOS appPlain: test/perf/test-app-plain.ipa - platform: android @@ -188,13 +190,9 @@ jobs: - platform: ios rn-version: '0.73.9' runs-on: macos-14 # uses m1 https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available/ - runtime: 'latest' - device: 'iPhone 14' - platform: ios rn-version: '0.65.3' - runs-on: macos-12 - runtime: 'latest' - device: 'iPhone 14' + runs-on: macos-13 - platform: android runs-on: ubuntu-latest exclude: @@ -345,14 +343,10 @@ jobs: include: - platform: ios rn-version: '0.73.9' - runs-on: macos-14 # uses m1 https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available/ - runtime: 'latest' - device: 'iPhone 14' + runs-on: macos-15 - platform: ios rn-version: '0.65.3' - runs-on: macos-latest - runtime: 'latest' - device: 'iPhone 14' + runs-on: macos-15 - platform: android runs-on: ubuntu-latest exclude: diff --git a/.github/workflows/native-tests.yml b/.github/workflows/native-tests.yml index f296aeea1c..0451941410 100644 --- a/.github/workflows/native-tests.yml +++ b/.github/workflows/native-tests.yml @@ -23,7 +23,7 @@ jobs: test-ios: name: ios - runs-on: macos-14 # uses m1 https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available/ + runs-on: macos-15 needs: [diff_check] if: ${{ needs.diff_check.outputs.skip_ci != 'true' }} steps: @@ -49,7 +49,7 @@ jobs: env: SCHEME: RNSentryCocoaTester CONFIGURATION: Release - DESTINATION: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + DESTINATION: 'platform=iOS Simulator,OS=latest,name=iPhone 16' run: | env NSUnbufferedIO=YES \ xcodebuild -workspace *.xcworkspace \ diff --git a/.github/workflows/sample-application.yml b/.github/workflows/sample-application.yml index b104938a5e..6775b30f7a 100644 --- a/.github/workflows/sample-application.yml +++ b/.github/workflows/sample-application.yml @@ -46,11 +46,9 @@ jobs: build-type: ['dev', 'production'] include: - platform: ios - runs-on: macos-14 # uses m1 https://github.blog/changelog/2024-01-30-github-actions-macos-14-sonoma-is-now-available/ - runtime: 'latest' - device: 'iPhone 14' + runs-on: macos-15 - platform: macos - runs-on: macos-14 + runs-on: macos-15 - platform: android runs-on: ubuntu-latest exclude: @@ -143,7 +141,8 @@ jobs: -workspace sentryreactnativesample.xcworkspace \ -configuration "$CONFIG" \ -scheme sentryreactnativesample \ - -destination 'platform=iOS Simulator,OS=${{ matrix.runtime }},name=${{ matrix.device }}' \ + -sdk 'iphonesimulator' \ + -destination 'generic/platform=iOS Simulator' \ ONLY_ACTIVE_ARCH=yes \ -derivedDataPath "$derivedData" \ build \ From 51e8d5b354169cfabb4163c6fbe73a6e60f55238 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:39:35 +0100 Subject: [PATCH 05/10] Update e2e.mjs --- scripts/e2e.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/e2e.mjs b/scripts/e2e.mjs index e73ecb105b..1c2943664d 100755 --- a/scripts/e2e.mjs +++ b/scripts/e2e.mjs @@ -181,7 +181,8 @@ if (actions.includes('test')) { execSync(`set -o pipefail && xcodebuild \ -project node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj \ -scheme WebDriverAgentRunner \ - -destination 'platform=iOS Simulator,OS=${runtime},name=${device}' \ + -sdk 'iphonesimulator' \ + -destination 'generic/platform=iOS Simulator' \ GCC_TREAT_WARNINGS_AS_ERRORS=0 \ COMPILER_INDEX_STORE_ENABLE=NO \ ONLY_ACTIVE_ARCH=yes \ From 5cf4c45aa12ad45bdedb60eb697d85e520027653 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:43:35 +0100 Subject: [PATCH 06/10] Update e2e.yml --- .github/workflows/e2e.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index db580edb75..9f0b1723fd 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -7,7 +7,6 @@ on: - v5 pull_request: - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true From d573b008c184abda5566912cef9e4733e6b7f353 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:44:13 +0100 Subject: [PATCH 07/10] Update client.ts --- src/js/client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/js/client.ts b/src/js/client.ts index b9e954e1cd..278c9e0cb2 100644 --- a/src/js/client.ts +++ b/src/js/client.ts @@ -26,7 +26,6 @@ import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs'; import { mergeOutcomes } from './utils/outcome'; import { NATIVE } from './wrapper'; - /** * The Sentry React Native SDK Client. * From 083468964af6fc9e87cea961a602ea804284bfab Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:45:52 +0100 Subject: [PATCH 08/10] Update e2e.yml --- .github/workflows/e2e.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 9f0b1723fd..cc133a8467 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -174,8 +174,6 @@ jobs: USE_FRAMEWORKS: ${{ matrix.ios-use-frameworks }} PRODUCTION: ${{ matrix.build-type == 'production' && '1' || '0' }} RCT_NEW_ARCH_ENABLED: ${{ matrix.rn-architecture == 'new' && '1' || '0' }} - IOS_RUNTIME: ${{ matrix.runtime }} - IOS_DEVICE: ${{ matrix.device }} strategy: fail-fast: false # keeps matrix running if one fails matrix: @@ -363,7 +361,6 @@ jobs: rn-architecture: 'new' env: PLATFORM: ${{ matrix.platform }} - DEVICE: ${{ matrix.device }} steps: - uses: actions/checkout@v4 From 5aec52933ee083af11d025f9c77566ce466368a5 Mon Sep 17 00:00:00 2001 From: Krystof Woldrich <31292499+krystofwoldrich@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:07:32 +0100 Subject: [PATCH 09/10] Update e2e.mjs --- scripts/e2e.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/e2e.mjs b/scripts/e2e.mjs index 1c2943664d..16bb11903e 100755 --- a/scripts/e2e.mjs +++ b/scripts/e2e.mjs @@ -152,7 +152,8 @@ if (actions.includes('build')) { -workspace ${appName}.xcworkspace \ -configuration ${buildType} \ -scheme ${appName} \ - -destination 'platform=iOS Simulator,OS=${runtime},name=${device}' \ + -sdk 'iphonesimulator' \ + -destination 'generic/platform=iOS Simulator' \ ONLY_ACTIVE_ARCH=yes \ -derivedDataPath DerivedData \ build | tee xcodebuild.log | xcbeautify`, From f5f711d1fed111c2a14e31455c682b304242655f Mon Sep 17 00:00:00 2001 From: Krystof Woldrich Date: Mon, 2 Dec 2024 17:49:13 +0100 Subject: [PATCH 10/10] fix lint --- test/sdk.test.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/sdk.test.ts b/test/sdk.test.ts index a007cb7953..9921289a0e 100644 --- a/test/sdk.test.ts +++ b/test/sdk.test.ts @@ -694,9 +694,7 @@ describe('Tests the SDK functionality', () => { const actualOptions = usedOptions(); const actualIntegrations = actualOptions?.integrations; expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); - expect(actualIntegrations).toEqual( - expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), - ); + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); }); it('does not add any replay integration when on web even with session sample rate', () => { @@ -710,9 +708,7 @@ describe('Tests the SDK functionality', () => { const actualOptions = usedOptions(); const actualIntegrations = actualOptions?.integrations; expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); - expect(actualIntegrations).toEqual( - expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), - ); + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); }); it('does not add any replay integration when on web', () => { @@ -722,9 +718,7 @@ describe('Tests the SDK functionality', () => { const actualOptions = usedOptions(); const actualIntegrations = actualOptions?.integrations; expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'Replay' })])); - expect(actualIntegrations).toEqual( - expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })]), - ); + expect(actualIntegrations).toEqual(expect.not.arrayContaining([expect.objectContaining({ name: 'MobileReplay' })])); }); it('converts experimental replay options to standard web options when on web', () => {