From d14835df833714ef59408778505096aba26734c1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Apr 2026 11:37:25 +0400 Subject: [PATCH] Updated on 2026-08-14 --- features/approval/impl/build.gradle.kts | 12 ++ .../approval/impl/model/GiveApprovalModel.kt | 9 +- .../impl/model/GiveApprovalModelTest.kt | 114 ++++++++++++++++++ 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 features/approval/impl/src/test/kotlin/com/tangem/features/approval/impl/model/GiveApprovalModelTest.kt diff --git a/features/approval/impl/build.gradle.kts b/features/approval/impl/build.gradle.kts index 2e43f87aee..1a43aaf4a5 100644 --- a/features/approval/impl/build.gradle.kts +++ b/features/approval/impl/build.gradle.kts @@ -10,6 +10,10 @@ android { namespace = "com.tangem.features.approval.impl" } +tasks.withType().configureEach { + useJUnitPlatform() +} + dependencies { /** Feature */ @@ -56,4 +60,12 @@ dependencies { /** DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) + + // region Tests + testImplementation(deps.test.coroutine) + testImplementation(deps.test.junit5) + testRuntimeOnly(deps.test.junit5.engine) + testImplementation(deps.test.mockk) + testImplementation(deps.test.truth) + // endregion } \ No newline at end of file diff --git a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt index 727c03292f..2161f8c8a1 100644 --- a/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt +++ b/features/approval/impl/src/main/java/com/tangem/features/approval/impl/model/GiveApprovalModel.kt @@ -37,6 +37,7 @@ import com.tangem.features.approval.api.GiveApprovalComponent import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback import com.tangem.features.send.v2.api.entity.FeeItem import com.tangem.features.send.v2.api.entity.FeeSelectorUM +import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger import com.tangem.utils.TangemBlogUrlBuilder.RESOURCE_TO_LEARN_ABOUT_APPROVING_IN_SWAP import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.logging.TangemLogger @@ -65,6 +66,7 @@ internal class GiveApprovalModel @Inject constructor( private val urlOpener: UrlOpener, private val getUserWalletUseCase: GetUserWalletUseCase, private val analyticsEventHandler: AnalyticsEventHandler, + private val feeSelectorReloadTrigger: FeeSelectorReloadTrigger, ) : Model(), FeeSelectorModelCallback { private val params: GiveApprovalComponent.Params = paramsContainer.require() @@ -115,7 +117,12 @@ internal class GiveApprovalModel @Inject constructor( } fun onChangeApproveType(approveType: ApproveType) { - uiState.update { it.copy(approveType = approveType) } + if (uiState.value.approveType == approveType) return + uiState.update { it.copy(approveType = approveType, isApproveButtonEnabled = false) } + modelScope.launch { + feeSelectorReloadTrigger.triggerLoadingState() + feeSelectorReloadTrigger.triggerUpdate() + } } fun onOpenLearnMoreAboutApproveClick() { diff --git a/features/approval/impl/src/test/kotlin/com/tangem/features/approval/impl/model/GiveApprovalModelTest.kt b/features/approval/impl/src/test/kotlin/com/tangem/features/approval/impl/model/GiveApprovalModelTest.kt new file mode 100644 index 0000000000..fc097acb8c --- /dev/null +++ b/features/approval/impl/src/test/kotlin/com/tangem/features/approval/impl/model/GiveApprovalModelTest.kt @@ -0,0 +1,114 @@ +package com.tangem.features.approval.impl.model + +import arrow.core.right +import com.google.common.truth.Truth.assertThat +import com.tangem.common.ui.bottomsheet.permission.state.ApproveType +import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.decompose.model.MutableParamsContainer +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.navigation.url.UrlOpener +import com.tangem.core.ui.extensions.TextReference +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase +import com.tangem.domain.transaction.usecase.GetAllowanceInfoUseCase +import com.tangem.domain.transaction.usecase.GetFeeUseCase +import com.tangem.domain.transaction.usecase.SendTransactionUseCase +import com.tangem.domain.transaction.usecase.gasless.CreateAndSendGaslessTransactionUseCase +import com.tangem.domain.transaction.usecase.gasless.GetFeeForGaslessUseCase +import com.tangem.domain.transaction.usecase.gasless.GetFeeForTokenUseCase +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase +import com.tangem.features.approval.api.GiveApprovalComponent +import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger +import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class GiveApprovalModelTest { + + private val createApprovalTransactionUseCase: CreateApprovalTransactionUseCase = mockk(relaxed = true) + private val getAllowanceInfoUseCase: GetAllowanceInfoUseCase = mockk(relaxed = true) + private val sendTransactionUseCase: SendTransactionUseCase = mockk(relaxed = true) + private val getFeeUseCase: GetFeeUseCase = mockk(relaxed = true) + private val getFeeForGaslessUseCase: GetFeeForGaslessUseCase = mockk(relaxed = true) + private val getFeeForTokenUseCase: GetFeeForTokenUseCase = mockk(relaxed = true) + private val createAndSendGaslessTransactionUseCase: CreateAndSendGaslessTransactionUseCase = mockk(relaxed = true) + private val uiMessageSender: UiMessageSender = mockk(relaxed = true) + private val urlOpener: UrlOpener = mockk(relaxed = true) + private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true) + private val feeSelectorReloadTrigger: FeeSelectorReloadTrigger = mockk(relaxed = true) + + private val userWalletId = UserWalletId(stringValue = "0123456789ABCDEF") + private val userWallet: UserWallet.Hot = mockk(relaxed = true) + + private val cryptoCurrencyStatus: CryptoCurrencyStatus = mockk { + every { currency } returns mockk(relaxed = true) + } + + private val params = GiveApprovalComponent.Params( + userWalletId = userWalletId, + cryptoCurrencyStatus = cryptoCurrencyStatus, + feeCryptoCurrencyStatus = cryptoCurrencyStatus, + amount = "10", + spenderAddress = "0xSpender", + amountFooter = TextReference.EMPTY, + feeFooter = TextReference.EMPTY, + callback = mockk(relaxed = true), + ) + + private val getUserWalletUseCase: GetUserWalletUseCase = mockk(relaxed = true) + + @BeforeEach + fun setUp() { + every { getUserWalletUseCase.invoke(userWalletId) } returns userWallet.right() + } + + private fun createModel(): GiveApprovalModel = GiveApprovalModel( + dispatchers = TestingCoroutineDispatcherProvider(), + paramsContainer = MutableParamsContainer(params), + createApprovalTransactionUseCase = createApprovalTransactionUseCase, + getAllowanceInfoUseCase = getAllowanceInfoUseCase, + sendTransactionUseCase = sendTransactionUseCase, + getFeeUseCase = getFeeUseCase, + getFeeForGaslessUseCase = getFeeForGaslessUseCase, + getFeeForTokenUseCase = getFeeForTokenUseCase, + createAndSendGaslessTransactionUseCase = createAndSendGaslessTransactionUseCase, + uiMessageSender = uiMessageSender, + urlOpener = urlOpener, + getUserWalletUseCase = getUserWalletUseCase, + analyticsEventHandler = analyticsEventHandler, + feeSelectorReloadTrigger = feeSelectorReloadTrigger, + ) + + @Test + fun `GIVEN approveType LIMITED WHEN onChangeApproveType THEN triggers fee reload and updates state`() = runTest { + val model = createModel() + + model.onChangeApproveType(ApproveType.UNLIMITED) + + val state = model.uiState.value + assertThat(state.approveType).isEqualTo(ApproveType.UNLIMITED) + assertThat(state.isApproveButtonEnabled).isFalse() + coVerify(exactly = 1) { feeSelectorReloadTrigger.triggerLoadingState() } + coVerify(exactly = 1) { feeSelectorReloadTrigger.triggerUpdate() } + } + + @Test + fun `GIVEN same approveType WHEN onChangeApproveType THEN does not trigger fee reload`() = runTest { + val model = createModel() + + model.onChangeApproveType(ApproveType.LIMITED) + + assertThat(model.uiState.value.approveType).isEqualTo(ApproveType.LIMITED) + coVerify(exactly = 0) { feeSelectorReloadTrigger.triggerLoadingState() } + coVerify(exactly = 0) { feeSelectorReloadTrigger.triggerUpdate() } + } +} \ No newline at end of file