Updated on 2026-08-14
This commit is contained in:
parent
db28e42f72
commit
25444c3a2d
17 changed files with 415 additions and 50 deletions
|
|
@ -94,6 +94,7 @@ dependencies {
|
|||
// region Project - Features
|
||||
api(projects.features.swap.domain)
|
||||
api(projects.features.virtualAccounts.details.api)
|
||||
api(projects.features.tangempay.details.api)
|
||||
// endregion
|
||||
|
||||
// region Project - Libs
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@ import com.tangem.domain.pay.model.CustomerInfo.ProductInstance.SpecificationDat
|
|||
import com.tangem.domain.pay.model.OrderData
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayEntryPoint
|
||||
import com.tangem.domain.pay.usecase.GetTangemPayTariffPlanStateUseCase
|
||||
import com.tangem.domain.pay.repository.*
|
||||
import com.tangem.domain.pay.usecase.GetTangemPayTariffPlanStateUseCase
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusProducer
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.features.virtualaccount.VirtualAccountFeatureToggles
|
||||
import com.tangem.security.DeviceSecurityInfoProvider
|
||||
import com.tangem.security.isSecurityExposed
|
||||
|
|
@ -64,6 +65,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val issueCardRepository: TangemPayIssueCardRepository,
|
||||
private val virtualAccountFeatureToggles: VirtualAccountFeatureToggles,
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles,
|
||||
private val getTangemPayTariffPlanStateUseCase: GetTangemPayTariffPlanStateUseCase,
|
||||
) : PaymentAccountStatusFetcher {
|
||||
|
||||
|
|
@ -174,17 +176,65 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
},
|
||||
ifRight = { customerInfo ->
|
||||
logger.i("proceedWithoutOrder data customerInfo ${account.userWalletId}")
|
||||
val status = customerInfo.mapToPaymentAccountStatus(account.userWalletId)
|
||||
if (status is PaymentAccountStatusValue.IssuingCard && customerInfo.kycStatus == KycStatus.APPROVED) {
|
||||
// If order id wasn't saved -> start order creation and get customer info
|
||||
onboardingRepository.createOrder(account.userWalletId)
|
||||
.onLeft { TangemLogger.withTag(TAG).e("createOrder failed: $it") }
|
||||
}
|
||||
status
|
||||
resolveFinalStatus(
|
||||
account = account,
|
||||
customerInfo = customerInfo,
|
||||
status = customerInfo.mapToPaymentAccountStatus(account.userWalletId),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun resolveFinalStatus(
|
||||
account: Account.Payment,
|
||||
customerInfo: CustomerInfo,
|
||||
status: PaymentAccountStatusValue,
|
||||
): PaymentAccountStatusValue {
|
||||
val isIssuing = status is PaymentAccountStatusValue.IssuingCard
|
||||
val isApproved = customerInfo.kycStatus == KycStatus.APPROVED
|
||||
val userWalletId = account.userWalletId
|
||||
val tariffPlan = customerInfo.tariffPlan
|
||||
|
||||
if (!tangemPayFeatureToggles.isTiersPlusPlanEnabled) {
|
||||
if (isIssuing && isApproved) {
|
||||
// If order id wasn't saved -> start order creation and get customer info
|
||||
onboardingRepository.createOrder(userWalletId)
|
||||
.onLeft { logger.e("createOrder failed: $it") }
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
if (!isIssuing || !isApproved) {
|
||||
return status
|
||||
}
|
||||
|
||||
if (tariffPlan == null) {
|
||||
return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
}
|
||||
|
||||
val hasActiveIssueOrder = issueCardRepository.getIssueOrderIds(userWalletId).isNotEmpty()
|
||||
return if (hasActiveIssueOrder) {
|
||||
PaymentAccountStatusValue.Inactive(
|
||||
source = StatusSource.ACTUAL,
|
||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||
tariffPlan = getTangemPayTariffPlanStateUseCase(
|
||||
userWalletId = userWalletId,
|
||||
tariff = tariffPlan,
|
||||
),
|
||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||
availableBalance = BigDecimal.ZERO,
|
||||
currency = tariffPlan.plan.feeCurrencyOrDefault(),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
PaymentAccountStatusValue.AwaitingPlanSelection(
|
||||
source = StatusSource.ACTUAL,
|
||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||
tariffPlan = tariffPlan,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithOrderId(account: Account.Payment, orderId: String): PaymentAccountStatusValue {
|
||||
// Step 1: Check KYC status first
|
||||
val customerInfo = onboardingRepository.getCustomerInfo(account.userWalletId).fold(
|
||||
|
|
@ -286,24 +336,26 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
params = SingleQuoteStatusProducer.Params(rawCurrencyId = TangemPayCurrencyFactory.TOKEN_ID),
|
||||
)?.value as? QuoteStatus.Data
|
||||
|
||||
val customerId = customerId
|
||||
val isDeactivated = productInstance?.status == CustomerInfo.ProductInstance.Status.DEACTIVATED
|
||||
val isFormer = state == CustomerInfo.State.FORMER
|
||||
val fiatBalance = fiatBalance
|
||||
val cryptoBalance = cryptoBalance
|
||||
|
||||
val hasCardData = cards.isNotEmpty() && productInstances.isNotEmpty()
|
||||
val isTiersPlusPlanEnabled = tangemPayFeatureToggles.isTiersPlusPlanEnabled
|
||||
return when {
|
||||
kycStatus != KycStatus.APPROVED && !customerId.isNullOrEmpty() -> {
|
||||
PaymentAccountStatusValue.UnderReview(
|
||||
source = StatusSource.ACTUAL,
|
||||
kycStatus = kycStatus,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
}
|
||||
fiatBalance != null && cryptoBalance != null && !customerId.isNullOrEmpty() &&
|
||||
(isDeactivated || isFormer) -> {
|
||||
customerId.isNullOrEmpty() -> PaymentAccountStatusValue.IssuingCard(
|
||||
source = StatusSource.ACTUAL,
|
||||
)
|
||||
kycStatus != KycStatus.APPROVED -> PaymentAccountStatusValue.UnderReview(
|
||||
source = StatusSource.ACTUAL,
|
||||
kycStatus = kycStatus,
|
||||
customerId = customerId,
|
||||
)
|
||||
fiatBalance != null && cryptoBalance != null && (isDeactivated || isFormer) ->
|
||||
PaymentAccountStatusValue.Deactivated(
|
||||
source = StatusSource.ACTUAL,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
customerId = customerId,
|
||||
balance = PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
|
|
@ -313,15 +365,14 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
fiatRate = quotesData?.fiatRate,
|
||||
error = null,
|
||||
)
|
||||
}
|
||||
cards.isNotEmpty() && productInstances.isNotEmpty() &&
|
||||
fiatBalance != null && cryptoBalance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
||||
userWalletId = userWalletId,
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
fiatRate = quotesData?.fiatRate,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
fiatBalance != null && cryptoBalance != null && (hasCardData || isTiersPlusPlanEnabled) ->
|
||||
convertToContentState(
|
||||
userWalletId = userWalletId,
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
fiatRate = quotesData?.fiatRate,
|
||||
customerId = customerId,
|
||||
)
|
||||
else -> PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
}
|
||||
}
|
||||
|
|
@ -365,7 +416,9 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
if (tangemPayCards.isEmpty()) return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
if (!tangemPayFeatureToggles.isTiersPlusPlanEnabled && tangemPayCards.isEmpty()) {
|
||||
return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
}
|
||||
|
||||
// Additional-card issuance: the backend omits the new card until it is provisioned, so surface a
|
||||
// placeholder for every locally tracked in-flight issuance order alongside the real cards.
|
||||
|
|
@ -376,6 +429,12 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
// the previously shown order and append newly seen cards at the end.
|
||||
val orderedCards = tangemPayCards.stableOrder(previousRealCardOrder(userWalletId))
|
||||
|
||||
val allCards = orderedCards + issuingCards
|
||||
|
||||
if (allCards.isEmpty()) {
|
||||
return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
}
|
||||
|
||||
val virtualAccount = resolveVirtualAccountOnramp(userWalletId)
|
||||
|
||||
return PaymentAccountStatusValue.Loaded(
|
||||
|
|
@ -384,7 +443,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
depositAddress = cryptoBalance.depositAddress,
|
||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||
fiatRate = fiatRate,
|
||||
cards = orderedCards + issuingCards,
|
||||
cards = allCards,
|
||||
balance = PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
|
|
|
|||
|
|
@ -7,11 +7,15 @@ import com.tangem.data.pay.store.PaymentAccountStatusesStore
|
|||
import com.tangem.domain.models.account.AccountStatus
|
||||
import com.tangem.domain.models.account.BankCredentials
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlan
|
||||
import com.tangem.domain.models.account.TangemPayTariffPlanState
|
||||
import com.tangem.domain.models.account.VirtualAccountOnramp
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
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.models.pay.TangemPayEligibilityType
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayCurrencyFactory
|
||||
|
|
@ -22,6 +26,7 @@ import com.tangem.domain.pay.repository.*
|
|||
import com.tangem.domain.pay.usecase.GetTangemPayTariffPlanStateUseCase
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.features.tangempay.TangemPayFeatureToggles
|
||||
import com.tangem.features.virtualaccount.VirtualAccountFeatureToggles
|
||||
import com.tangem.security.DeviceSecurityInfoProvider
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
|
|
@ -49,6 +54,7 @@ internal class DefaultPaymentAccountStatusFetcherTest {
|
|||
private val cardDetailsRepository: TangemPayCardDetailsRepository = mockk()
|
||||
private val issueCardRepository: TangemPayIssueCardRepository = mockk()
|
||||
private val virtualAccountFeatureToggles: VirtualAccountFeatureToggles = mockk()
|
||||
private val tangemPayFeatureToggles: TangemPayFeatureToggles = mockk()
|
||||
private val getTangemPayTariffPlanStateUseCase: GetTangemPayTariffPlanStateUseCase = mockk()
|
||||
|
||||
private val fetcher = DefaultPaymentAccountStatusFetcher(
|
||||
|
|
@ -65,6 +71,7 @@ internal class DefaultPaymentAccountStatusFetcherTest {
|
|||
cardDetailsRepository = cardDetailsRepository,
|
||||
issueCardRepository = issueCardRepository,
|
||||
virtualAccountFeatureToggles = virtualAccountFeatureToggles,
|
||||
tangemPayFeatureToggles = tangemPayFeatureToggles,
|
||||
getTangemPayTariffPlanStateUseCase = getTangemPayTariffPlanStateUseCase,
|
||||
)
|
||||
|
||||
|
|
@ -111,27 +118,47 @@ internal class DefaultPaymentAccountStatusFetcherTest {
|
|||
images = emptyList(),
|
||||
)
|
||||
|
||||
private val basicPlan = TangemPayTariffPlan(
|
||||
id = "plan_basic",
|
||||
type = TangemPayTariffPlan.Type.BASIC,
|
||||
name = "Basic",
|
||||
descriptionItems = emptyList(),
|
||||
images = emptyList(),
|
||||
fees = emptyList(),
|
||||
)
|
||||
|
||||
private val customerTariffPlan = TangemPayCustomerTariffPlan(
|
||||
status = TangemPayCustomerTariffPlan.Status.ACTIVE,
|
||||
plan = basicPlan,
|
||||
nextBillingAt = null,
|
||||
pendingPlan = null,
|
||||
pendingTransitionAt = null,
|
||||
)
|
||||
|
||||
private fun buildCustomerInfo(
|
||||
productInstances: List<CustomerInfo.ProductInstance> = listOf(cardProductInstance),
|
||||
) = CustomerInfo(
|
||||
customerId = "cust_1",
|
||||
kycStatus = KycStatus.APPROVED,
|
||||
state = CustomerInfo.State.ACTIVE,
|
||||
fiatBalance = PaymentAccountStatusValue.FiatBalance(
|
||||
fiatBalance: PaymentAccountStatusValue.FiatBalance? = PaymentAccountStatusValue.FiatBalance(
|
||||
availableBalance = BigDecimal.TEN,
|
||||
currency = "USD",
|
||||
),
|
||||
cryptoBalance = PaymentAccountStatusValue.CryptoBalance(
|
||||
cryptoBalance: PaymentAccountStatusValue.CryptoBalance? = PaymentAccountStatusValue.CryptoBalance(
|
||||
id = "usdc",
|
||||
chainId = 137L,
|
||||
depositAddress = "0xdeposit",
|
||||
tokenContractAddress = "0xcontract",
|
||||
balance = BigDecimal.TEN,
|
||||
),
|
||||
tariffPlan: TangemPayCustomerTariffPlan? = null,
|
||||
) = CustomerInfo(
|
||||
customerId = "cust_1",
|
||||
kycStatus = KycStatus.APPROVED,
|
||||
state = CustomerInfo.State.ACTIVE,
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
availableForWithdrawal = BigDecimal.TEN,
|
||||
cards = listOf(cardInfo),
|
||||
productInstances = productInstances,
|
||||
tariffPlan = null,
|
||||
tariffPlan = tariffPlan,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
|
|
@ -146,10 +173,14 @@ internal class DefaultPaymentAccountStatusFetcherTest {
|
|||
cardDetailsRepository,
|
||||
issueCardRepository,
|
||||
virtualAccountFeatureToggles,
|
||||
tangemPayFeatureToggles,
|
||||
getTangemPayTariffPlanStateUseCase,
|
||||
)
|
||||
// Relaxed mocks don't need clearing — deviceSecurity, eligibilityManager, paymentAccountStatusesStore
|
||||
// are relaxed and consistent with their relaxed defaults (false, empty, etc.)
|
||||
clearMocks(paymentAccountStatusesStore, answers = false)
|
||||
// Tiers off by default — legacy auto-order-creation behavior. Individual tests override.
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns false
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -304,4 +335,142 @@ internal class DefaultPaymentAccountStatusFetcherTest {
|
|||
assertThat(loaded.virtualAccount).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class TiersPlanSelection {
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers on and KYC approved and no plan order WHEN invoke THEN stores AwaitingPlanSelection`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(
|
||||
productInstances = emptyList(),
|
||||
fiatBalance = null,
|
||||
cryptoBalance = null,
|
||||
tariffPlan = customerTariffPlan,
|
||||
)
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns true
|
||||
coEvery { issueCardRepository.getIssueOrderIds(userWalletId) } returns emptyList()
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
assertThat(storedStatuses.last().value)
|
||||
.isInstanceOf(PaymentAccountStatusValue.AwaitingPlanSelection::class.java)
|
||||
coVerify(exactly = 0) { onboardingRepository.createOrder(userWalletId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers on and fallback plan is missing WHEN invoke THEN stores IssuingCard without order`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(
|
||||
productInstances = emptyList(),
|
||||
fiatBalance = null,
|
||||
cryptoBalance = null,
|
||||
tariffPlan = null,
|
||||
)
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns true
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
assertThat(storedStatuses.last().value)
|
||||
.isInstanceOf(PaymentAccountStatusValue.IssuingCard::class.java)
|
||||
coVerify(exactly = 0) { onboardingRepository.createOrder(userWalletId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers on and plan selected but no balance yet WHEN invoke THEN stores Inactive`() = runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(
|
||||
productInstances = emptyList(),
|
||||
fiatBalance = null,
|
||||
cryptoBalance = null,
|
||||
tariffPlan = customerTariffPlan,
|
||||
)
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns true
|
||||
coEvery { issueCardRepository.getIssueOrderIds(userWalletId) } returns listOf("order_1")
|
||||
coEvery {
|
||||
getTangemPayTariffPlanStateUseCase(userWalletId = userWalletId, tariff = customerTariffPlan)
|
||||
} returns TangemPayTariffPlanState(tariff = customerTariffPlan, order = null)
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
assertThat(storedStatuses.last().value)
|
||||
.isInstanceOf(PaymentAccountStatusValue.Inactive::class.java)
|
||||
coVerify(exactly = 0) { onboardingRepository.createOrder(userWalletId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers off and KYC approved without card WHEN invoke THEN creates order and stays issuing`() = runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(productInstances = emptyList())
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns false
|
||||
coEvery { onboardingRepository.createOrder(userWalletId) } returns Either.Right("order_1")
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
assertThat(storedStatuses.last().value)
|
||||
.isInstanceOf(PaymentAccountStatusValue.IssuingCard::class.java)
|
||||
coVerify(exactly = 1) { onboardingRepository.createOrder(userWalletId) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers off and balance without instances but local issue order WHEN invoke THEN stores IssuingCard`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(productInstances = emptyList())
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns false
|
||||
coEvery { issueCardRepository.getIssueOrderIds(userWalletId) } returns listOf("order_1")
|
||||
coEvery { onboardingRepository.createOrder(userWalletId) } returns Either.Right("order_1")
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
assertThat(storedStatuses.last().value)
|
||||
.isInstanceOf(PaymentAccountStatusValue.IssuingCard::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN tiers on and balance without instances but local issue order WHEN invoke THEN stores Loaded with placeholder`() =
|
||||
runTest {
|
||||
// Arrange
|
||||
val customerInfo = buildCustomerInfo(productInstances = emptyList())
|
||||
stubHappyPath(customerInfo)
|
||||
every { tangemPayFeatureToggles.isTiersPlusPlanEnabled } returns true
|
||||
every { virtualAccountFeatureToggles.isVaMvp0Enabled } returns false
|
||||
coEvery { issueCardRepository.getIssueOrderIds(userWalletId) } returns listOf("order_1")
|
||||
coEvery {
|
||||
cardDetailsRepository.getOrderInfo(userWalletId, "order_1")
|
||||
} returns VisaApiError.UnknownWithoutCode.left()
|
||||
val storedStatuses = captureStoredStatuses()
|
||||
|
||||
// Act
|
||||
fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
val loaded = storedStatuses.lastLoaded()
|
||||
assertThat(loaded.cards).hasSize(1)
|
||||
assertThat(loaded.cards.single().state).isEqualTo(TangemPayCardState.Issuing)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue