From 4bcd6a2a8fd2d4c5c9862a74645f1d8388413e09 Mon Sep 17 00:00:00 2001 From: Jonathan Moskovich <48201295+jonathanmos@users.noreply.github.com> Date: Mon, 25 Dec 2023 11:10:51 +0200 Subject: [PATCH] Implement Android SR text masking --- ...eactNativeSessionReplayExtensionSupport.kt | 20 ++++-- .../mappers/ReactMaskInputTextMapper.kt | 55 ++++++++++++++ .../mappers/ReactMaskTextMapper.kt | 55 ++++++++++++++ .../sessionreplay/mappers/ReactTextMapper.kt | 38 +++------- .../sessionreplay/utils/TextViewUtils.kt | 40 +++++++++++ ...NativeSessionReplayExtensionSupportTest.kt | 36 ++++++++++ .../{ => utils}/ColorUtilsTest.kt | 3 +- .../{ => utils}/DrawableUtilsTest.kt | 3 +- .../TextViewUtilsTest.kt} | 72 ++++++------------- 9 files changed, 234 insertions(+), 88 deletions(-) create mode 100644 packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt create mode 100644 packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt create mode 100644 packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt rename packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/{ => utils}/ColorUtilsTest.kt (91%) rename packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/{ => utils}/DrawableUtilsTest.kt (96%) rename packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/{mappers/ReactTextMapperTest.kt => utils/TextViewUtilsTest.kt} (61%) 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 c415e9734..ad1dee845 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 @@ -13,6 +13,8 @@ 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.reactnative.sessionreplay.mappers.ReactTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper import com.facebook.react.bridge.ReactContext @@ -34,10 +36,20 @@ internal class ReactNativeSessionReplayExtensionSupport( ReactViewGroup::class.java to ReactViewGroupMapper(), ReactTextView::class.java to ReactTextMapper(reactContext, uiManagerModule), ReactEditText::class.java to ReactTextMapper(reactContext, uiManagerModule) - ).mapValues{ - it.value as WireframeMapper - } - ) + ), + 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> + } } override fun getOptionSelectorDetectors(): List { 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 new file mode 100644 index 000000000..63080b045 --- /dev/null +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskInputTextMapper.kt @@ -0,0 +1,55 @@ +/* + * 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 = + NoopTextPropertiesResolver(), + 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/ReactMaskTextMapper.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt new file mode 100644 index 000000000..e7aa2b2d5 --- /dev/null +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactMaskTextMapper.kt @@ -0,0 +1,55 @@ +/* + * 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.MaskTextViewMapper +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 ReactMaskTextMapper( + private val reactTextPropertiesResolver: TextPropertiesResolver = + NoopTextPropertiesResolver(), + private val textViewUtils: TextViewUtils = TextViewUtils() +): MaskTextViewMapper() { + + 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 6b5330912..4ff59505c 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,7 +7,6 @@ package com.datadog.reactnative.sessionreplay.mappers import android.widget.TextView -import androidx.annotation.VisibleForTesting import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback import com.datadog.android.sessionreplay.internal.recorder.MappingContext import com.datadog.android.sessionreplay.internal.recorder.mapper.TextViewMapper @@ -15,12 +14,14 @@ 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 ReactTextMapper( private val reactTextPropertiesResolver: TextPropertiesResolver = - NoopTextPropertiesResolver() + NoopTextPropertiesResolver(), + private val textViewUtils: TextViewUtils = TextViewUtils() ): TextViewMapper() { internal constructor( @@ -42,31 +43,12 @@ internal class ReactTextMapper( mappingContext: MappingContext, asyncJobStatusCallback: AsyncJobStatusCallback ): List { - val result = mutableListOf() - val wireframes = mapOnSuperclass(view, mappingContext, asyncJobStatusCallback) - val pixelDensity = mappingContext.systemInformation.screenDensity - - wireframes.forEach { originalWireframe -> - if (originalWireframe !is MobileSegment.Wireframe.TextWireframe) { - result.add(originalWireframe) - } else { - result.add(reactTextPropertiesResolver.addReactNativeProperties( - originalWireframe = originalWireframe, - view = view, - pixelDensity = pixelDensity, - )) - } - } - - return result - } - - @VisibleForTesting - internal fun mapOnSuperclass( - textView: TextView, - mappingContext: MappingContext, - asyncJobStatusCallback: AsyncJobStatusCallback - ): List { - return super.map(textView, mappingContext, asyncJobStatusCallback) + 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/utils/TextViewUtils.kt b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt new file mode 100644 index 000000000..021990d07 --- /dev/null +++ b/packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt @@ -0,0 +1,40 @@ +/* + * + * * 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.utils + +import android.widget.TextView +import com.datadog.android.sessionreplay.internal.recorder.MappingContext +import com.datadog.android.sessionreplay.model.MobileSegment +import com.datadog.reactnative.sessionreplay.TextPropertiesResolver + +internal class TextViewUtils { + internal fun mapTextViewToWireframes( + wireframes: List, + view: TextView, + mappingContext: MappingContext, + reactTextPropertiesResolver: TextPropertiesResolver + ): List { + val result = mutableListOf() + val pixelDensity = mappingContext.systemInformation.screenDensity + + wireframes.forEach { originalWireframe -> + if (originalWireframe !is MobileSegment.Wireframe.TextWireframe) { + result.add(originalWireframe) + } else { + result.add(reactTextPropertiesResolver.addReactNativeProperties( + originalWireframe = originalWireframe, + view = view, + pixelDensity = pixelDensity, + )) + } + } + + return result + } +} 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 93c931c03..d393d30da 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 @@ -8,6 +8,8 @@ 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.ReactTextMapper import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper import com.facebook.react.bridge.NativeModule @@ -76,6 +78,40 @@ internal class ReactNativeSessionReplayExtensionSupportTest { .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] + + // Then + check(maskUserInputMappers != null) + assertThat(maskUserInputMappers).hasSize(3) + assertThat(maskUserInputMappers[ReactViewGroup::class.java]) + .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] + + // 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) + } + @Test fun `M return null W getUiManagerModule() { cannot get uiManagerModule }`() { // Given diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ColorUtilsTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/ColorUtilsTest.kt similarity index 91% rename from packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ColorUtilsTest.kt rename to packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/ColorUtilsTest.kt index fc8ae3ac8..6580cf61c 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ColorUtilsTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/ColorUtilsTest.kt @@ -4,9 +4,8 @@ * Copyright 2016-Present Datadog, Inc. */ -package com.datadog.reactnative.sessionreplay +package com.datadog.reactnative.sessionreplay.utils -import com.datadog.reactnative.sessionreplay.utils.formatAsRgba import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DrawableUtilsTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtilsTest.kt similarity index 96% rename from packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DrawableUtilsTest.kt rename to packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtilsTest.kt index 5e2668bc2..f71c351d7 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DrawableUtilsTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/DrawableUtilsTest.kt @@ -4,12 +4,11 @@ * Copyright 2016-Present Datadog, Inc. */ -package com.datadog.reactnative.sessionreplay +package com.datadog.reactnative.sessionreplay.utils import android.graphics.drawable.ColorDrawable import android.graphics.drawable.InsetDrawable import android.graphics.drawable.LayerDrawable -import com.datadog.reactnative.sessionreplay.utils.DrawableUtils import com.facebook.react.views.view.ReactViewBackgroundDrawable import fr.xgouchet.elmyr.junit5.ForgeExtension import org.assertj.core.api.Assertions.assertThat diff --git a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapperTest.kt b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt similarity index 61% rename from packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapperTest.kt rename to packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt index 29ff84190..ea758d3c4 100644 --- a/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapperTest.kt +++ b/packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt @@ -4,13 +4,12 @@ * Copyright 2016-Present Datadog, Inc. */ -package com.datadog.reactnative.sessionreplay.mappers +package com.datadog.reactnative.sessionreplay.utils import android.content.res.Resources import android.graphics.Typeface import android.util.DisplayMetrics 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.SystemInformation import com.datadog.android.sessionreplay.model.MobileSegment @@ -23,10 +22,10 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.Extensions import org.mockito.Mock +import org.mockito.Mockito.spy import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoSettings import org.mockito.kotlin.eq -import org.mockito.kotlin.spy import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @@ -35,8 +34,8 @@ import org.mockito.quality.Strictness ExtendWith(ForgeExtension::class) ) @MockitoSettings(strictness = Strictness.LENIENT) -internal class ReactTextMapperTest { - private lateinit var testedMapper: ReactTextMapper +internal class TextViewUtilsTest { + private lateinit var testedUtils: TextViewUtils @Mock private lateinit var mockReactTextPropertiesResolver: ReactTextPropertiesResolver @@ -44,9 +43,6 @@ internal class ReactTextMapperTest { @Mock private lateinit var mockMappingContext: MappingContext - @Mock - private lateinit var mockAsyncJobStatusCallback: AsyncJobStatusCallback - @Mock private lateinit var mockTextView: TextView @@ -59,9 +55,6 @@ internal class ReactTextMapperTest { @Mock private lateinit var mockDisplayMetrics: DisplayMetrics - @Mock - private lateinit var mockTextWireframe: MobileSegment.Wireframe.TextWireframe - @BeforeEach fun `set up`(forge: Forge) { whenever(mockResources.displayMetrics).thenReturn(mockDisplayMetrics) @@ -71,56 +64,30 @@ internal class ReactTextMapperTest { whenever(mockTextView.text).thenReturn(forge.aString()) whenever(mockTextView.typeface).thenReturn(Typeface.SANS_SERIF) - whenever( - mockReactTextPropertiesResolver.addReactNativeProperties( - originalWireframe = eq(mockTextWireframe), - view = eq(mockTextView), - pixelDensity = eq(0f) - ) - ).thenReturn(mockTextWireframe) - - testedMapper = spy( - ReactTextMapper( - reactTextPropertiesResolver = mockReactTextPropertiesResolver - ) - ) + testedUtils = spy(TextViewUtils()) } @Test fun `M return wireframe W map() { even if not TextWireframeType }`( @Mock mockImageWireframe: MobileSegment.Wireframe.ImageWireframe ) { - // Given - whenever( - testedMapper.mapOnSuperclass( - textView = eq(mockTextView), - mappingContext = eq(mockMappingContext), - asyncJobStatusCallback = eq(mockAsyncJobStatusCallback) - ) - ).thenReturn( - listOf(mockImageWireframe) - ) - // When - val result = testedMapper.map(mockTextView, mockMappingContext, mockAsyncJobStatusCallback) + val result = testedUtils.mapTextViewToWireframes( + wireframes = listOf(mockImageWireframe), + view = mockTextView, + mappingContext = mockMappingContext, + reactTextPropertiesResolver = mockReactTextPropertiesResolver + ) // Then assertThat(result).contains(mockImageWireframe) } @Test - fun `M return textWireframe W map()`() { + fun `M return textWireframe W map()`( + @Mock mockTextWireframe: MobileSegment.Wireframe.TextWireframe + ) { // Given - whenever( - testedMapper.mapOnSuperclass( - textView = eq(mockTextView), - mappingContext = eq(mockMappingContext), - asyncJobStatusCallback = eq(mockAsyncJobStatusCallback) - ) - ).thenReturn( - listOf(mockTextWireframe) - ) - whenever( mockReactTextPropertiesResolver.addReactNativeProperties( originalWireframe = eq(mockTextWireframe), @@ -130,13 +97,14 @@ internal class ReactTextMapperTest { ).thenReturn(mockTextWireframe) // When - val result = testedMapper.map( - mockTextView, - mockMappingContext, - mockAsyncJobStatusCallback + val result = testedUtils.mapTextViewToWireframes( + wireframes = listOf(mockTextWireframe), + view = mockTextView, + mappingContext = mockMappingContext, + reactTextPropertiesResolver = mockReactTextPropertiesResolver )[0] as MobileSegment.Wireframe.TextWireframe // Then - assertThat(result.text).isEqualTo(mockTextWireframe.text) + assertThat(result).isEqualTo(mockTextWireframe) } }