diff --git a/packages/react-native-session-replay/android/build.gradle b/packages/react-native-session-replay/android/build.gradle index 14bc0dae7..97ba8d23b 100644 --- a/packages/react-native-session-replay/android/build.gradle +++ b/packages/react-native-session-replay/android/build.gradle @@ -167,6 +167,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.0.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/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt index 8dbd4d217..662af4315 100644 --- a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt @@ -6,21 +6,44 @@ package com.datadog.reactnative.sessionreplay +import com.datadog.android.sessionreplay.SessionReplayConfiguration +import com.datadog.android.sessionreplay.SessionReplayPrivacy import com.facebook.react.bridge.Promise +import java.util.Locale /** * The entry point to use Datadog's Session Replay feature. */ -class DdSessionReplayImplementation() { +class DdSessionReplayImplementation( + private val sessionReplayProvider: () -> SessionReplayWrapper = { + SessionReplaySDKWrapper() + } +) { /** * Enable session replay and start recording session. * @param replaySampleRate The sample rate applied for session replay. * @param defaultPrivacyLevel The privacy level used for replay. */ fun enable(replaySampleRate: Double, defaultPrivacyLevel: String, promise: Promise) { + val configuration = SessionReplayConfiguration.Builder(replaySampleRate.toFloat()) + .setPrivacy(buildPrivacy(defaultPrivacyLevel)) + .build() + sessionReplayProvider().enable(configuration) promise.resolve(null) } + private fun buildPrivacy(defaultPrivacyLevel: String): SessionReplayPrivacy { + return when (defaultPrivacyLevel?.lowercase(Locale.US)) { + "mask" -> SessionReplayPrivacy.MASK + "mask_user_input" -> SessionReplayPrivacy.MASK_USER_INPUT + "allow" -> SessionReplayPrivacy.ALLOW + else -> { + SessionReplayPrivacy.MASK + } + } + + } + companion object { internal const val NAME = "DdSessionReplay" } diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplaySDKWrapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplaySDKWrapper.kt new file mode 100644 index 000000000..7fa70e152 --- /dev/null +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplaySDKWrapper.kt @@ -0,0 +1,24 @@ +/* + * 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 + +import com.datadog.android.sessionreplay.SessionReplay +import com.datadog.android.sessionreplay.SessionReplayConfiguration + +internal class SessionReplaySDKWrapper : SessionReplayWrapper { + /** + * Enables a SessionReplay feature based on the configuration provided. + * @param sessionReplayConfiguration Configuration to use for the feature. + */ + override fun enable( + sessionReplayConfiguration: SessionReplayConfiguration, + ) { + SessionReplay.enable( + sessionReplayConfiguration, + ) + } +} diff --git a/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplayWrapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplayWrapper.kt new file mode 100644 index 000000000..2f395c637 --- /dev/null +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/SessionReplayWrapper.kt @@ -0,0 +1,22 @@ +/* + * 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 + +import com.datadog.android.sessionreplay.SessionReplayConfiguration + +/** + * Wrapper around [SessionReplay]. + */ +interface SessionReplayWrapper { + /** + * Enables a SessionReplay feature based on the configuration provided. + * @param sessionReplayConfiguration Configuration to use for the feature. + */ + fun enable( + sessionReplayConfiguration: SessionReplayConfiguration, + ) +} diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt index 57ccb69e2..f2b72dce6 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt @@ -6,7 +6,14 @@ package com.datadog.reactnative.sessionreplay +import com.datadog.android.sessionreplay.SessionReplayConfiguration +import com.datadog.android.sessionreplay.SessionReplayPrivacy +import com.datadog.tools.unit.GenericAssert.Companion.assertThat import com.facebook.react.bridge.Promise +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.inOrder +import fr.xgouchet.elmyr.Forge +import fr.xgouchet.elmyr.annotation.Forgery import fr.xgouchet.elmyr.junit5.ForgeExtension import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -30,9 +37,12 @@ internal class DdSessionReplayImplementationTest { @Mock lateinit var mockPromise: Promise + @Mock + lateinit var mockSessionReplay: SessionReplayWrapper + @BeforeEach fun `set up`() { - testedSessionReplay = DdSessionReplayImplementation() + testedSessionReplay = DdSessionReplayImplementation { mockSessionReplay } } @AfterEach @@ -40,8 +50,45 @@ internal class DdSessionReplayImplementationTest { } @Test - fun `M do nothing W enable()`() { + fun `M enable session replay W enable()`( + forge: Forge, + @Forgery privacy: SessionReplayPrivacy + ) { + // Given + val replaySampleRate = forge.aDouble(0.0, 100.0) + val sessionReplayConfigCaptor = argumentCaptor() + + // When + testedSessionReplay.enable(replaySampleRate, privacy.toString(), mockPromise) + + // Then + inOrder(mockSessionReplay) { + verify(mockSessionReplay).enable(sessionReplayConfigCaptor.capture()) + } + assertThat(sessionReplayConfigCaptor.firstValue) + .hasFieldEqualTo("sampleRate", replaySampleRate.toFloat()) + .hasFieldEqualTo("privacy", privacy) + } + + @Test + fun `M enable session replay with mask W enable with bad privacy option()`( + forge: Forge + ) { + // Given + // Not ALLOW nor MASK_USER_INPUT + val replaySampleRate = forge.aDouble(0.0, 100.0) + val privacy = forge.aStringMatching("^/(?!ALLOW|MASK_USER_INPUT)([a-z0-9]+)$/i") + val sessionReplayConfigCaptor = argumentCaptor() + // When - testedSessionReplay.enable(100.0, "MASK", mockPromise) + testedSessionReplay.enable(replaySampleRate, privacy, mockPromise) + + // Then + inOrder(mockSessionReplay) { + verify(mockSessionReplay).enable(sessionReplayConfigCaptor.capture()) + } + assertThat(sessionReplayConfigCaptor.firstValue) + .hasFieldEqualTo("sampleRate", replaySampleRate.toFloat()) + .hasFieldEqualTo("privacy", SessionReplayPrivacy.MASK) } }