Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-07 20:49:21 +03:00
parent 2eee398c36
commit 8c93c3b23c
7 changed files with 419 additions and 43 deletions

View file

@ -1905,6 +1905,7 @@
<string name="tangempay_change_pin_code">Change PIN-code</string>
<string name="tangempay_come_back_if_forget_pin">Come back to the app if you forget it.</string>
<string name="tangempay_common_card">Card</string>
<string name="tangempay_common_error_loading">Error loading</string>
<string name="tangempay_current_plan_change">Change plan</string>
<string name="tangempay_current_plan_section_card">Card related</string>
<string name="tangempay_current_plan_section_plan">Plan related</string>

View file

@ -44,7 +44,7 @@ internal data class TangemPayTxHistoryDetailsUMV2(
val subtitle: TextReference,
val iconState: TangemIconUM,
val transactionTitle: TextReference,
val card: TextReference?,
val detail: TransactionDetailUM?,
val transactionCategory: TextReference,
val mcc: TextReference?,
val transactionAmount: String,
@ -68,6 +68,15 @@ internal enum class TransactionStateType {
Reversed,
}
@Immutable
internal sealed interface TransactionDetailUM {
data object Loading : TransactionDetailUM
data class Content(val card: TextReference) : TransactionDetailUM
data class Error(val onRefreshClick: () -> Unit) : TransactionDetailUM
}
internal enum class TransactionLoadState { Loading, Loaded, Error }
@Immutable
internal sealed interface TangemPayTxHistoryDetailsUiState {
data class Legacy(val state: TangemPayTxHistoryDetailsUM) : TangemPayTxHistoryDetailsUiState

View file

@ -17,9 +17,11 @@ import com.tangem.domain.tangempay.repository.TangemPayTxHistoryRepository
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import com.tangem.features.tangempay.components.TangemPayTransactionBottomSheetComponent
import com.tangem.features.tangempay.entity.TangemPayTxHistoryDetailsUiStates
import com.tangem.features.tangempay.entity.TransactionLoadState
import com.tangem.features.tangempay.model.transformers.TangemPayTxHistoryDetailsConverter
import com.tangem.features.tangempay.model.transformers.TangemPayTxHistoryDetailsConverterV2
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -41,16 +43,23 @@ internal class TangemPayTxHistoryDetailsModel @Inject constructor(
private val params = paramsContainer.require<TangemPayTransactionBottomSheetComponent.Params>()
private val transaction = MutableStateFlow(params.transaction)
private val transactionLoadState = MutableStateFlow(TransactionLoadState.Loading)
private var loadTransactionJob: Job? = null
val uiState: StateFlow<TangemPayTxHistoryDetailsUiStates> = combine(
balanceHidingSettings.isBalanceHidden(),
transaction,
) { isBalanceHidden, transaction ->
buildUiStates(isBalanceHidden, transaction)
transactionLoadState,
) { isBalanceHidden, transaction, transactionLoadState ->
buildUiStates(isBalanceHidden, transaction, transactionLoadState)
}.stateIn(
scope = modelScope,
started = SharingStarted.Eagerly,
initialValue = buildUiStates(isBalanceHidden = params.isBalanceHidden, transaction = params.transaction),
initialValue = buildUiStates(
isBalanceHidden = params.isBalanceHidden,
transaction = params.transaction,
transactionLoadState = transactionLoadState.value,
),
)
init {
@ -64,17 +73,25 @@ internal class TangemPayTxHistoryDetailsModel @Inject constructor(
private fun loadTransaction() {
val current = params.transaction
if (current !is TangemPayTxHistoryItem.Spend) return
modelScope.launch {
if (loadTransactionJob?.isActive == true) return
loadTransactionJob = modelScope.launch {
transactionLoadState.value = TransactionLoadState.Loading
tangemPayTxHistoryRepository.getTransaction(
userWalletId = params.userWalletId,
transactionId = current.id,
).onRight { loaded -> if (loaded != null) transaction.value = loaded }
).onRight { loaded ->
if (loaded != null) transaction.value = loaded
transactionLoadState.value = TransactionLoadState.Loaded
}.onLeft {
transactionLoadState.value = TransactionLoadState.Error
}
}
}
private fun buildUiStates(
isBalanceHidden: Boolean,
transaction: TangemPayTxHistoryItem,
transactionLoadState: TransactionLoadState,
): TangemPayTxHistoryDetailsUiStates {
val converterInput = TangemPayTxHistoryDetailsConverter.Input(
item = transaction,
@ -89,8 +106,10 @@ internal class TangemPayTxHistoryDetailsModel @Inject constructor(
value = TangemPayTxHistoryDetailsConverterV2.Input(
item = converterInput.item,
isBalanceHidden = converterInput.isBalanceHidden,
transactionLoadState = transactionLoadState,
onExplorerClick = converterInput.onExplorerClick,
onDisputeClick = converterInput.onDisputeClick,
onCardRefreshClick = ::loadTransaction,
onDismiss = converterInput.onDismiss,
),
),

View file

@ -15,7 +15,9 @@ import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.ButtonState
import com.tangem.features.tangempay.entity.TangemPayTxHistoryDetailsUMV2
import com.tangem.features.tangempay.entity.TransactionDetailUM
import com.tangem.features.tangempay.entity.TransactionLabelUM
import com.tangem.features.tangempay.entity.TransactionLoadState
import com.tangem.features.tangempay.entity.TransactionStateType
import com.tangem.utils.StringsSigns
import com.tangem.utils.converter.Converter
@ -34,7 +36,7 @@ internal object TangemPayTxHistoryDetailsConverterV2 :
subtitle = transaction.extractDate(),
iconState = transaction.extractIcon(),
transactionTitle = transaction.extractTransactionTitle(),
card = transaction.extractCard(),
detail = value.extractDetail(),
transactionCategory = transaction.extractTransactionCategory(),
mcc = transaction.extractMcc(),
transactionAmount = transaction.extractAmount(),
@ -290,8 +292,16 @@ internal object TangemPayTxHistoryDetailsConverterV2 :
}
}
private fun TangemPayTxHistoryItem.extractCard(): TextReference? {
if (this !is TangemPayTxHistoryItem.Spend) return null
private fun Input.extractDetail(): TransactionDetailUM? {
val spend = item as? TangemPayTxHistoryItem.Spend ?: return null
return when (transactionLoadState) {
TransactionLoadState.Loading -> TransactionDetailUM.Loading
TransactionLoadState.Error -> TransactionDetailUM.Error(onRefreshClick = onCardRefreshClick)
TransactionLoadState.Loaded -> spend.extractCardValue()?.let(TransactionDetailUM::Content)
}
}
private fun TangemPayTxHistoryItem.Spend.extractCardValue(): TextReference? {
val name = cardName?.takeIf { it.isNotEmpty() }
val last4 = cardNumberLast4?.takeIf { it.isNotEmpty() }
return when {
@ -312,8 +322,10 @@ internal object TangemPayTxHistoryDetailsConverterV2 :
data class Input(
val item: TangemPayTxHistoryItem,
val isBalanceHidden: Boolean,
val transactionLoadState: TransactionLoadState,
val onExplorerClick: (String?) -> Unit,
val onDisputeClick: () -> Unit,
val onCardRefreshClick: () -> Unit,
val onDismiss: () -> Unit,
)
}

View file

@ -2,12 +2,14 @@ package com.tangem.features.tangempay.ui
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.TextAutoSize
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -30,23 +32,16 @@ import com.tangem.core.ui.ds.image.TangemIconUM
import com.tangem.core.ui.ds.topbar.TangemTopBar
import com.tangem.core.ui.ds.topbar.TangemTopBarType
import com.tangem.core.ui.ds2.button.TangemButton
import com.tangem.core.ui.ds2.row.TangemRow
import com.tangem.core.ui.ds2.row.TangemRowContentLead
import com.tangem.core.ui.ds2.row.TangemRowText
import com.tangem.core.ui.ds2.row.TangemRowTextRole
import com.tangem.core.ui.extensions.orMaskWithStars
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.ds2.row.*
import com.tangem.core.ui.ds2.shimmers.TangemShimmer
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreviewRedesign
import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_arrow_down_24
import com.tangem.core.ui.res.generated.icons.ic_arrow_refresh_20
import com.tangem.features.tangempay.details.impl.R
import com.tangem.features.tangempay.entity.ButtonState
import com.tangem.features.tangempay.entity.TangemPayTxHistoryDetailsUMV2
import com.tangem.features.tangempay.entity.TransactionLabelUM
import com.tangem.features.tangempay.entity.TransactionStateType
import com.tangem.features.tangempay.entity.*
@Suppress("LongMethod")
@Composable
@ -233,23 +228,11 @@ internal fun TransactionLabel(label: TransactionLabelUM, modifier: Modifier = Mo
@Composable
private fun TransactionDetailsBlock(state: TangemPayTxHistoryDetailsUMV2, modifier: Modifier = Modifier) {
Column(modifier = modifier) {
if (state.card != null) {
TangemRow(
divider = true,
contentLead = TangemRowContentLead.Start,
titleSlot = {
TangemRowText(
text = resourceReference(R.string.tangempay_common_card),
role = TangemRowTextRole.Title,
)
},
valueSlot = {
TangemRowText(
text = state.card,
role = TangemRowTextRole.Value,
)
},
)
when (val detail = state.detail) {
null -> Unit
TransactionDetailUM.Loading -> CardRowShimmer()
is TransactionDetailUM.Content -> CardRow(value = detail.card)
is TransactionDetailUM.Error -> CardRowError(onRefreshClick = detail.onRefreshClick)
}
TangemRow(
divider = state.mcc != null,
@ -287,6 +270,79 @@ private fun TransactionDetailsBlock(state: TangemPayTxHistoryDetailsUMV2, modifi
}
}
@Composable
private fun CardRow(value: TextReference, modifier: Modifier = Modifier) {
TangemRow(
modifier = modifier,
divider = true,
contentLead = TangemRowContentLead.Start,
titleSlot = {
TangemRowText(
text = resourceReference(R.string.tangempay_common_card),
role = TangemRowTextRole.Title,
)
},
valueSlot = {
TangemRowText(
text = value,
role = TangemRowTextRole.Value,
)
},
)
}
@Composable
private fun CardRowShimmer(modifier: Modifier = Modifier) {
TangemRow(
modifier = modifier,
divider = true,
contentLead = TangemRowContentLead.Start,
titleSlot = {
TangemShimmer(style = TangemTheme.typography3.body.medium)
},
)
}
@Composable
private fun CardRowError(onRefreshClick: () -> Unit, modifier: Modifier = Modifier) {
TangemRow(
modifier = modifier,
divider = true,
contentLead = TangemRowContentLead.Start,
verticalAlignment = TangemRowVerticalAlignment.Center,
titleSlot = {
TangemRowText(
text = resourceReference(R.string.tangempay_common_card),
role = TangemRowTextRole.Title,
)
},
valueSlot = {
Row(
modifier = Modifier
.clip(RoundedCornerShape(4.dp))
.clickable(onClick = onRefreshClick)
.padding(2.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = resourceReference(R.string.tangempay_common_error_loading).resolveReference(),
style = TangemTheme.typography3.body.medium,
color = TangemTheme.colors3.text.status.error,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Icon(
modifier = Modifier.size(20.dp),
imageVector = Icons.ic_arrow_refresh_20,
contentDescription = null,
tint = TangemTheme.colors3.icon.status.error,
)
}
},
)
}
@Preview(device = Devices.PIXEL_7_PRO)
@Preview(device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
@ -307,7 +363,7 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_category_24),
transactionTitle = stringReference("Starbucks"),
card = stringReference("Basic card *9092"),
detail = TransactionDetailUM.Content(stringReference("Basic card *9092")),
transactionCategory = stringReference("Food and drinks"),
mcc = stringReference("5814"),
transactionAmount = "-$5.86",
@ -329,7 +385,7 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_category_24),
transactionTitle = stringReference("NuCaloric"),
card = stringReference("Basic card *9092"),
detail = TransactionDetailUM.Content(stringReference("Basic card *9092")),
transactionCategory = stringReference("Groceries"),
mcc = stringReference("0000"),
transactionAmount = "-$820.52",
@ -352,7 +408,7 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_category_24),
transactionTitle = stringReference("Starbucks"),
card = stringReference("Basic card *9092"),
detail = TransactionDetailUM.Content(stringReference("Basic card *9092")),
transactionCategory = stringReference("Food and drinks"),
mcc = null,
transactionAmount = "-$5.86",
@ -374,7 +430,7 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_percent_24),
transactionTitle = stringReference("Service fees"),
card = null,
detail = null,
transactionCategory = stringReference("Service fees"),
mcc = null,
transactionAmount = "-$5.86",
@ -397,7 +453,7 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(imageVector = Icons.ic_arrow_down_24),
transactionTitle = resourceReference(R.string.common_transfer),
card = null,
detail = null,
transactionCategory = resourceReference(R.string.common_transfer),
mcc = null,
transactionAmount = "+$20",
@ -409,5 +465,49 @@ private class TangemPayTxHistoryDetailsUMProviderV2 :
),
dismiss = {},
),
TangemPayTxHistoryDetailsUMV2(
isBalanceHidden = false,
title = resourceReference(R.string.tangem_pay_purchase),
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_category_24),
transactionTitle = stringReference("Starbucks"),
detail = TransactionDetailUM.Loading,
transactionCategory = stringReference("Food and drinks"),
mcc = stringReference("5814"),
transactionAmount = "-$5.86",
localTransactionText = null,
label = TransactionLabelUM(
transactionStateType = TransactionStateType.Completed,
icon = TangemIconUM.Icon(iconRes = R.drawable.ic_token_info_24),
title = resourceReference(R.string.tangem_pay_status_completed),
),
buttonState = ButtonState(
text = resourceReference(R.string.tangem_pay_get_help),
onClick = {},
),
dismiss = {},
),
TangemPayTxHistoryDetailsUMV2(
isBalanceHidden = false,
title = resourceReference(R.string.tangem_pay_purchase),
subtitle = stringReference("12 June 2026, 12:40"),
iconState = TangemIconUM.Icon(iconRes = R.drawable.ic_category_24),
transactionTitle = stringReference("Starbucks"),
detail = TransactionDetailUM.Error(onRefreshClick = {}),
transactionCategory = stringReference("Food and drinks"),
mcc = stringReference("5814"),
transactionAmount = "-$5.86",
localTransactionText = null,
label = TransactionLabelUM(
transactionStateType = TransactionStateType.Completed,
icon = TangemIconUM.Icon(iconRes = R.drawable.ic_token_info_24),
title = resourceReference(R.string.tangem_pay_status_completed),
),
buttonState = ButtonState(
text = resourceReference(R.string.tangem_pay_get_help),
onClick = {},
),
dismiss = {},
),
),
)

View file

@ -3,6 +3,46 @@ package com.tangem.features.tangempay
import com.tangem.domain.models.pay.TangemPayCard
import com.tangem.domain.models.pay.TangemPayCardFrozenState
import com.tangem.domain.models.pay.TangemPayCardState
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import org.joda.time.DateTime
import java.math.BigDecimal
import java.util.Currency
internal fun spendTransaction(
id: String = "tx_1",
cardName: String? = "Basic card",
cardNumberLast4: String? = "9092",
status: TangemPayTxHistoryItem.Status = TangemPayTxHistoryItem.Status.COMPLETED,
): TangemPayTxHistoryItem.Spend = TangemPayTxHistoryItem.Spend(
id = id,
jsonRepresentation = "{}",
date = DateTime(0L),
amount = BigDecimal.TEN,
currency = Currency.getInstance("USD"),
authorizedAmount = BigDecimal.TEN,
localAmount = null,
localCurrency = null,
enrichedMerchantName = null,
merchantName = "Merchant",
enrichedMerchantCategory = null,
merchantCategoryCode = null,
merchantCategory = null,
status = status,
enrichedMerchantIconUrl = null,
declinedReason = null,
cardName = cardName,
cardNumberLast4 = cardNumberLast4,
)
internal fun paymentTransaction(id: String = "tx_payment_1"): TangemPayTxHistoryItem.Payment =
TangemPayTxHistoryItem.Payment(
id = id,
jsonRepresentation = "{}",
date = DateTime(0L),
amount = BigDecimal.TEN,
currency = Currency.getInstance("USD"),
transactionHash = null,
)
internal fun tangemPayCard(
id: String = "card_1",

View file

@ -0,0 +1,195 @@
package com.tangem.features.tangempay.model
import android.text.format.DateFormat
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.google.common.truth.Truth.assertThat
import com.tangem.core.decompose.model.MutableParamsContainer
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tangempay.repository.TangemPayTxHistoryRepository
import com.tangem.domain.visa.error.VisaApiError
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
import com.tangem.features.tangempay.components.TangemPayTransactionBottomSheetComponent
import com.tangem.features.tangempay.entity.TransactionDetailUM
import com.tangem.features.tangempay.paymentTransaction
import com.tangem.features.tangempay.spendTransaction
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.clearMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@OptIn(ExperimentalCoroutinesApi::class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class TangemPayTxHistoryDetailsModelTest {
private val userWalletId = UserWalletId("123")
private val repository: TangemPayTxHistoryRepository = mockk()
private val balanceHidingSettings: GetBalanceHidingSettingsUseCase = mockk()
@BeforeEach
fun setup() {
clearMocks(repository, balanceHidingSettings)
every { balanceHidingSettings.isBalanceHidden() } returns flowOf(false)
mockkStatic(DateFormat::class)
every { DateFormat.getBestDateTimePattern(any(), any()) } answers { secondArg() }
}
@AfterEach
fun tearDown() {
unmockkStatic(DateFormat::class)
}
@Test
fun `GIVEN spend transaction WHEN detail fetch in flight THEN card is Loading`() = runTest {
// Arrange
coEvery { repository.getTransaction(any(), any()) } coAnswers { awaitCancellation() }
val model = createModel(testScope = this, transaction = spendTransaction())
// Act
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail).isEqualTo(TransactionDetailUM.Loading)
model.onDestroy()
}
@Test
fun `GIVEN spend transaction WHEN detail fetch succeeds THEN card shows loaded name and last4`() = runTest {
// Arrange — the sheet opens with no card info, the detail fetch back-fills it
val loaded = spendTransaction(cardName = "Loaded card", cardNumberLast4 = "4321")
coEvery { repository.getTransaction(any(), any()) } returns loaded.right()
val model = createModel(
testScope = this,
transaction = spendTransaction(cardName = null, cardNumberLast4 = null),
)
// Act
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail)
.isEqualTo(TransactionDetailUM.Content(stringReference("Loaded card *4321")))
model.onDestroy()
}
@Test
fun `GIVEN spend transaction WHEN detail fetch succeeds without card info THEN card row is hidden`() = runTest {
// Arrange
coEvery { repository.getTransaction(any(), any()) } returns
spendTransaction(cardName = null, cardNumberLast4 = null).right()
val model = createModel(testScope = this, transaction = spendTransaction())
// Act
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail).isNull()
model.onDestroy()
}
@Test
fun `GIVEN spend transaction WHEN detail fetch fails THEN card is Error`() = runTest {
// Arrange
coEvery { repository.getTransaction(any(), any()) } returns VisaApiError.Unspecified.left()
val model = createModel(testScope = this, transaction = spendTransaction())
// Act
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail).isInstanceOf(TransactionDetailUM.Error::class.java)
model.onDestroy()
}
@Test
fun `GIVEN card error WHEN refresh clicked and fetch succeeds THEN card shows value`() = runTest {
// Arrange — first fetch fails, retry succeeds
val loaded = spendTransaction(cardName = "Loaded card", cardNumberLast4 = "4321")
coEvery {
repository.getTransaction(any(), any())
} returnsMany listOf<Either<VisaApiError, TangemPayTxHistoryItem?>>(
VisaApiError.Unspecified.left(),
loaded.right(),
)
val model = createModel(testScope = this, transaction = spendTransaction())
advanceUntilIdle()
val errorState = model.uiState.value.redesign.detail
assertThat(errorState).isInstanceOf(TransactionDetailUM.Error::class.java)
// Act — tap refresh
(errorState as TransactionDetailUM.Error).onRefreshClick()
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail)
.isEqualTo(TransactionDetailUM.Content(stringReference("Loaded card *4321")))
coVerify(exactly = 2) { repository.getTransaction(any(), any()) }
model.onDestroy()
}
@Test
fun `GIVEN non-spend transaction WHEN model created THEN card is hidden and detail not fetched`() = runTest {
// Arrange
val model = createModel(testScope = this, transaction = paymentTransaction())
// Act
advanceUntilIdle()
// Assert
assertThat(model.uiState.value.redesign.detail).isNull()
coVerify(exactly = 0) { repository.getTransaction(any(), any()) }
model.onDestroy()
}
private fun createModel(
testScope: TestScope,
transaction: TangemPayTxHistoryItem,
): TangemPayTxHistoryDetailsModel {
val params = TangemPayTransactionBottomSheetComponent.Params(
isBalanceHidden = false,
transaction = transaction,
userWalletId = userWalletId,
customerId = "customer_1",
onDismiss = {},
)
return TangemPayTxHistoryDetailsModel(
dispatchers = testScope.createTestingCoroutineDispatcherProvider(),
getWalletMetaInfoUseCase = mockk(relaxed = true),
sendFeedbackEmailUseCase = mockk(relaxed = true),
urlOpener = mockk(relaxed = true),
balanceHidingSettings = balanceHidingSettings,
tangemPayTxHistoryRepository = repository,
analytics = mockk(relaxed = true),
paramsContainer = MutableParamsContainer(params),
)
}
private fun TestScope.createTestingCoroutineDispatcherProvider(): TestingCoroutineDispatcherProvider {
val testDispatcher = StandardTestDispatcher(testScheduler)
return TestingCoroutineDispatcherProvider(
main = testDispatcher,
mainImmediate = testDispatcher,
io = testDispatcher,
default = testDispatcher,
single = testDispatcher,
)
}
}