Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-27 13:56:55 +03:00
parent 357bee1107
commit 112549a18a
2 changed files with 27 additions and 72 deletions

View file

@ -27,7 +27,6 @@ import com.tangem.features.tangempay.model.transformers.TangemPayOnboardingButto
import com.tangem.features.tangempay.ui.TangemPayOnboardingNavigation
import com.tangem.features.tangempay.ui.TangemPayOnboardingScreenState
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runSuspendCatching
import com.tangem.utils.logging.TangemLogger
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -68,7 +67,7 @@ internal class TangemPayOnboardingModel @Inject constructor(
when (params) {
is TangemPayOnboardingComponent.Params.Deeplink -> {
repository.validateDeeplink(params.deeplink)
.onRight { isValid -> if (isValid) checkEligibilityAndShow() else back() }
.onRight { isValid -> if (isValid) showOnboarding() else showNotAvailable() }
.onLeft { back() }
}
is TangemPayOnboardingComponent.Params.ContinueOnboarding -> {
@ -99,17 +98,6 @@ internal class TangemPayOnboardingModel @Inject constructor(
}
}
private suspend fun checkEligibilityAndShow() {
runSuspendCatching {
eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK)
}
.onSuccess { isAvailable -> if (isAvailable) showOnboarding() else showNotAvailable() }
.onFailure { error ->
TangemLogger.e(messageString = "TangemPayOnboarding: eligibility check failed", throwable = error)
back()
}
}
private fun showNotAvailable() {
uiState.update { state -> TangemPayOnboardingScreenState.NotAvailable(onBack = state.onBack) }
}

View file

@ -2,7 +2,6 @@
package com.tangem.features.tangempay.model
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.google.common.truth.Truth.assertThat
@ -16,7 +15,6 @@ import com.tangem.domain.models.kyc.KycStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.pay.TangemPayEligibilityManager
import com.tangem.domain.pay.model.CustomerInfo
import com.tangem.domain.pay.model.TangemPayEntryPoint
import com.tangem.domain.pay.repository.OnboardingRepository
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
import com.tangem.features.tangempay.TangemPayFeatureToggles
@ -37,8 +35,6 @@ import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import java.math.BigDecimal
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ -60,65 +56,57 @@ internal class TangemPayOnboardingModelTest {
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns false
}
@ParameterizedTest
@MethodSource("provideAvailabilityCases")
fun `GIVEN valid deeplink WHEN model created THEN state reflects tangem pay availability`(
case: AvailabilityCase,
) = runTest {
@Test
fun `GIVEN valid deeplink WHEN model created THEN onboarding shown AND availability not checked`() = runTest {
// Arrange
coEvery { repository.validateDeeplink(deeplink) } returns true.right()
coEvery { eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK) } returns case.isAvailable
// Act
val model = createModel(TangemPayOnboardingComponent.Params.Deeplink(deeplink))
advanceUntilIdle()
// Assert
assertThat(model.uiState.value).isInstanceOf(case.expectedState)
coVerify(exactly = 1) { eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK) }
model.onDestroy()
}
@ParameterizedTest
@MethodSource("provideRejectedDeeplinkCases")
fun `GIVEN deeplink rejected WHEN model created THEN screen closed AND availability not checked`(
validationResult: Either<UniversalError, Boolean>,
) = runTest {
// Arrange
coEvery { repository.validateDeeplink(deeplink) } returns validationResult
// Act
val model = createModel(TangemPayOnboardingComponent.Params.Deeplink(deeplink))
advanceUntilIdle()
// Assert
verify(exactly = 1) { router.pop() }
assertThat(model.uiState.value).isInstanceOf(TangemPayOnboardingScreenState.Content::class.java)
coVerify(exactly = 0) { eligibilityManager.getTangemPayAvailability(any()) }
model.onDestroy()
}
@Test
fun `GIVEN availability check fails WHEN model created THEN screen closed`() = runTest {
fun `GIVEN invalid deeplink WHEN model created THEN sorry screen shown AND screen not closed`() = runTest {
// Arrange
coEvery { repository.validateDeeplink(deeplink) } returns true.right()
coEvery { eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK) } throws
RuntimeException("network error")
coEvery { repository.validateDeeplink(deeplink) } returns false.right()
// Act
val model = createModel(TangemPayOnboardingComponent.Params.Deeplink(deeplink))
advanceUntilIdle()
// Assert
coVerify(exactly = 1) { eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK) }
verify(exactly = 1) { router.pop() }
assertThat(model.uiState.value).isInstanceOf(TangemPayOnboardingScreenState.NotAvailable::class.java)
verify(exactly = 0) { router.pop() }
coVerify(exactly = 0) { eligibilityManager.getTangemPayAvailability(any()) }
model.onDestroy()
}
@Test
fun `GIVEN unavailable shown WHEN got it clicked THEN screen closed`() = runTest {
fun `GIVEN deeplink validation error WHEN model created THEN screen closed AND availability not checked`() =
runTest {
// Arrange
coEvery { repository.validateDeeplink(deeplink) } returns DEEPLINK_ERROR.left()
// Act
val model = createModel(TangemPayOnboardingComponent.Params.Deeplink(deeplink))
advanceUntilIdle()
// Assert
verify(exactly = 1) { router.pop() }
coVerify(exactly = 0) { eligibilityManager.getTangemPayAvailability(any()) }
model.onDestroy()
}
@Test
fun `GIVEN sorry screen shown WHEN got it clicked THEN screen closed`() = runTest {
// Arrange
coEvery { repository.validateDeeplink(deeplink) } returns true.right()
coEvery { eligibilityManager.getTangemPayAvailability(TangemPayEntryPoint.DEEPLINK) } returns false
coEvery { repository.validateDeeplink(deeplink) } returns false.right()
val model = createModel(TangemPayOnboardingComponent.Params.Deeplink(deeplink))
advanceUntilIdle()
@ -251,27 +239,6 @@ internal class TangemPayOnboardingModelTest {
)
}
internal data class AvailabilityCase(
val isAvailable: Boolean,
val expectedState: Class<out TangemPayOnboardingScreenState>,
)
private fun provideAvailabilityCases() = listOf(
AvailabilityCase(
isAvailable = true,
expectedState = TangemPayOnboardingScreenState.Content::class.java,
),
AvailabilityCase(
isAvailable = false,
expectedState = TangemPayOnboardingScreenState.NotAvailable::class.java,
),
)
private fun provideRejectedDeeplinkCases(): List<Either<UniversalError, Boolean>> = listOf(
false.right(),
DEEPLINK_ERROR.left(),
)
private companion object {
val DEEPLINK_ERROR = object : UniversalError {
override val errorCode: Int = 0