Updated on 2026-08-14
This commit is contained in:
parent
67577e8653
commit
b5209c613d
5 changed files with 108 additions and 21 deletions
|
|
@ -7,11 +7,14 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.yield.supply.models.YieldBoostPromo
|
||||
import com.tangem.domain.yield.supply.models.YieldBoostStatus
|
||||
import com.tangem.domain.yield.supply.promo.YieldPromoRepository
|
||||
import io.mockk.Deregisterable
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.mockk
|
||||
import io.mockk.registerInstanceFactory
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.Instant
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
|
@ -25,11 +28,23 @@ class IsYieldBoostPromoEnabledForTokenUseCaseTest {
|
|||
private val contractAddress = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
||||
private val networkRawId = "ethereum"
|
||||
|
||||
// Stub concrete instances of the sealed return types so MockK doesn't subclass them while recording coEvery
|
||||
// (Objenesis on a JVM-sealed type throws InstantiationError flakily under full-suite CI runs).
|
||||
private val instanceFactories = mutableListOf<Deregisterable>()
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
instanceFactories += registerInstanceFactory { YieldBoostPromo.None }
|
||||
instanceFactories += registerInstanceFactory { YieldBoostStatus.NotStarted }
|
||||
useCase = IsYieldBoostPromoEnabledForTokenUseCase(repository = repository)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
instanceFactories.forEach { it.deregister() }
|
||||
instanceFactories.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN currency is coin WHEN invoke THEN returns Right(false)`() = runTest {
|
||||
val coin = createCoin()
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.yield.supply.models.YieldBoostPromo
|
||||
import com.tangem.domain.yield.supply.models.YieldBoostStatus
|
||||
import com.tangem.domain.yield.supply.promo.YieldPromoRepository
|
||||
import io.mockk.Deregisterable
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.mockk
|
||||
import io.mockk.registerInstanceFactory
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.Instant
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
|
|
@ -23,11 +26,23 @@ class ShouldShowYieldBoostMainBannerUseCaseTest {
|
|||
private val contractAddress = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
||||
private val networkRawId = "ethereum"
|
||||
|
||||
// Stub concrete instances of the sealed return types so MockK doesn't subclass them while recording coEvery
|
||||
// (Objenesis on a JVM-sealed type throws InstantiationError flakily under full-suite CI runs).
|
||||
private val instanceFactories = mutableListOf<Deregisterable>()
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
instanceFactories += registerInstanceFactory { YieldBoostPromo.None }
|
||||
instanceFactories += registerInstanceFactory { YieldBoostStatus.NotStarted }
|
||||
useCase = ShouldShowYieldBoostMainBannerUseCase(repository = repository)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
instanceFactories.forEach { it.deregister() }
|
||||
instanceFactories.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN promo repository throws WHEN invoke THEN returns Left`() = runTest {
|
||||
coEvery { repository.getYieldBoostPromo(userWalletId, false) } throws RuntimeException("net")
|
||||
|
|
|
|||
|
|
@ -533,7 +533,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
network = cryptoCurrency.network,
|
||||
).getOrElse { false }
|
||||
|
||||
val isSupported = isXPUBSupported()
|
||||
val isSupported = isXpubSupported()
|
||||
val isDynamicAddressesAvailable = isSupported &&
|
||||
isDynamicAddressesAvailableUseCase(userWallet, cryptoCurrency)
|
||||
|
||||
|
|
@ -546,7 +546,7 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun isXPUBSupported(): Boolean {
|
||||
private suspend fun isXpubSupported(): Boolean {
|
||||
return isXpubSupportedUseCase(userWalletId = userWalletId, network = cryptoCurrency.network)
|
||||
}
|
||||
|
||||
|
|
@ -1437,15 +1437,17 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
network = cryptoCurrency.network,
|
||||
).getOrElse { false }
|
||||
|
||||
val isSupported = isXPUBSupported()
|
||||
val isXpubSupported = isXpubSupported()
|
||||
val isDynamicAddressesAvailable = isXpubSupported &&
|
||||
isDynamicAddressesAvailableUseCase(userWallet, cryptoCurrency)
|
||||
|
||||
redesignStateController.update(
|
||||
UpdateTopBarMenuTransformer(
|
||||
userWallet = userWallet,
|
||||
hasDerivations = hasDerivations,
|
||||
isXPubSupported = isSupported,
|
||||
onGenerateExtendedKey = ::onGenerateExtendedKey,
|
||||
onHideClick = ::onHideClick,
|
||||
isXpubSupported = isXpubSupported,
|
||||
isDynamicAddressesAvailable = isDynamicAddressesAvailable,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.ui.extensions.themedColor
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -15,9 +16,9 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
internal class UpdateTopBarMenuTransformer(
|
||||
private val userWallet: UserWallet,
|
||||
private val hasDerivations: Boolean,
|
||||
private val isXPubSupported: Boolean,
|
||||
private val onGenerateExtendedKey: () -> Unit,
|
||||
private val onHideClick: () -> Unit,
|
||||
private val isXpubSupported: Boolean,
|
||||
private val isDynamicAddressesAvailable: Boolean,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
) : Transformer<TokenDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TokenDetailsUM): TokenDetailsUM = prevState.copy(
|
||||
|
|
@ -30,12 +31,21 @@ internal class UpdateTopBarMenuTransformer(
|
|||
persistentListOf()
|
||||
} else {
|
||||
buildList {
|
||||
if (isXPubSupported && hasDerivations) {
|
||||
if (isDynamicAddressesAvailable) {
|
||||
add(
|
||||
TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.dynamic_addresses),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = clickIntents::onDynamicAddressesClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (isXpubSupported && hasDerivations) {
|
||||
add(
|
||||
TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.token_details_generate_xpub),
|
||||
textColor = themedColor { TangemTheme.colors.text.primary1 },
|
||||
onClick = onGenerateExtendedKey,
|
||||
onClick = clickIntents::onGenerateExtendedKey,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -43,7 +53,7 @@ internal class UpdateTopBarMenuTransformer(
|
|||
TangemDropdownMenuItem(
|
||||
title = resourceReference(R.string.token_details_hide_token),
|
||||
textColor = themedColor { TangemTheme.colors.text.warning },
|
||||
onClick = onHideClick,
|
||||
onClick = clickIntents::onHideClick,
|
||||
),
|
||||
)
|
||||
}.toImmutableList()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.domain.card.CardTypesResolver
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.AddFundsUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsBalanceBlockUM
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsTopAppBarUM
|
||||
|
|
@ -29,8 +30,7 @@ class UpdateTopBarMenuTransformerTest {
|
|||
private val coldWallet: UserWallet.Cold = mockk(relaxed = true)
|
||||
private val hotWallet: UserWallet.Hot = mockk(relaxed = true)
|
||||
private val cardTypesResolver: CardTypesResolver = mockk(relaxed = true)
|
||||
private val onGenerateExtendedKey: () -> Unit = mockk(relaxed = true)
|
||||
private val onHideClick: () -> Unit = mockk(relaxed = true)
|
||||
private val clickIntents: TokenDetailsClickIntents = mockk(relaxed = true)
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
|
|
@ -77,8 +77,8 @@ class UpdateTopBarMenuTransformerTest {
|
|||
assertThat(result.topAppBarUM.menuItems).hasSize(1)
|
||||
|
||||
result.topAppBarUM.menuItems.single().onClick()
|
||||
verify(exactly = 1) { onHideClick.invoke() }
|
||||
verify(exactly = 0) { onGenerateExtendedKey.invoke() }
|
||||
verify(exactly = 1) { clickIntents.onHideClick() }
|
||||
verify(exactly = 0) { clickIntents.onGenerateExtendedKey() }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -169,6 +169,48 @@ class UpdateTopBarMenuTransformerTest {
|
|||
assertThat(result.marketPriceBlockState).isSameInstanceAs(state.marketPriceBlockState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN dynamic addresses available WHEN transform THEN dynamic addresses item is shown first`() {
|
||||
// GIVEN
|
||||
every { cardTypesResolver.isSingleWalletWithToken() } returns false
|
||||
val transformer = createTransformer(
|
||||
userWallet = coldWallet,
|
||||
hasDerivations = false,
|
||||
isXPubSupported = false,
|
||||
isDynamicAddressesAvailable = true,
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = transformer.transform(initialState())
|
||||
|
||||
// THEN — Dynamic addresses item first, Hide token second
|
||||
assertThat(result.topAppBarUM.menuItems).hasSize(2)
|
||||
|
||||
result.topAppBarUM.menuItems.first().onClick()
|
||||
verify(exactly = 1) { clickIntents.onDynamicAddressesClick() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN dynamic addresses unavailable WHEN transform THEN dynamic addresses item is hidden`() {
|
||||
// GIVEN
|
||||
every { cardTypesResolver.isSingleWalletWithToken() } returns false
|
||||
val transformer = createTransformer(
|
||||
userWallet = coldWallet,
|
||||
hasDerivations = false,
|
||||
isXPubSupported = false,
|
||||
isDynamicAddressesAvailable = false,
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = transformer.transform(initialState())
|
||||
|
||||
// THEN — only Hide token
|
||||
assertThat(result.topAppBarUM.menuItems).hasSize(1)
|
||||
|
||||
result.topAppBarUM.menuItems.single().onClick()
|
||||
verify(exactly = 0) { clickIntents.onDynamicAddressesClick() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN callbacks WHEN menu items invoked THEN callbacks are dispatched`() {
|
||||
// GIVEN
|
||||
|
|
@ -177,6 +219,7 @@ class UpdateTopBarMenuTransformerTest {
|
|||
userWallet = coldWallet,
|
||||
hasDerivations = true,
|
||||
isXPubSupported = true,
|
||||
isDynamicAddressesAvailable = true,
|
||||
)
|
||||
|
||||
// WHEN
|
||||
|
|
@ -184,20 +227,22 @@ class UpdateTopBarMenuTransformerTest {
|
|||
result.topAppBarUM.menuItems.forEach { it.onClick() }
|
||||
|
||||
// THEN
|
||||
verify(exactly = 1) { onGenerateExtendedKey.invoke() }
|
||||
verify(exactly = 1) { onHideClick.invoke() }
|
||||
verify(exactly = 1) { clickIntents.onDynamicAddressesClick() }
|
||||
verify(exactly = 1) { clickIntents.onGenerateExtendedKey() }
|
||||
verify(exactly = 1) { clickIntents.onHideClick() }
|
||||
}
|
||||
|
||||
private fun createTransformer(
|
||||
userWallet: UserWallet,
|
||||
hasDerivations: Boolean,
|
||||
isXPubSupported: Boolean,
|
||||
isDynamicAddressesAvailable: Boolean = false,
|
||||
) = UpdateTopBarMenuTransformer(
|
||||
userWallet = userWallet,
|
||||
hasDerivations = hasDerivations,
|
||||
isXPubSupported = isXPubSupported,
|
||||
onGenerateExtendedKey = onGenerateExtendedKey,
|
||||
onHideClick = onHideClick,
|
||||
isXpubSupported = isXPubSupported,
|
||||
isDynamicAddressesAvailable = isDynamicAddressesAvailable,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
private fun initialState(): TokenDetailsUM = TokenDetailsUM(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue