From fd4ca7524350a65ed5b2bd6da888e1bf6bc02e5c Mon Sep 17 00:00:00 2001 From: Marco Saia Date: Fri, 14 Jun 2024 11:40:20 +0200 Subject: [PATCH 1/3] Bumped SDK versions --- example/index.tsx | 6 ++++++ packages/core/DatadogSDKReactNative.podspec | 12 ++++++------ packages/core/android/build.gradle | 8 ++++---- .../DatadogSDKReactNativeSessionReplay.podspec | 2 +- .../react-native-session-replay/android/build.gradle | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/example/index.tsx b/example/index.tsx index 4cb1260a5..077a3f11c 100644 --- a/example/index.tsx +++ b/example/index.tsx @@ -1,3 +1,9 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2016-Present Datadog, Inc. + */ + import {AppRegistry} from 'react-native'; import App from './src/App'; import {startReactNativeNavigation} from './src/WixApp'; diff --git a/packages/core/DatadogSDKReactNative.podspec b/packages/core/DatadogSDKReactNative.podspec index 72e89bd98..222f782bf 100644 --- a/packages/core/DatadogSDKReactNative.podspec +++ b/packages/core/DatadogSDKReactNative.podspec @@ -19,12 +19,12 @@ Pod::Spec.new do |s| s.dependency "React-Core" # /!\ Remember to keep the versions in sync with DatadogSDKReactNativeSessionReplay.podspec - s.dependency 'DatadogCore', '~> 2.7.1' - s.dependency 'DatadogLogs', '~> 2.7.1' - s.dependency 'DatadogTrace', '~> 2.7.1' - s.dependency 'DatadogRUM', '~> 2.7.1' - s.dependency 'DatadogCrashReporting', '~> 2.7.1' - s.dependency 'DatadogWebViewTracking', '~> 2.7.1' + s.dependency 'DatadogCore', '~> 2.13.0' + s.dependency 'DatadogLogs', '~> 2.13.0' + s.dependency 'DatadogTrace', '~> 2.13.0' + s.dependency 'DatadogRUM', '~> 2.13.0' + s.dependency 'DatadogCrashReporting', '~> 2.13.0' + s.dependency 'DatadogWebViewTracking', '~> 2.13.0' s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'ios/Tests/**/*.{swift,json}' diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index 2ac78fe8c..91ce2d84e 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -188,10 +188,10 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compileOnly "com.squareup.okhttp3:okhttp:3.12.13" - implementation "com.datadoghq:dd-sdk-android-rum:2.6.2" - implementation "com.datadoghq:dd-sdk-android-logs:2.6.2" - implementation "com.datadoghq:dd-sdk-android-trace:2.6.2" - implementation "com.datadoghq:dd-sdk-android-webview:2.6.2" + implementation "com.datadoghq:dd-sdk-android-rum:2.11.0" + implementation "com.datadoghq:dd-sdk-android-logs:2.11.0" + implementation "com.datadoghq:dd-sdk-android-trace:2.11.0" + implementation "com.datadoghq:dd-sdk-android-webview:2.11.0" implementation "com.google.code.gson:gson:2.10.0" testImplementation "org.junit.platform:junit-platform-launcher:1.6.2" testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2" diff --git a/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec b/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec index 419058a3d..86add0390 100644 --- a/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec +++ b/packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec @@ -19,7 +19,7 @@ Pod::Spec.new do |s| s.dependency "React-Core" # /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec - s.dependency 'DatadogSessionReplay', '~> 2.7.1' + s.dependency 'DatadogSessionReplay', '~> 2.13.0' s.dependency 'DatadogSDKReactNative' s.test_spec 'Tests' do |test_spec| diff --git a/packages/react-native-session-replay/android/build.gradle b/packages/react-native-session-replay/android/build.gradle index 0c6a4dc28..d0059a6d5 100644 --- a/packages/react-native-session-replay/android/build.gradle +++ b/packages/react-native-session-replay/android/build.gradle @@ -188,7 +188,7 @@ dependencies { api "com.facebook.react:react-android:$reactNativeVersion" } implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "com.datadoghq:dd-sdk-android-session-replay:2.6.2" + implementation "com.datadoghq:dd-sdk-android-session-replay:2.11.0" implementation project(path: ':datadog_mobile-react-native') testImplementation "org.junit.platform:junit-platform-launcher:1.6.2" From 5faa876d7c198c05cb1866901ae8b75e9352eeba Mon Sep 17 00:00:00 2001 From: Marco Saia Date: Fri, 14 Jun 2024 13:40:30 +0200 Subject: [PATCH 2/3] Fixed latest SDK breaking changes --- example-new-architecture/ios/Podfile.lock | 60 ++++++------- example/ios/Podfile.lock | 84 ++++++++++--------- .../com/datadog/tools/unit/MockRumMonitor.kt | 2 + ...lemetryConfigurationEventForgeryFactory.kt | 15 ++++ .../core/ios/Sources/DatadogSDKWrapper.swift | 6 +- packages/core/ios/Tests/DdSdkTests.swift | 11 ++- packages/core/ios/Tests/MockDatadogCore.swift | 20 +++-- packages/core/ios/Tests/RUMMocks.swift | 14 ++++ .../DdInternalTestingImplementation.kt | 4 +- .../DdInternalTestingImplementationTest.kt | 4 +- .../ios/Sources/DatadogCoreProxy.swift | 41 +++++---- ...eactNativeSessionReplayExtensionSupport.kt | 35 ++------ ...skTextMapper.kt => ReactEditTextMapper.kt} | 42 +++++++--- .../mappers/ReactMaskInputTextMapper.kt | 54 ------------ .../sessionreplay/mappers/ReactTextMapper.kt | 26 ++++-- .../mappers/ReactViewGroupMapper.kt | 26 ++++-- .../sessionreplay/utils/TextViewUtils.kt | 2 +- ...NativeSessionReplayExtensionSupportTest.kt | 52 ++---------- .../mappers/ReactViewGroupMapperTest.kt | 16 ++-- .../sessionreplay/utils/TextViewUtilsTest.kt | 4 +- .../DdSessionReplayImplementation.swift | 2 +- .../ios/Tests/DdSessionReplayTests.swift | 20 ++--- .../ios/Tests/RCTTextViewRecorderTests.swift | 9 +- 23 files changed, 272 insertions(+), 277 deletions(-) rename packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/{ReactMaskTextMapper.kt => ReactEditTextMapper.kt} (52%) delete mode 100644 packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt diff --git a/example-new-architecture/ios/Podfile.lock b/example-new-architecture/ios/Podfile.lock index 0979e727b..9b37241cf 100644 --- a/example-new-architecture/ios/Podfile.lock +++ b/example-new-architecture/ios/Podfile.lock @@ -1,23 +1,23 @@ PODS: - boost (1.83.0) - CocoaAsyncSocket (7.6.5) - - DatadogCore (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogCrashReporting (2.7.1): - - DatadogInternal (= 2.7.1) - - PLCrashReporter (~> 1.11.1) - - DatadogInternal (2.7.1) - - DatadogLogs (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogRUM (2.7.1): - - DatadogInternal (= 2.7.1) + - DatadogCore (2.13.0): + - DatadogInternal (= 2.13.0) + - DatadogCrashReporting (2.13.0): + - DatadogInternal (= 2.13.0) + - PLCrashReporter (~> 1.11.2) + - DatadogInternal (2.13.0) + - DatadogLogs (2.13.0): + - DatadogInternal (= 2.13.0) + - DatadogRUM (2.13.0): + - DatadogInternal (= 2.13.0) - DatadogSDKReactNative (2.3.6): - - DatadogCore (~> 2.7.1) - - DatadogCrashReporting (~> 2.7.1) - - DatadogLogs (~> 2.7.1) - - DatadogRUM (~> 2.7.1) - - DatadogTrace (~> 2.7.1) - - DatadogWebViewTracking (~> 2.7.1) + - DatadogCore (~> 2.13.0) + - DatadogCrashReporting (~> 2.13.0) + - DatadogLogs (~> 2.13.0) + - DatadogRUM (~> 2.13.0) + - DatadogTrace (~> 2.13.0) + - DatadogWebViewTracking (~> 2.13.0) - glog - hermes-engine - RCT-Folly (= 2022.05.16.00) @@ -36,10 +36,11 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - DatadogTrace (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogWebViewTracking (2.7.1): - - DatadogInternal (= 2.7.1) + - DatadogTrace (2.13.0): + - DatadogInternal (= 2.13.0) + - OpenTelemetrySwiftApi (= 1.6.0) + - DatadogWebViewTracking (2.13.0): + - DatadogInternal (= 2.13.0) - DoubleConversion (1.1.6) - FBLazyVector (0.73.6) - Flipper (0.201.0): @@ -105,6 +106,7 @@ PODS: - hermes-engine/Pre-built (0.73.6) - libevent (2.1.12) - OpenSSL-Universal (1.1.1100) + - OpenTelemetrySwiftApi (1.6.0) - PLCrashReporter (1.11.2) - RCT-Folly (2022.05.16.00): - boost @@ -1295,6 +1297,7 @@ SPEC REPOS: - fmt - libevent - OpenSSL-Universal + - OpenTelemetrySwiftApi - PLCrashReporter - SocketRocket @@ -1408,14 +1411,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: d3f49c53809116a5d38da093a8aa78bf551aed09 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DatadogCore: 4a4cdf7beca3aa12b7095bebd926acea1a865a99 - DatadogCrashReporting: f8b4ea638acaf58b68bbc51cb62a2d876f763241 - DatadogInternal: b9217da25018284c087a2ed4b9bb3b0f26c767c0 - DatadogLogs: 3b4132eefa67f196bb3ab2d603c1a2acd1292615 - DatadogRUM: 8845815ba89f5ab8ceee765ee268f7de36f3e35d - DatadogSDKReactNative: 65a87cf33b9dde71b730ccb98713fa8709dbaf67 - DatadogTrace: a63da746c609bd4c683bca61a94429889e33b11e - DatadogWebViewTracking: 713f862ddd89173e0a3f5342cefa23def40f0f48 + DatadogCore: 9390fd07a89f57a23983de66fbec5bf3c2034f7a + DatadogCrashReporting: 79b67b790df186524fc76d45c0b8ce751c36ef41 + DatadogInternal: 61ab12516d2faad79e35973534c29a72b0d44382 + DatadogLogs: 912d7b3fd3d75df856de060082b785f92f7cefe6 + DatadogRUM: b5629479d4553d80f2a57ef9db44ce37e56f8b97 + DatadogSDKReactNative: 2146426b86f121fbe03418c0576a77aaeaf2cc47 + DatadogTrace: 1f40893de00c9a9b87be46fa7016fa0d50c4e66b + DatadogWebViewTracking: d1e2e755bb2ed7c18208471b9cbcfc7cb920aa45 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 FBLazyVector: f64d1e2ea739b4d8f7e4740cde18089cd97fe864 Flipper: c7a0093234c4bdd456e363f2f19b2e4b27652d44 @@ -1431,6 +1434,7 @@ SPEC CHECKSUMS: hermes-engine: 9cecf9953a681df7556b8cc9c74905de8f3293c0 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + OpenTelemetrySwiftApi: 657da8071c2908caecce11548e006f779924ff9c PLCrashReporter: 499c53b0104f95c302d94fd723ebb03c56d9bac8 RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 RCTRequired: ca1d7414aba0b27efcfa2ccd37637edb1ab77d96 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 20835aa01..59f079c45 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,46 +1,47 @@ PODS: - boost (1.83.0) - - DatadogCore (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogCrashReporting (2.7.1): - - DatadogInternal (= 2.7.1) - - PLCrashReporter (~> 1.11.1) - - DatadogInternal (2.7.1) - - DatadogLogs (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogRUM (2.7.1): - - DatadogInternal (= 2.7.1) + - DatadogCore (2.13.0): + - DatadogInternal (= 2.13.0) + - DatadogCrashReporting (2.13.0): + - DatadogInternal (= 2.13.0) + - PLCrashReporter (~> 1.11.2) + - DatadogInternal (2.13.0) + - DatadogLogs (2.13.0): + - DatadogInternal (= 2.13.0) + - DatadogRUM (2.13.0): + - DatadogInternal (= 2.13.0) - DatadogSDKReactNative (2.3.6): - - DatadogCore (~> 2.7.1) - - DatadogCrashReporting (~> 2.7.1) - - DatadogLogs (~> 2.7.1) - - DatadogRUM (~> 2.7.1) - - DatadogTrace (~> 2.7.1) - - DatadogWebViewTracking (~> 2.7.1) + - DatadogCore (~> 2.13.0) + - DatadogCrashReporting (~> 2.13.0) + - DatadogLogs (~> 2.13.0) + - DatadogRUM (~> 2.13.0) + - DatadogTrace (~> 2.13.0) + - DatadogWebViewTracking (~> 2.13.0) - React-Core - DatadogSDKReactNative/Tests (2.3.6): - - DatadogCore (~> 2.7.1) - - DatadogCrashReporting (~> 2.7.1) - - DatadogLogs (~> 2.7.1) - - DatadogRUM (~> 2.7.1) - - DatadogTrace (~> 2.7.1) - - DatadogWebViewTracking (~> 2.7.1) + - DatadogCore (~> 2.13.0) + - DatadogCrashReporting (~> 2.13.0) + - DatadogLogs (~> 2.13.0) + - DatadogRUM (~> 2.13.0) + - DatadogTrace (~> 2.13.0) + - DatadogWebViewTracking (~> 2.13.0) - React-Core - DatadogSDKReactNativeSessionReplay (2.3.6-alpha.0): - DatadogSDKReactNative - - DatadogSessionReplay (~> 2.7.1) + - DatadogSessionReplay (~> 2.13.0) - React-Core - DatadogSDKReactNativeSessionReplay/Tests (2.3.6-alpha.0): - DatadogSDKReactNative - - DatadogSessionReplay (~> 2.7.1) + - DatadogSessionReplay (~> 2.13.0) - React-Core - React-RCTText - - DatadogSessionReplay (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogTrace (2.7.1): - - DatadogInternal (= 2.7.1) - - DatadogWebViewTracking (2.7.1): - - DatadogInternal (= 2.7.1) + - DatadogSessionReplay (2.13.0): + - DatadogInternal (= 2.13.0) + - DatadogTrace (2.13.0): + - DatadogInternal (= 2.13.0) + - OpenTelemetrySwiftApi (= 1.6.0) + - DatadogWebViewTracking (2.13.0): + - DatadogInternal (= 2.13.0) - DoubleConversion (1.1.6) - FBLazyVector (0.73.6) - FBReactNativeSpec (0.73.6): @@ -57,6 +58,7 @@ PODS: - hermes-engine/Pre-built (0.73.6) - HMSegmentedControl (1.5.6) - libevent (2.1.12) + - OpenTelemetrySwiftApi (1.6.0) - PLCrashReporter (1.11.2) - RCT-Folly (2022.05.16.00): - boost @@ -1201,6 +1203,7 @@ SPEC REPOS: - fmt - HMSegmentedControl - libevent + - OpenTelemetrySwiftApi - PLCrashReporter - SocketRocket @@ -1323,16 +1326,16 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: d3f49c53809116a5d38da093a8aa78bf551aed09 - DatadogCore: 4a4cdf7beca3aa12b7095bebd926acea1a865a99 - DatadogCrashReporting: f8b4ea638acaf58b68bbc51cb62a2d876f763241 - DatadogInternal: b9217da25018284c087a2ed4b9bb3b0f26c767c0 - DatadogLogs: 3b4132eefa67f196bb3ab2d603c1a2acd1292615 - DatadogRUM: 8845815ba89f5ab8ceee765ee268f7de36f3e35d - DatadogSDKReactNative: 2abe05ac536daaf462cc801db9c9ad8b36eb2f8d - DatadogSDKReactNativeSessionReplay: 8709d75b13290d95a793de50d107ca869522a650 - DatadogSessionReplay: f189054bd2fc2d14c487fd614f04b2b8041dd81f - DatadogTrace: a63da746c609bd4c683bca61a94429889e33b11e - DatadogWebViewTracking: 713f862ddd89173e0a3f5342cefa23def40f0f48 + DatadogCore: 9390fd07a89f57a23983de66fbec5bf3c2034f7a + DatadogCrashReporting: 79b67b790df186524fc76d45c0b8ce751c36ef41 + DatadogInternal: 61ab12516d2faad79e35973534c29a72b0d44382 + DatadogLogs: 912d7b3fd3d75df856de060082b785f92f7cefe6 + DatadogRUM: b5629479d4553d80f2a57ef9db44ce37e56f8b97 + DatadogSDKReactNative: cf34eea449b1eaa05e479cb95a5fea7210e09b98 + DatadogSDKReactNativeSessionReplay: 16b6db2ef784ce0bc2b14c2afb4cb16f37f41300 + DatadogSessionReplay: 2e7795c1a8a86ff989ed5c0ccd616eed0f6c9a3a + DatadogTrace: 1f40893de00c9a9b87be46fa7016fa0d50c4e66b + DatadogWebViewTracking: d1e2e755bb2ed7c18208471b9cbcfc7cb920aa45 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 FBLazyVector: f64d1e2ea739b4d8f7e4740cde18089cd97fe864 FBReactNativeSpec: 9f2b8b243131565335437dba74923a8d3015e780 @@ -1341,6 +1344,7 @@ SPEC CHECKSUMS: hermes-engine: 9cecf9953a681df7556b8cc9c74905de8f3293c0 HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + OpenTelemetrySwiftApi: 657da8071c2908caecce11548e006f779924ff9c PLCrashReporter: 499c53b0104f95c302d94fd723ebb03c56d9bac8 RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 RCTRequired: ca1d7414aba0b27efcfa2ccd37637edb1ab77d96 diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt index 6c810110f..ba97ac996 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt @@ -44,6 +44,8 @@ class MockRumMonitor : RumMonitor { override fun addFeatureFlagEvaluation(name: String, value: Any) {} + override fun addFeatureFlagEvaluations(featureFlags: Map) {} + override fun addTiming(name: String) {} override fun clearAttributes() {} diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt index c5d22ae53..8e1601546 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/forge/TelemetryConfigurationEventForgeryFactory.kt @@ -6,6 +6,7 @@ package com.datadog.tools.unit.forge +import com.datadog.android.privacy.TrackingConsent import com.datadog.android.telemetry.model.TelemetryConfigurationEvent import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.ForgeryFactory @@ -49,8 +50,20 @@ internal class TelemetryConfigurationEventForgeryFactory : forge.aNullable { aLong() }, forge.aNullable { aLong() }, forge.aNullable { aLong() }, + forge.aNullable { + aValueFrom( + TelemetryConfigurationEvent.TraceContextInjection::class.java + ) + }, forge.aNullable { aLong() }, forge.aNullable { aLong() }, + forge.aNullable { aLong() }, + forge.aNullable { + aValueFrom( + TelemetryConfigurationEvent.TrackingConsent::class.java + ) + }, + forge.aNullable { aBool() }, forge.aNullable { aBool() }, forge.aNullable { aBool() }, forge.aNullable { aBool() }, @@ -80,6 +93,8 @@ internal class TelemetryConfigurationEventForgeryFactory : forge.aNullable { aBool() }, forge.aNullable { aBool() }, + forge.aNullable { aBool() }, + forge.aNullable { aBool() }, forge.aNullable { aBool() }, forge.aNullable { aBool() }, forge.aNullable { aList { aString() } }, diff --git a/packages/core/ios/Sources/DatadogSDKWrapper.swift b/packages/core/ios/Sources/DatadogSDKWrapper.swift index abf40113c..4cabca237 100644 --- a/packages/core/ios/Sources/DatadogSDKWrapper.swift +++ b/packages/core/ios/Sources/DatadogSDKWrapper.swift @@ -139,11 +139,11 @@ public class DatadogSDKWrapper { reactVersion: reactVersion, trackCrossPlatformLongTasks: trackCrossPlatformLongTasks, trackErrors: trackErrors, - trackInteractions: trackInteractions, - trackLongTask: trackLongTask, + trackLongTask: trackLongTask, trackNativeErrors: trackNativeErrors, trackNativeLongTasks: trackNativeLongTasks, - trackNetworkRequests: trackNetworkRequests + trackNetworkRequests: trackNetworkRequests, + trackUserInteractions: trackInteractions ) } diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index 678c75238..04eb25f06 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -513,17 +513,20 @@ internal class DdSdkTests: XCTestCase { let expectedFirstPartyHosts: [String: Set]? = ["example.com": [.datadog, .b3], "datadog.com": [.b3multi, .tracecontext]] var actualFirstPartyHosts: [String: Set]? var actualTracingSamplingRate: Float? + var actualTraceContextInjection: TraceContextInjection? switch ddConfig.urlSessionTracking?.firstPartyHostsTracing { - case .trace(_,_): break - case let .traceWithHeaders(hostsWithHeaders, samplingRate): + case .trace(_,_,_): break + case let .traceWithHeaders(hostsWithHeaders, samplingRate, traceContextInjection): actualFirstPartyHosts = hostsWithHeaders actualTracingSamplingRate = samplingRate + actualTraceContextInjection = traceContextInjection break case .none: break } XCTAssertEqual(actualFirstPartyHosts, expectedFirstPartyHosts) XCTAssertEqual(actualTracingSamplingRate, 66) + XCTAssertEqual(actualTraceContextInjection, .all) } func testBuildTelemetrySampleRate() { @@ -806,7 +809,7 @@ internal class DdSdkTests: XCTestCase { XCTAssertEqual(core.configuration?.initializationType, "LEGACY") XCTAssertEqual(core.configuration?.trackErrors, true) - XCTAssertEqual(core.configuration?.trackInteractions, true) + XCTAssertEqual(core.configuration?.trackUserInteractions, true) XCTAssertEqual(core.configuration?.trackNetworkRequests, true) XCTAssertEqual(core.configuration?.trackNativeErrors, false) XCTAssertEqual(core.configuration?.trackNativeLongTasks, false) @@ -886,7 +889,7 @@ internal class DdSdkTests: XCTestCase { DatadogSDKWrapper.shared.setCoreInstance(core: core) DdSdkNativeInitialization().enableFeatures(sdkConfiguration: configuration) - DdSdkImplementation().consumeWebviewEvent(message: "{\"eventType\":\"RUM\",\"event\":{\"blabla\":\"custom message\"}}", resolve: mockResolve, reject: mockReject) + DdSdkImplementation().consumeWebviewEvent(message: "{\"eventType\":\"rum\",\"event\":{\"blabla\":\"custom message\"}}", resolve: mockResolve, reject: mockReject) XCTAssertNotNil(core.baggages["browser-rum-event"]) } diff --git a/packages/core/ios/Tests/MockDatadogCore.swift b/packages/core/ios/Tests/MockDatadogCore.swift index e59480f7c..424ab04ed 100644 --- a/packages/core/ios/Tests/MockDatadogCore.swift +++ b/packages/core/ios/Tests/MockDatadogCore.swift @@ -8,8 +8,6 @@ @testable import DatadogInternal internal class MockDatadogCore: DatadogCoreProtocol { - func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) {} - func send(message: FeatureMessage, else fallback: @escaping () -> Void) { if // Configuration Telemetry Message case .telemetry(let telemetry) = message, @@ -20,6 +18,10 @@ internal class MockDatadogCore: DatadogCoreProtocol { if case .baggage(let key, let baggage) = message { self.baggages[key] = baggage } + + if case .webview(let webViewMessage) = message { + self.baggages["browser-rum-event"] = webViewMessage + } } @ReadWriteLock @@ -29,20 +31,20 @@ internal class MockDatadogCore: DatadogCoreProtocol { @ReadWriteLock private(set) var baggages: [String: Any] = [:] - func register(feature: T) throws where T : DatadogFeature { + func register(feature: T) throws where T : DatadogInternal.DatadogFeature { features[T.name] = feature } - func get(feature type: T.Type) -> T? where T : DatadogFeature { + func feature(named name: String, type: T.Type) -> T? { return nil } - func scope(for feature: String) -> FeatureScope? { - return nil + func scope(for featureType: T.Type) -> any DatadogInternal.FeatureScope where T : DatadogInternal.DatadogFeature { + return NOPFeatureScope() } - func set(feature: String, attributes: @escaping () -> FeatureBaggage) {} - - func update(feature: String, attributes: @escaping () -> FeatureBaggage) {} + func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) { + baggages[key] = baggage + } } diff --git a/packages/core/ios/Tests/RUMMocks.swift b/packages/core/ios/Tests/RUMMocks.swift index 2ab32a86b..aff3024d9 100644 --- a/packages/core/ios/Tests/RUMMocks.swift +++ b/packages/core/ios/Tests/RUMMocks.swift @@ -279,10 +279,15 @@ extension RUMResourceEvent: RandomMockable { os: .mockRandom(), resource: .init( connect: .init(duration: .mockRandom(), start: .mockRandom()), + decodedBodySize: .mockRandom(), dns: .init(duration: .mockRandom(), start: .mockRandom()), download: .init(duration: .mockRandom(), start: .mockRandom()), duration: .mockRandom(), + encodedBodySize: .mockRandom(), firstByte: .init(duration: .mockRandom(), start: .mockRandom()), + graphql: .init( + operationName: .mockRandom(), + operationType: [.query, .mutation, .subscription].randomElement()!), id: .mockRandom(), method: .mockRandom(), provider: .init( @@ -291,9 +296,11 @@ extension RUMResourceEvent: RandomMockable { type: Bool.random() ? .firstParty : nil ), redirect: .init(duration: .mockRandom(), start: .mockRandom()), + renderBlockingStatus: [.blocking, .nonBlocking].randomElement()!, size: .mockRandom(), ssl: .init(duration: .mockRandom(), start: .mockRandom()), statusCode: .mockRandom(), + transferSize: .mockRandom(), type: [.native, .image].randomElement()!, url: .mockRandom() ), @@ -340,10 +347,15 @@ extension RUMResourceEvent: RandomMockable { os: .mockRandom(), resource: .init( connect: .init(duration: .mockRandom(), start: .mockRandom()), + decodedBodySize: .mockRandom(), dns: .init(duration: .mockRandom(), start: .mockRandom()), download: .init(duration: .mockRandom(), start: .mockRandom()), duration: .mockRandom(), + encodedBodySize: .mockRandom(), firstByte: .init(duration: .mockRandom(), start: .mockRandom()), + graphql: .init( + operationName: .mockRandom(), + operationType: [.query, .mutation, .subscription].randomElement()!), id: .mockRandom(), method: .mockRandom(), provider: .init( @@ -352,9 +364,11 @@ extension RUMResourceEvent: RandomMockable { type: Bool.random() ? .firstParty : nil ), redirect: .init(duration: .mockRandom(), start: .mockRandom()), + renderBlockingStatus: [.blocking, .nonBlocking].randomElement()!, size: .mockRandom(), ssl: .init(duration: .mockRandom(), start: .mockRandom()), statusCode: .mockRandom(), + transferSize: .mockRandom(), type: [.native, .image].randomElement()!, url: .mockRandom() ), diff --git a/packages/internal-testing-tools/android/src/main/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementation.kt b/packages/internal-testing-tools/android/src/main/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementation.kt index 0211d5f0c..ca143f18a 100644 --- a/packages/internal-testing-tools/android/src/main/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementation.kt +++ b/packages/internal-testing-tools/android/src/main/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementation.kt @@ -13,6 +13,7 @@ import com.datadog.android.api.context.TimeInfo import com.datadog.android.api.feature.Feature import com.datadog.android.api.feature.FeatureScope import com.datadog.android.api.storage.EventBatchWriter +import com.datadog.android.api.storage.EventType import com.datadog.android.api.storage.RawBatchEvent import com.datadog.android.core.InternalSdkCore import com.datadog.android.core.internal.net.FirstPartyHostHeaderTypeResolver @@ -145,7 +146,8 @@ internal class EventBatchInterceptor: EventBatchWriter { override fun write( event: RawBatchEvent, - batchMetadata: ByteArray? + batchMetadata: ByteArray?, + eventType: EventType ): Boolean { val eventContent = String(event.data) diff --git a/packages/internal-testing-tools/android/src/test/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementationTest.kt b/packages/internal-testing-tools/android/src/test/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementationTest.kt index c97e1f821..b0d3910bf 100644 --- a/packages/internal-testing-tools/android/src/test/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementationTest.kt +++ b/packages/internal-testing-tools/android/src/test/kotlin/com/datadog/reactnative/internaltesting/DdInternalTestingImplementationTest.kt @@ -11,6 +11,7 @@ import com.datadog.android.api.context.DatadogContext import com.datadog.android.api.feature.Feature import com.datadog.android.api.feature.FeatureScope import com.datadog.android.api.storage.EventBatchWriter +import com.datadog.android.api.storage.EventType import com.datadog.android.api.storage.RawBatchEvent import com.datadog.android.core.InternalSdkCore import com.datadog.reactnative.DatadogSDKWrapperStorage @@ -76,7 +77,8 @@ internal class DdInternalTestingImplementationTest { .withWriteContext { _, eventBatchWriter -> eventBatchWriter.write( RawBatchEvent(data = "mock event for test".toByteArray()), - batchMetadata = null + batchMetadata = null, + eventType = EventType.DEFAULT ) } diff --git a/packages/internal-testing-tools/ios/Sources/DatadogCoreProxy.swift b/packages/internal-testing-tools/ios/Sources/DatadogCoreProxy.swift index 2ba0f5f1e..4ed1d3c65 100644 --- a/packages/internal-testing-tools/ios/Sources/DatadogCoreProxy.swift +++ b/packages/internal-testing-tools/ios/Sources/DatadogCoreProxy.swift @@ -9,6 +9,7 @@ import DatadogCore import DatadogInternal internal class DatadogCoreProxy: DatadogCoreProtocol { + let core: DatadogCoreProtocol private var featureScopeInterceptors: [String: FeatureScopeInterceptor] = [:] @@ -17,10 +18,6 @@ internal class DatadogCoreProxy: DatadogCoreProtocol { self.core = core } - func get(feature type: T.Type) -> T? where T : DatadogInternal.DatadogFeature { - return core.get(feature: type) - } - func register(feature: T) throws where T: DatadogFeature { do { try self.core.register(feature: feature) @@ -29,14 +26,19 @@ internal class DatadogCoreProxy: DatadogCoreProtocol { // TODO: add logging here } } - - func scope(for feature: String) -> FeatureScope? { - if let interceptor = featureScopeInterceptors[feature] { - return core.scope(for: feature).map { scope in - FeatureScopeProxy(proxy: scope, interceptor: interceptor) - } + + func feature(named name: String, type: T.Type) -> T? { + return core.feature(named: name, type: type) + } + + func scope(for featureType: T.Type) -> any DatadogInternal.FeatureScope where T : DatadogInternal.DatadogFeature { + if let interceptor = featureScopeInterceptors[featureType.name] { + return FeatureScopeProxy( + proxy: core.scope(for: featureType), + interceptor: interceptor + ) } - return core.scope(for: feature) + return core.scope(for: featureType) } func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) { @@ -46,17 +48,18 @@ internal class DatadogCoreProxy: DatadogCoreProtocol { func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) { core.set(baggage: baggage, forKey: key) } - - } private struct FeatureScopeProxy: FeatureScope { let proxy: FeatureScope let interceptor: FeatureScopeInterceptor + + var dataStore: DataStore { proxy.dataStore } + var telemetry: Telemetry { proxy.telemetry } - func eventWriteContext(bypassConsent: Bool, forceNewBatch: Bool, _ block: @escaping (DatadogContext, Writer) -> Void) { + func eventWriteContext(bypassConsent: Bool, _ block: @escaping (DatadogInternal.DatadogContext, any DatadogInternal.Writer) -> Void) { interceptor.enter() - proxy.eventWriteContext(bypassConsent: bypassConsent, forceNewBatch: forceNewBatch) { context, writer in + proxy.eventWriteContext(bypassConsent: bypassConsent) { context, writer in block(context, interceptor.intercept(writer: writer)) interceptor.leave() } @@ -65,6 +68,14 @@ private struct FeatureScopeProxy: FeatureScope { func context(_ block: @escaping (DatadogInternal.DatadogContext) -> Void) { proxy.context(block) } + + func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) { + proxy.send(message: message, else: fallback) + } + + func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) { + proxy.set(baggage: baggage, forKey: key) + } } private class FeatureScopeInterceptor { diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt index ad1dee845..bce3bd6b8 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt @@ -6,15 +6,12 @@ package com.datadog.reactnative.sessionreplay -import android.view.View import androidx.annotation.VisibleForTesting import com.datadog.android.api.InternalLogger import com.datadog.android.sessionreplay.ExtensionSupport -import com.datadog.android.sessionreplay.SessionReplayPrivacy -import com.datadog.android.sessionreplay.internal.recorder.OptionSelectorDetector -import com.datadog.android.sessionreplay.internal.recorder.mapper.WireframeMapper -import com.datadog.reactnative.sessionreplay.mappers.ReactMaskInputTextMapper -import com.datadog.reactnative.sessionreplay.mappers.ReactMaskTextMapper +import com.datadog.android.sessionreplay.MapperTypeWrapper +import com.datadog.android.sessionreplay.recorder.OptionSelectorDetector +import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper import com.facebook.react.bridge.ReactContext @@ -28,28 +25,14 @@ internal class ReactNativeSessionReplayExtensionSupport( private val logger: InternalLogger ) : ExtensionSupport { - override fun getCustomViewMappers(): Map, WireframeMapper>> { + override fun getCustomViewMappers(): List> { val uiManagerModule = getUiManagerModule() - return mapOf( - SessionReplayPrivacy.ALLOW to mapOf( - ReactViewGroup::class.java to ReactViewGroupMapper(), - ReactTextView::class.java to ReactTextMapper(reactContext, uiManagerModule), - ReactEditText::class.java to ReactTextMapper(reactContext, uiManagerModule) - ), - SessionReplayPrivacy.MASK to mapOf( - ReactViewGroup::class.java to ReactViewGroupMapper(), - ReactTextView::class.java to ReactMaskTextMapper(reactContext, uiManagerModule), - ReactEditText::class.java to ReactMaskTextMapper(reactContext, uiManagerModule) - ), - SessionReplayPrivacy.MASK_USER_INPUT to mapOf( - ReactViewGroup::class.java to ReactViewGroupMapper(), - ReactTextView::class.java to ReactMaskInputTextMapper(reactContext, uiManagerModule), - ReactEditText::class.java to ReactMaskInputTextMapper(reactContext, uiManagerModule) - ) - ).mapValues { - it.value as Map, WireframeMapper> - } + return listOf( + MapperTypeWrapper(ReactViewGroup::class.java, ReactViewGroupMapper()), + MapperTypeWrapper(ReactTextView::class.java, ReactTextMapper(reactContext, uiManagerModule)), + MapperTypeWrapper(ReactEditText::class.java, ReactEditTextMapper(reactContext, uiManagerModule)), + ) } override fun getOptionSelectorDetectors(): List { diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt similarity index 52% rename from packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt rename to packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt index e7aa2b2d5..f62a17cda 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt @@ -6,23 +6,36 @@ package com.datadog.reactnative.sessionreplay.mappers -import android.widget.TextView -import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.mapper.MaskTextViewMapper +import com.datadog.android.api.InternalLogger import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext +import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper +import com.datadog.android.sessionreplay.recorder.mapper.WireframeMapper +import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback +import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter +import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver +import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver +import com.datadog.android.sessionreplay.utils.DrawableToColorMapper import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver import com.datadog.reactnative.sessionreplay.TextPropertiesResolver import com.datadog.reactnative.sessionreplay.utils.TextViewUtils import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerModule +import com.facebook.react.views.textinput.ReactEditText -internal class ReactMaskTextMapper( +internal class ReactEditTextMapper( private val reactTextPropertiesResolver: TextPropertiesResolver = NoopTextPropertiesResolver(), - private val textViewUtils: TextViewUtils = TextViewUtils() -): MaskTextViewMapper() { + private val textViewUtils: TextViewUtils = TextViewUtils(), +): WireframeMapper { + + private val editTextMapper = EditTextMapper( + viewIdentifierResolver = DefaultViewIdentifierResolver, + colorStringFormatter = DefaultColorStringFormatter, + viewBoundsResolver = DefaultViewBoundsResolver, + drawableToColorMapper = DrawableToColorMapper.getDefault(), + ) internal constructor( reactContext: ReactContext, @@ -37,13 +50,19 @@ internal class ReactMaskTextMapper( ) } ) - override fun map( - view: TextView, + view: ReactEditText, mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback + asyncJobStatusCallback: AsyncJobStatusCallback, + internalLogger: InternalLogger ): List { - val wireframes = super.map(view, mappingContext, asyncJobStatusCallback) + val wireframes = editTextMapper.map( + view = view, + mappingContext = mappingContext, + asyncJobStatusCallback = asyncJobStatusCallback, + internalLogger = internalLogger + ) + return textViewUtils.mapTextViewToWireframes( wireframes = wireframes, view = view, @@ -52,4 +71,3 @@ internal class ReactMaskTextMapper( ) } } - diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt deleted file mode 100644 index 5c17e3ddb..000000000 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. - * This product includes software developed at Datadog (https://www.datadoghq.com/). - * Copyright 2016-Present Datadog, Inc. - */ - -package com.datadog.reactnative.sessionreplay.mappers - -import android.widget.TextView -import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.mapper.MaskInputTextViewMapper -import com.datadog.android.sessionreplay.model.MobileSegment -import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver -import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver -import com.datadog.reactnative.sessionreplay.TextPropertiesResolver -import com.datadog.reactnative.sessionreplay.utils.TextViewUtils -import com.facebook.react.bridge.ReactContext -import com.facebook.react.uimanager.UIManagerModule - -internal class ReactMaskInputTextMapper( - private val reactTextPropertiesResolver: TextPropertiesResolver, - private val textViewUtils: TextViewUtils = TextViewUtils() -): MaskInputTextViewMapper() { - - internal constructor( - reactContext: ReactContext, - uiManagerModule: UIManagerModule? - ): this( - reactTextPropertiesResolver = if (uiManagerModule == null) { - NoopTextPropertiesResolver() - } else { - ReactTextPropertiesResolver( - reactContext = reactContext, - uiManagerModule = uiManagerModule - ) - } - ) - - override fun map( - view: TextView, - mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback - ): List { - val wireframes = super.map(view, mappingContext, asyncJobStatusCallback) - return textViewUtils.mapTextViewToWireframes( - wireframes = wireframes, - view = view, - mappingContext = mappingContext, - reactTextPropertiesResolver = reactTextPropertiesResolver - ) - } -} - diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt index 4ff59505c..dcdd71b28 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt @@ -7,10 +7,16 @@ package com.datadog.reactnative.sessionreplay.mappers import android.widget.TextView -import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.mapper.TextViewMapper +import com.datadog.android.api.InternalLogger +import com.datadog.android.sessionreplay.SessionReplayPrivacy import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext +import com.datadog.android.sessionreplay.recorder.mapper.TextViewMapper +import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback +import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter +import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver +import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver +import com.datadog.android.sessionreplay.utils.DrawableToColorMapper import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver import com.datadog.reactnative.sessionreplay.TextPropertiesResolver @@ -21,8 +27,13 @@ import com.facebook.react.uimanager.UIManagerModule internal class ReactTextMapper( private val reactTextPropertiesResolver: TextPropertiesResolver = NoopTextPropertiesResolver(), - private val textViewUtils: TextViewUtils = TextViewUtils() -): TextViewMapper() { + private val textViewUtils: TextViewUtils = TextViewUtils(), +): TextViewMapper( + viewIdentifierResolver = DefaultViewIdentifierResolver, + colorStringFormatter = DefaultColorStringFormatter, + viewBoundsResolver = DefaultViewBoundsResolver, + drawableToColorMapper = DrawableToColorMapper.getDefault() +) { internal constructor( reactContext: ReactContext, @@ -41,9 +52,10 @@ internal class ReactTextMapper( override fun map( view: TextView, mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback + asyncJobStatusCallback: AsyncJobStatusCallback, + internalLogger: InternalLogger ): List { - val wireframes = super.map(view, mappingContext, asyncJobStatusCallback) + val wireframes = super.map(view, mappingContext, asyncJobStatusCallback, internalLogger) return textViewUtils.mapTextViewToWireframes( wireframes = wireframes, view = view, diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt index 260939884..a65fc18ad 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt @@ -6,11 +6,17 @@ package com.datadog.reactnative.sessionreplay.mappers -import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.mapper.BaseWireframeMapper -import com.datadog.android.sessionreplay.internal.recorder.mapper.TraverseAllChildrenMapper +import com.datadog.android.api.InternalLogger import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext +import com.datadog.android.sessionreplay.recorder.mapper.BaseWireframeMapper +import com.datadog.android.sessionreplay.recorder.mapper.TraverseAllChildrenMapper +import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback +import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter +import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver +import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver.resolveViewGlobalBounds +import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver +import com.datadog.android.sessionreplay.utils.DrawableToColorMapper import com.datadog.reactnative.sessionreplay.utils.DrawableUtils import com.datadog.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils import com.facebook.react.views.view.ReactViewGroup @@ -20,13 +26,19 @@ internal class ReactViewGroupMapper( ReactViewBackgroundDrawableUtils(), private val drawableUtils: DrawableUtils = DrawableUtils() ) : - BaseWireframeMapper(), - TraverseAllChildrenMapper { + BaseWireframeMapper( + viewIdentifierResolver = DefaultViewIdentifierResolver, + colorStringFormatter = DefaultColorStringFormatter, + viewBoundsResolver = DefaultViewBoundsResolver, + drawableToColorMapper = DrawableToColorMapper.getDefault() + ), + TraverseAllChildrenMapper { override fun map( view: ReactViewGroup, mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback + asyncJobStatusCallback: AsyncJobStatusCallback, + internalLogger: InternalLogger ): List { val pixelDensity = mappingContext.systemInformation.screenDensity val viewGlobalBounds = resolveViewGlobalBounds(view, pixelDensity) diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt index 43f4d72e2..ede97acf1 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt @@ -9,8 +9,8 @@ package com.datadog.reactnative.sessionreplay.utils import android.widget.TextView -import com.datadog.android.sessionreplay.internal.recorder.MappingContext import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext import com.datadog.reactnative.sessionreplay.TextPropertiesResolver internal class TextViewUtils { diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt index d393d30da..de64684de 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt @@ -7,17 +7,12 @@ package com.datadog.reactnative.sessionreplay import com.datadog.android.api.InternalLogger -import com.datadog.android.sessionreplay.SessionReplayPrivacy -import com.datadog.reactnative.sessionreplay.mappers.ReactMaskInputTextMapper -import com.datadog.reactnative.sessionreplay.mappers.ReactMaskTextMapper +import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerModule -import com.facebook.react.views.text.ReactTextView -import com.facebook.react.views.textinput.ReactEditText -import com.facebook.react.views.view.ReactViewGroup import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach @@ -65,51 +60,18 @@ internal class ReactNativeSessionReplayExtensionSupportTest { fun `M get custom view mappers W getCustomViewMappers()`() { // When val customViewMappers = testedExtensionSupport.getCustomViewMappers() - val allowMappers = customViewMappers[SessionReplayPrivacy.ALLOW] // Then - check(allowMappers != null) - assertThat(allowMappers).hasSize(3) - assertThat(allowMappers[ReactViewGroup::class.java]) - .isInstanceOf(ReactViewGroupMapper::class.java) - assertThat(allowMappers[ReactTextView::class.java]) - .isInstanceOf(ReactTextMapper::class.java) - assertThat(allowMappers[ReactEditText::class.java]) - .isInstanceOf(ReactTextMapper::class.java) - } - - @Test - fun `M get mask input mappers W getCustomViewMappers()`() { - // When - val customViewMappers = testedExtensionSupport.getCustomViewMappers() - val maskUserInputMappers = customViewMappers[SessionReplayPrivacy.MASK_USER_INPUT] + assertThat(customViewMappers).hasSize(3) - // Then - check(maskUserInputMappers != null) - assertThat(maskUserInputMappers).hasSize(3) - assertThat(maskUserInputMappers[ReactViewGroup::class.java]) + assertThat(customViewMappers[0].getUnsafeMapper()) .isInstanceOf(ReactViewGroupMapper::class.java) - assertThat(maskUserInputMappers[ReactTextView::class.java]) - .isInstanceOf(ReactMaskInputTextMapper::class.java) - assertThat(maskUserInputMappers[ReactEditText::class.java]) - .isInstanceOf(ReactMaskInputTextMapper::class.java) - } - @Test - fun `M get mask mappers W getCustomViewMappers()`() { - // When - val customViewMappers = testedExtensionSupport.getCustomViewMappers() - val maskMappers = customViewMappers[SessionReplayPrivacy.MASK] + assertThat(customViewMappers[1].getUnsafeMapper()) + .isInstanceOf(ReactTextMapper::class.java) - // Then - check(maskMappers != null) - assertThat(maskMappers).hasSize(3) - assertThat(maskMappers[ReactViewGroup::class.java]) - .isInstanceOf(ReactViewGroupMapper::class.java) - assertThat(maskMappers[ReactTextView::class.java]) - .isInstanceOf(ReactMaskTextMapper::class.java) - assertThat(maskMappers[ReactEditText::class.java]) - .isInstanceOf(ReactMaskTextMapper::class.java) + assertThat(customViewMappers[2].getUnsafeMapper()) + .isInstanceOf(ReactEditTextMapper::class.java) } @Test diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapperTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapperTest.kt index 61ac82e98..23662f149 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapperTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapperTest.kt @@ -9,10 +9,11 @@ package com.datadog.reactnative.sessionreplay.mappers import android.graphics.drawable.ColorDrawable -import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.SystemInformation +import com.datadog.android.api.InternalLogger import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext +import com.datadog.android.sessionreplay.recorder.SystemInformation +import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback import com.datadog.reactnative.sessionreplay.utils.DrawableUtils import com.datadog.reactnative.sessionreplay.utils.ReactViewBackgroundDrawableUtils import com.facebook.react.views.view.ReactViewBackgroundDrawable @@ -50,6 +51,9 @@ internal class ReactViewGroupMapperTest { @Mock private lateinit var mockAsyncJobStatusCallback: AsyncJobStatusCallback + @Mock + private lateinit var mockInternalLogger: InternalLogger + @Mock private lateinit var mockSystemInformation: SystemInformation @@ -92,7 +96,8 @@ internal class ReactViewGroupMapperTest { val result = testedMapper.map( view = mockReactViewGroup, mappingContext = mockMappingContext, - asyncJobStatusCallback = mockAsyncJobStatusCallback + asyncJobStatusCallback = mockAsyncJobStatusCallback, + internalLogger = mockInternalLogger )[0] as MobileSegment.Wireframe.ShapeWireframe // Then @@ -121,7 +126,8 @@ internal class ReactViewGroupMapperTest { val result = testedMapper.map( view = mockReactViewGroup, mappingContext = mockMappingContext, - asyncJobStatusCallback = mockAsyncJobStatusCallback + asyncJobStatusCallback = mockAsyncJobStatusCallback, + internalLogger = mockInternalLogger )[0] as MobileSegment.Wireframe.ShapeWireframe // Then diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt index b4128c0c6..485dce64d 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt @@ -10,9 +10,9 @@ import android.content.res.Resources import android.graphics.Typeface import android.util.DisplayMetrics import android.widget.TextView -import com.datadog.android.sessionreplay.internal.recorder.MappingContext -import com.datadog.android.sessionreplay.internal.recorder.SystemInformation import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.android.sessionreplay.recorder.MappingContext +import com.datadog.android.sessionreplay.recorder.SystemInformation import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver import fr.xgouchet.elmyr.Forge import fr.xgouchet.elmyr.junit5.ForgeExtension diff --git a/packages/react-native-session-replay/ios/Sources/DdSessionReplayImplementation.swift b/packages/react-native-session-replay/ios/Sources/DdSessionReplayImplementation.swift index 43477440c..40136b4ac 100644 --- a/packages/react-native-session-replay/ios/Sources/DdSessionReplayImplementation.swift +++ b/packages/react-native-session-replay/ios/Sources/DdSessionReplayImplementation.swift @@ -55,7 +55,7 @@ public class DdSessionReplayImplementation: NSObject { resolve(nil) } - func buildPrivacyLevel(privacyLevel: NSString) -> SessionReplay.Configuration.PrivacyLevel { + func buildPrivacyLevel(privacyLevel: NSString) -> SessionReplayPrivacyLevel { switch privacyLevel.lowercased { case "mask": return .mask diff --git a/packages/react-native-session-replay/ios/Tests/DdSessionReplayTests.swift b/packages/react-native-session-replay/ios/Tests/DdSessionReplayTests.swift index 6b074021a..0f38089b2 100644 --- a/packages/react-native-session-replay/ios/Tests/DdSessionReplayTests.swift +++ b/packages/react-native-session-replay/ios/Tests/DdSessionReplayTests.swift @@ -26,7 +26,7 @@ internal class DdSessionReplayTests: XCTestCase { let uiManagerMock = MockUIManager() DdSessionReplayImplementation(sessionReplayProvider:{ sessionReplayMock }, uiManager: uiManagerMock) .enable(replaySampleRate: 0, defaultPrivacyLevel: "MASK", customEndpoint: "", resolve: mockResolve, reject: mockReject) - + XCTAssertEqual(sessionReplayMock.calledMethods.first, .enable(replaySampleRate: 0.0, privacyLevel: .mask, customEndpoint: nil)) } @@ -78,7 +78,7 @@ internal class DdSessionReplayTests: XCTestCase { private class MockSessionReplay: SessionReplayProtocol { enum CalledMethod: Equatable { - case enable(replaySampleRate: Float, privacyLevel: SessionReplay.Configuration.PrivacyLevel, customEndpoint: URL?) + case enable(replaySampleRate: Float, privacyLevel: SessionReplayPrivacyLevel, customEndpoint: URL?) } public var calledMethods = [CalledMethod]() @@ -97,17 +97,15 @@ private class MockSessionReplay: SessionReplayProtocol { private class MockUIManager: RCTUIManager {} private class MockDatadogCore: DatadogCoreProtocol { - func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) {} - - func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) {} - - func register(feature: T) throws where T : DatadogInternal.DatadogFeature {} - - func get(feature type: T.Type) -> T? where T : DatadogInternal.DatadogFeature { - return nil + func scope(for featureType: T.Type) -> any DatadogInternal.FeatureScope where T : DatadogInternal.DatadogFeature { + return NOPFeatureScope() } - func scope(for feature: String) -> DatadogInternal.FeatureScope? { + func feature(named name: String, type: T.Type) -> T? { return nil } + + func register(feature: T) throws where T : DatadogInternal.DatadogFeature {} + func send(message: DatadogInternal.FeatureMessage, else fallback: @escaping () -> Void) {} + func set(baggage: @escaping () -> DatadogInternal.FeatureBaggage?, forKey key: String) {} } diff --git a/packages/react-native-session-replay/ios/Tests/RCTTextViewRecorderTests.swift b/packages/react-native-session-replay/ios/Tests/RCTTextViewRecorderTests.swift index 99720080f..a93c13fd9 100644 --- a/packages/react-native-session-replay/ios/Tests/RCTTextViewRecorderTests.swift +++ b/packages/react-native-session-replay/ios/Tests/RCTTextViewRecorderTests.swift @@ -27,11 +27,10 @@ internal class RCTTextViewRecorderTests: XCTestCase { ) let mockAllowContext = SessionReplayViewTreeRecordingContext( - recorder: .init(privacy: SessionReplayPrivacyLevel.allow, applicationID: "app_id", sessionID: "session_id", viewID: "view_id", viewServerTimeOffset: nil), + recorder: .init(privacy: .allow, applicationID: "app_id", sessionID: "session_id", viewID: "view_id", viewServerTimeOffset: nil), coordinateSpace: UIView(), ids: .init(), - imageDataProvider: ImageDataProvider() - ) + webViewCache: .init()) var mockShadowView: RCTTextShadowView { // The shadow view must be initialized with a bridge so that we can insert React Subviews into it. @@ -133,10 +132,10 @@ internal class RCTTextViewRecorderTests: XCTestCase { func testReturnsBuilderWithCorrectInformationWhenTextIsObfuscated() throws { let mockMaskContext = SessionReplayViewTreeRecordingContext( - recorder: .init(privacy: SessionReplayPrivacyLevel.mask, applicationID: "app_id", sessionID: "session_id", viewID: "view_id", viewServerTimeOffset: nil), + recorder: .init(privacy: .mask, applicationID: "app_id", sessionID: "session_id", viewID: "view_id", viewServerTimeOffset: nil), coordinateSpace: UIView(), ids: .init(), - imageDataProvider: ImageDataProvider() + webViewCache: .init() ) let reactTag = NSNumber(value: 44) let uiManagerMock = MockUIManager(reactTag: reactTag, shadowView: mockShadowView) From d0321e79adaa72f761b3ae0d99da791dd48a1e9f Mon Sep 17 00:00:00 2001 From: Marco Saia Date: Fri, 28 Jun 2024 10:35:05 +0200 Subject: [PATCH 3/3] Updated .vscode config --- .vscode/launch.json | 18 ++++++++++++++++++ .vscode/settings.json | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..94ba137e7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Jest: current file", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": [ + "${fileBasenameNoExtension}", + ], + "console": "integratedTerminal", + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 131d38e7f..a9d59e44a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -29,7 +29,7 @@ ], "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "typescript.tsdk": "node_modules/typescript/lib", } \ No newline at end of file