Updated on 2026-08-14
This commit is contained in:
commit
592bc82e98
3 changed files with 175 additions and 1 deletions
|
|
@ -122,6 +122,7 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
|
||||||
// [REDACTED_JIRA]
|
// [REDACTED_JIRA]
|
||||||
Blockchain.Dischain,
|
Blockchain.Dischain,
|
||||||
Blockchain.Polygon,
|
Blockchain.Polygon,
|
||||||
|
Blockchain.TON,
|
||||||
-> this.currency
|
-> this.currency
|
||||||
else -> responseToken.symbol
|
else -> responseToken.symbol
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,13 @@ internal class YieldSupplyActiveModel @Inject constructor(
|
||||||
if (!yieldSupplyFeatureToggles.isYieldPromoEnabled) return
|
if (!yieldSupplyFeatureToggles.isYieldPromoEnabled) return
|
||||||
if (designFeatureToggles.isRedesignEnabled) return
|
if (designFeatureToggles.isRedesignEnabled) return
|
||||||
modelScope.launch(dispatchers.io) {
|
modelScope.launch(dispatchers.io) {
|
||||||
val status = getYieldBoostStatusUseCase(userWalletId).getOrNull() ?: return@launch
|
|
||||||
val token = cryptoCurrency as? CryptoCurrency.Token ?: return@launch
|
val token = cryptoCurrency as? CryptoCurrency.Token ?: return@launch
|
||||||
|
val cached = getYieldBoostStatusUseCase(userWalletId).getOrNull()
|
||||||
|
val status = if (cached is YieldBoostStatus.Enrolled && cached.matches(token)) {
|
||||||
|
cached
|
||||||
|
} else {
|
||||||
|
getYieldBoostStatusUseCase(userWalletId, forceRefresh = true).getOrNull()
|
||||||
|
}
|
||||||
if (status !is YieldBoostStatus.Enrolled || !status.matches(token)) return@launch
|
if (status !is YieldBoostStatus.Enrolled || !status.matches(token)) return@launch
|
||||||
|
|
||||||
val state = resolveBoostBlockState(
|
val state = resolveBoostBlockState(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
package com.tangem.features.yield.supply.impl.active.model
|
||||||
|
|
||||||
|
import arrow.core.right
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||||
|
import com.tangem.core.decompose.model.MutableParamsContainer
|
||||||
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
|
import com.tangem.core.ui.DesignFeatureToggles
|
||||||
|
import com.tangem.common.routing.AppRouter
|
||||||
|
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||||
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
import com.tangem.domain.yield.supply.models.YieldBoostStatus
|
||||||
|
import com.tangem.domain.yield.supply.promo.usecase.GetYieldBoostStatusUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetCurrentFeeUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetDustMinAmountUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetMaxFeeUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetProtocolBalanceUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase
|
||||||
|
import com.tangem.domain.yield.supply.usecase.YieldSupplyMinAmountUseCase
|
||||||
|
import com.tangem.features.yield.supply.api.YieldSupplyActiveComponent
|
||||||
|
import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles
|
||||||
|
import com.tangem.features.yield.supply.impl.YieldBoostStoryPreloader
|
||||||
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.datetime.Clock
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import kotlin.time.Duration.Companion.days
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class YieldSupplyActiveModelBoostBlockTest {
|
||||||
|
|
||||||
|
private val yieldSupplyGetProtocolBalanceUseCase: YieldSupplyGetProtocolBalanceUseCase = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyGetCurrentFeeUseCase: YieldSupplyGetCurrentFeeUseCase = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyGetMaxFeeUseCase: YieldSupplyGetMaxFeeUseCase = mockk(relaxed = true)
|
||||||
|
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase = mockk(relaxed = true)
|
||||||
|
private val getUserWalletUseCase: GetUserWalletUseCase = mockk(relaxed = true)
|
||||||
|
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier = mockk(relaxed = true)
|
||||||
|
private val urlOpener: UrlOpener = mockk(relaxed = true)
|
||||||
|
private val appRouter: AppRouter = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyGetDustMinAmountUseCase: YieldSupplyGetDustMinAmountUseCase = mockk(relaxed = true)
|
||||||
|
private val getYieldBoostStatusUseCase: GetYieldBoostStatusUseCase = mockk(relaxed = true)
|
||||||
|
private val yieldSupplyFeatureToggles: YieldSupplyFeatureToggles = mockk(relaxed = true)
|
||||||
|
private val designFeatureToggles: DesignFeatureToggles = mockk(relaxed = true)
|
||||||
|
private val boostStoryPreloader: YieldBoostStoryPreloader = mockk(relaxed = true)
|
||||||
|
private val analyticsHandler: AnalyticsEventHandler = mockk(relaxed = true)
|
||||||
|
|
||||||
|
private val userWalletId = UserWalletId(stringValue = "0123456789ABCDEF")
|
||||||
|
private val userWallet: UserWallet.Hot = mockk(relaxed = true)
|
||||||
|
|
||||||
|
private val network: Network = mockk(relaxed = true) {
|
||||||
|
every { rawId } returns NETWORK_ID
|
||||||
|
every { name } returns "Ethereum"
|
||||||
|
}
|
||||||
|
private val token: CryptoCurrency.Token = mockk(relaxed = true) {
|
||||||
|
every { contractAddress } returns CONTRACT_ADDRESS
|
||||||
|
every { network } returns this@YieldSupplyActiveModelBoostBlockTest.network
|
||||||
|
every { symbol } returns "USDT"
|
||||||
|
every { decimals } returns 6
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enrolledStatus = YieldBoostStatus.Enrolled(
|
||||||
|
tokenName = "USDT",
|
||||||
|
networkId = NETWORK_ID,
|
||||||
|
moduleAddress = "0xModule",
|
||||||
|
userAddress = "0xUser",
|
||||||
|
contractAddress = CONTRACT_ADDRESS,
|
||||||
|
qualificationEndDate = Clock.System.now() + 100.days,
|
||||||
|
)
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setUp() {
|
||||||
|
every { yieldSupplyFeatureToggles.isYieldPromoEnabled } returns true
|
||||||
|
every { designFeatureToggles.isRedesignEnabled } returns false
|
||||||
|
every { getUserWalletUseCase.invoke(userWalletId) } returns userWallet.right()
|
||||||
|
every { singleAccountStatusListSupplier.invoke(userWalletId) } returns emptyFlow()
|
||||||
|
coEvery { getSelectedAppCurrencyUseCase.invokeSync() } returns AppCurrency.Default.right()
|
||||||
|
coEvery { yieldSupplyGetProtocolBalanceUseCase(any(), any()) } returns BigDecimal.ONE.right()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createModel(): YieldSupplyActiveModel = YieldSupplyActiveModel(
|
||||||
|
paramsContainer = MutableParamsContainer(
|
||||||
|
YieldSupplyActiveComponent.Params(userWalletId = userWalletId, cryptoCurrency = token),
|
||||||
|
),
|
||||||
|
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||||
|
analyticsHandler = analyticsHandler,
|
||||||
|
yieldSupplyGetProtocolBalanceUseCase = yieldSupplyGetProtocolBalanceUseCase,
|
||||||
|
yieldSupplyGetTokenStatusUseCase = yieldSupplyGetTokenStatusUseCase,
|
||||||
|
yieldSupplyMinAmountUseCase = yieldSupplyMinAmountUseCase,
|
||||||
|
yieldSupplyGetCurrentFeeUseCase = yieldSupplyGetCurrentFeeUseCase,
|
||||||
|
yieldSupplyGetMaxFeeUseCase = yieldSupplyGetMaxFeeUseCase,
|
||||||
|
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||||
|
getUserWalletUseCase = getUserWalletUseCase,
|
||||||
|
singleAccountStatusListSupplier = singleAccountStatusListSupplier,
|
||||||
|
urlOpener = urlOpener,
|
||||||
|
appRouter = appRouter,
|
||||||
|
yieldSupplyGetDustMinAmountUseCase = yieldSupplyGetDustMinAmountUseCase,
|
||||||
|
getYieldBoostStatusUseCase = getYieldBoostStatusUseCase,
|
||||||
|
yieldSupplyFeatureToggles = yieldSupplyFeatureToggles,
|
||||||
|
designFeatureToggles = designFeatureToggles,
|
||||||
|
boostStoryPreloader = boostStoryPreloader,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN cached status NotStarted WHEN model created THEN force refreshes and shows boost text`() = runTest {
|
||||||
|
coEvery { getYieldBoostStatusUseCase(userWalletId, false) } returns YieldBoostStatus.NotStarted.right()
|
||||||
|
coEvery { getYieldBoostStatusUseCase(userWalletId, true) } returns enrolledStatus.right()
|
||||||
|
|
||||||
|
val model = createModel()
|
||||||
|
|
||||||
|
assertThat(model.uiState.value.boostText).isNotNull()
|
||||||
|
coVerify(exactly = 1) { getYieldBoostStatusUseCase(userWalletId, false) }
|
||||||
|
coVerify(exactly = 1) { getYieldBoostStatusUseCase(userWalletId, true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN cached status already Enrolled WHEN model created THEN does not force refresh`() = runTest {
|
||||||
|
coEvery { getYieldBoostStatusUseCase(userWalletId, false) } returns enrolledStatus.right()
|
||||||
|
|
||||||
|
val model = createModel()
|
||||||
|
|
||||||
|
assertThat(model.uiState.value.boostText).isNotNull()
|
||||||
|
coVerify(exactly = 1) { getYieldBoostStatusUseCase(userWalletId, false) }
|
||||||
|
coVerify(exactly = 0) { getYieldBoostStatusUseCase(userWalletId, true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN status NotStarted even after refresh WHEN model created THEN shows no boost text`() = runTest {
|
||||||
|
coEvery { getYieldBoostStatusUseCase(userWalletId, false) } returns YieldBoostStatus.NotStarted.right()
|
||||||
|
coEvery { getYieldBoostStatusUseCase(userWalletId, true) } returns YieldBoostStatus.NotStarted.right()
|
||||||
|
|
||||||
|
val model = createModel()
|
||||||
|
|
||||||
|
assertThat(model.uiState.value.boostText).isNull()
|
||||||
|
coVerify(exactly = 1) { getYieldBoostStatusUseCase(userWalletId, false) }
|
||||||
|
coVerify(exactly = 1) { getYieldBoostStatusUseCase(userWalletId, true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN promo toggle disabled WHEN model created THEN does not query boost status`() = runTest {
|
||||||
|
every { yieldSupplyFeatureToggles.isYieldPromoEnabled } returns false
|
||||||
|
|
||||||
|
val model = createModel()
|
||||||
|
|
||||||
|
assertThat(model.uiState.value.boostText).isNull()
|
||||||
|
coVerify(exactly = 0) { getYieldBoostStatusUseCase(any(), any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val CONTRACT_ADDRESS = "0xCONTRACT"
|
||||||
|
const val NETWORK_ID = "ethereum"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue