Updated on 2026-08-14
This commit is contained in:
parent
e513b24234
commit
d4b9d7e9b8
2 changed files with 147 additions and 2 deletions
|
|
@ -10,6 +10,7 @@ import com.tangem.core.ui.extensions.themedColor
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.generated.icons.Icons
|
||||
import com.tangem.core.ui.res.generated.icons.ic_document_20
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
|
|
@ -59,9 +60,11 @@ internal class TangemPayDetailsStateFactory(
|
|||
}
|
||||
|
||||
fun getLoadedState(status: PaymentAccountStatusValue.Loaded): TangemPayDetailsUM {
|
||||
val isFresh = status.source == StatusSource.ACTUAL && status.error == null
|
||||
val hasUnfrozenCard = status.cards.any { it.frozenState == TangemPayCardFrozenState.Unfrozen }
|
||||
val hasIssuingCard = status.cards.any { it.state == TangemPayCardState.Issuing }
|
||||
val isAddCardEnabled = status.error == null && !hasIssuingCard
|
||||
val isAddCardEnabled = isFresh && !hasIssuingCard
|
||||
val areActionButtonsEnabled = isFresh && hasUnfrozenCard
|
||||
return TangemPayDetailsUM(
|
||||
topBarConfig = TangemPayDetailsTopBarConfig(
|
||||
onBackClick = onBack,
|
||||
|
|
@ -74,7 +77,7 @@ internal class TangemPayDetailsStateFactory(
|
|||
onRefresh = intents::onRefreshSwipe,
|
||||
),
|
||||
balanceBlockState = TangemPayDetailsBalanceBlockState.Loading(
|
||||
actionButtons = getActionButtonsConfig(isEnabled = status.error == null && hasUnfrozenCard),
|
||||
actionButtons = getActionButtonsConfig(isEnabled = areActionButtonsEnabled),
|
||||
cardsBlockState = TangemPayDetailsBalanceBlockState.CardsBlockState(
|
||||
cards = status.cards
|
||||
.let { if (isMultipleCardsEnabled) it else it.take(1) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
package com.tangem.features.tangempay.entity
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.features.tangempay.utils.TangemPayDetailIntents
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
|
||||
internal class TangemPayDetailsStateFactoryTest {
|
||||
|
||||
private val intents: TangemPayDetailIntents = mockk(relaxed = true)
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(intents)
|
||||
}
|
||||
|
||||
private val activeUnfrozenCard = TangemPayCard(
|
||||
id = "card_1",
|
||||
productInstanceId = "pi_card_1",
|
||||
cardStatus = TangemPayCard.Status.ACTIVE,
|
||||
hasPinCode = false,
|
||||
displayName = null,
|
||||
frozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
lastDigits = "1234",
|
||||
limit = null,
|
||||
state = TangemPayCardState.Active,
|
||||
)
|
||||
|
||||
private fun createFactory() = TangemPayDetailsStateFactory(
|
||||
onBack = {},
|
||||
onOpenMenu = {},
|
||||
intents = intents,
|
||||
isRedesignEnabled = true,
|
||||
isRemoveAccountEnabled = true,
|
||||
isMultipleCardsEnabled = true,
|
||||
)
|
||||
|
||||
private fun loadedStatus(
|
||||
statusSource: StatusSource,
|
||||
statusError: PaymentAccountStatusValue.Error?,
|
||||
statusCards: List<TangemPayCard> = listOf(activeUnfrozenCard),
|
||||
): PaymentAccountStatusValue.Loaded = mockk(relaxed = true) {
|
||||
every { source } returns statusSource
|
||||
every { error } returns statusError
|
||||
every { cards } returns statusCards
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideButtonStateCases")
|
||||
fun `GIVEN status source WHEN getLoadedState THEN buttons enabled only for actual data without error`(
|
||||
case: ButtonStateCase,
|
||||
) {
|
||||
// Arrange
|
||||
val factory = createFactory()
|
||||
val status = loadedStatus(statusSource = case.source, statusError = case.error)
|
||||
|
||||
// Act
|
||||
val state = factory.getLoadedState(status)
|
||||
|
||||
// Assert
|
||||
val actionButtonsEnabled = state.balanceBlockState.actionButtons.map { it.isEnabled }
|
||||
assertThat(actionButtonsEnabled).containsExactly(case.expectedEnabled, case.expectedEnabled)
|
||||
assertThat(state.balanceBlockState.cardsBlockState?.isAddCardEnabled).isEqualTo(case.expectedEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN actual status with only frozen card WHEN getLoadedState THEN action buttons disabled`() {
|
||||
// Arrange
|
||||
val factory = createFactory()
|
||||
val frozenCard = activeUnfrozenCard.copy(frozenState = TangemPayCardFrozenState.Frozen)
|
||||
val status = loadedStatus(
|
||||
statusSource = StatusSource.ACTUAL,
|
||||
statusError = null,
|
||||
statusCards = listOf(frozenCard),
|
||||
)
|
||||
|
||||
// Act
|
||||
val state = factory.getLoadedState(status)
|
||||
|
||||
// Assert
|
||||
assertThat(state.balanceBlockState.actionButtons.map { it.isEnabled }).containsExactly(false, false)
|
||||
assertThat(state.balanceBlockState.cardsBlockState?.isAddCardEnabled).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN actual status with issuing card WHEN getLoadedState THEN add card disabled`() {
|
||||
// Arrange
|
||||
val factory = createFactory()
|
||||
val issuingCard = activeUnfrozenCard.copy(state = TangemPayCardState.Issuing)
|
||||
val status = loadedStatus(
|
||||
statusSource = StatusSource.ACTUAL,
|
||||
statusError = null,
|
||||
statusCards = listOf(activeUnfrozenCard, issuingCard),
|
||||
)
|
||||
|
||||
// Act
|
||||
val state = factory.getLoadedState(status)
|
||||
|
||||
// Assert
|
||||
assertThat(state.balanceBlockState.cardsBlockState?.isAddCardEnabled).isFalse()
|
||||
}
|
||||
|
||||
internal data class ButtonStateCase(
|
||||
val source: StatusSource,
|
||||
val error: PaymentAccountStatusValue.Error?,
|
||||
val expectedEnabled: Boolean,
|
||||
)
|
||||
|
||||
private companion object {
|
||||
@JvmStatic
|
||||
fun provideButtonStateCases() = listOf(
|
||||
// Fresh data from the network -> actions allowed.
|
||||
ButtonStateCase(source = StatusSource.ACTUAL, error = null, expectedEnabled = true),
|
||||
// Cache restored from disk before a refresh confirms it -> actions blocked.
|
||||
ButtonStateCase(source = StatusSource.CACHE, error = null, expectedEnabled = false),
|
||||
// Internet unavailable, only cache left ([REDACTED_TASK_KEY] case 1) -> actions blocked.
|
||||
ButtonStateCase(source = StatusSource.ONLY_CACHE, error = null, expectedEnabled = false),
|
||||
// Expired refresh token, only cache left ([REDACTED_TASK_KEY] case 2) -> actions blocked.
|
||||
ButtonStateCase(
|
||||
source = StatusSource.ONLY_CACHE,
|
||||
error = PaymentAccountStatusValue.Error.NotSynced,
|
||||
expectedEnabled = false,
|
||||
),
|
||||
// Transient error overlaid on actual data -> actions blocked.
|
||||
ButtonStateCase(
|
||||
source = StatusSource.ACTUAL,
|
||||
error = PaymentAccountStatusValue.Error.Unavailable,
|
||||
expectedEnabled = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue