Skip to content

Commit

Permalink
Enable session replay on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
louiszawadzki committed Oct 27, 2023
1 parent 5c58db4 commit 23e3209
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/react-native-session-replay/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
)
}
}
Original file line number Diff line number Diff line change
@@ -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,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,18 +37,58 @@ internal class DdSessionReplayImplementationTest {
@Mock
lateinit var mockPromise: Promise

@Mock
lateinit var mockSessionReplay: SessionReplayWrapper

@BeforeEach
fun `set up`() {
testedSessionReplay = DdSessionReplayImplementation()
testedSessionReplay = DdSessionReplayImplementation { mockSessionReplay }
}

@AfterEach
fun `tear down`() {
}

@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<SessionReplayConfiguration>()

// 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<SessionReplayConfiguration>()

// 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)
}
}

0 comments on commit 23e3209

Please sign in to comment.