Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-22 12:48:30 +05:00
parent c372e4faee
commit 96baa58105
7 changed files with 1767 additions and 9 deletions

View file

@ -47,6 +47,7 @@ import com.tangem.features.send.v2.sendnft.confirm.NFTSendConfirmComponent
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmInitialStateTransformer
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmSendingStateTransformer
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformer
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
import com.tangem.features.send.v2.sendnft.ui.state.NFTSendUM
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadListener
import com.tangem.features.send.v2.subcomponents.fee.SendFeeCheckReloadTrigger
@ -393,13 +394,23 @@ internal class NFTSendConfirmModel @Inject constructor(
}
_uiState.update {
it.copy(
confirmUM = NFTSendConfirmationNotificationsTransformer(
feeUM = uiState.value.feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrencyStatus.currency,
analyticsCategoryName = analyticsCategoryName,
appCurrency = params.appCurrency,
).transform(uiState.value.confirmUM),
confirmUM = if (uiState.value.isRedesignEnabled) {
NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = uiState.value.feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrencyStatus.currency,
appCurrency = params.appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
} else {
NFTSendConfirmationNotificationsTransformer(
feeUM = uiState.value.feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrencyStatus.currency,
analyticsCategoryName = analyticsCategoryName,
appCurrency = params.appCurrency,
)
}.transform(uiState.value.confirmUM),
)
}
}

View file

@ -62,8 +62,10 @@ internal class NFTSendConfirmationNotificationsTransformer(
val feeUM = feeUM as? FeeUM.Content
val fee = (feeUM?.feeSelectorUM as? FeeSelectorUM.Content)?.selectedFee ?: return TextReference.EMPTY
val fiatFeeValue = feeUM.rate?.let { fee.amount.value?.multiply(it) }
val fiatFee = formatFooterFiatFee(
amount = fee.amount,
amount = fee.amount.copy(value = fiatFeeValue),
isFeeConvertibleToFiat = feeUM.isFeeConvertibleToFiat,
isFeeApproximate = feeUM.isFeeApproximate,
appCurrency = appCurrency,

View file

@ -0,0 +1,92 @@
package com.tangem.features.send.v2.sendnft.confirm.model.transformers
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.subcomponents.feeSelector.utils.FeeCalculationUtils
import com.tangem.features.send.v2.api.utils.formatFooterFiatFee
import com.tangem.features.send.v2.api.utils.getTronTokenFeeSendingText
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.toPersistentList
internal class NFTSendConfirmationNotificationsTransformerV2(
private val feeSelectorUM: FeeSelectorUM,
private val analyticsEventHandler: AnalyticsEventHandler,
private val cryptoCurrency: CryptoCurrency,
private val appCurrency: AppCurrency,
private val analyticsCategoryName: String,
) : Transformer<ConfirmUM> {
override fun transform(prevState: ConfirmUM): ConfirmUM {
val state = prevState as? ConfirmUM.Content ?: return prevState
val feeSelectorUM = feeSelectorUM as? FeeSelectorUM.Content ?: return prevState
return state.copy(
sendingFooter = getSendingFooterText(),
notifications = buildList {
addTooHighNotification(feeSelectorUM)
addTooLowNotification(feeSelectorUM)
}.toPersistentList(),
)
}
private fun MutableList<NotificationUM>.addTooLowNotification(feeSelectorUM: FeeSelectorUM.Content) {
if (FeeCalculationUtils.checkIfCustomFeeTooLow(feeSelectorUM)) {
add(NotificationUM.Warning.FeeTooLow)
analyticsEventHandler.send(
CommonSendAnalyticEvents.NoticeTransactionDelays(
categoryName = analyticsCategoryName,
token = cryptoCurrency.symbol,
),
)
}
}
private fun MutableList<NotificationUM>.addTooHighNotification(feeSelectorUM: FeeSelectorUM.Content) {
val (isFeeTooHigh, diff) = FeeCalculationUtils.checkIfCustomFeeTooHigh(feeSelectorUM)
if (isFeeTooHigh) {
add(NotificationUM.Warning.TooHigh(diff))
}
}
private fun getSendingFooterText(): TextReference {
val feeSelectorUM = feeSelectorUM as? FeeSelectorUM.Content
val fee = feeSelectorUM?.selectedFeeItem?.fee ?: return TextReference.EMPTY
val fiatFeeValue = feeSelectorUM.feeFiatRateUM?.rate?.let { fee.amount.value?.multiply(it) }
val fiatFee = formatFooterFiatFee(
amount = fee.amount.copy(value = fiatFeeValue),
isFeeConvertibleToFiat = feeSelectorUM.feeFiatRateUM != null,
isFeeApproximate = feeSelectorUM.feeExtraInfo.isFeeApproximate,
appCurrency = appCurrency,
)
return if (fee is Fee.Tron) {
getTronTokenFeeSendingText(
fee = fee,
fiatFee = fiatFee,
fiatSending = resourceReference(R.string.common_nft),
)
} else {
resourceReference(
id = if (feeSelectorUM.feeFiatRateUM != null) {
R.string.send_summary_transaction_description
} else {
R.string.send_summary_transaction_description_no_fiat_fee
},
formatArgs = wrappedList(
resourceReference(R.string.common_nft),
fiatFee,
),
)
}
}
}

View file

@ -0,0 +1,822 @@
package com.tangem.features.send.v2.send.confirm.model.transformers
import com.google.common.truth.Truth.assertThat
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.entity.*
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformer
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import io.mockk.mockk
import io.mockk.verify
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.BigInteger
import java.util.Locale
import com.tangem.features.send.v2.api.entity.FeeSelectorUM as FeeSelectorUMV2
class NFTSendConfirmNotificationsTransformersComparisonTest {
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true)
private val appCurrency = AppCurrency(name = "US Dollar", code = "USD", symbol = "$")
private val analyticsCategoryName = "test_category"
@Test
fun `GIVEN equivalent input data WHEN both transformers transform THEN they produce equal ConfirmUM`() = runTest {
// GIVEN
val initialConfirmUM = createTestConfirmUM()
val feeUM = createTestFeeUM()
val feeSelectorUMV2 = createTestFeeSelectorUMV2()
// WHEN
val transformerV1 = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val transformerV2 = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUMV2,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val resultV1 = transformerV1.transform(initialConfirmUM)
val resultV2 = transformerV2.transform(initialConfirmUM)
// THEN
assertThat(resultV1).isInstanceOf(ConfirmUM.Content::class.java)
assertThat(resultV2).isInstanceOf(ConfirmUM.Content::class.java)
val contentV1 = resultV1 as ConfirmUM.Content
val contentV2 = resultV2 as ConfirmUM.Content
assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled)
assertThat(contentV1.notifications.size).isEqualTo(contentV2.notifications.size)
assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter)
assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled)
assertThat(contentV1.isSending).isEqualTo(contentV2.isSending)
assertThat(contentV1.showTapHelp).isEqualTo(contentV2.showTapHelp)
}
@Test
fun `GIVEN fee too low WHEN both transformers transform THEN they produce equal notifications`() = runTest {
// GIVEN
val initialConfirmUM = createTestConfirmUM()
val feeUM = createFeeTooLowUM()
val feeSelectorUMV2 = createFeeTooLowUMV2()
// WHEN
val transformerV1 = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val transformerV2 = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUMV2,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val resultV1 = transformerV1.transform(initialConfirmUM)
val resultV2 = transformerV2.transform(initialConfirmUM)
// THEN
assertThat(resultV1).isInstanceOf(ConfirmUM.Content::class.java)
assertThat(resultV2).isInstanceOf(ConfirmUM.Content::class.java)
val contentV1 = resultV1 as ConfirmUM.Content
val contentV2 = resultV2 as ConfirmUM.Content
assertThat(contentV1.isPrimaryButtonEnabled).isTrue()
assertThat(contentV2.isPrimaryButtonEnabled).isTrue()
assertThat(contentV1.notifications).hasSize(1)
assertThat(contentV2.notifications).hasSize(1)
assertThat(contentV1.notifications.first()).isInstanceOf(NotificationUM.Warning.FeeTooLow::class.java)
assertThat(contentV2.notifications.first()).isInstanceOf(NotificationUM.Warning.FeeTooLow::class.java)
assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter)
// Verify analytics event was sent for both transformers
verify(exactly = 2) { analyticsEventHandler.send(any()) }
}
@Test
fun `GIVEN fee too high WHEN both transformers transform THEN they produce equal notifications`() = runTest {
// GIVEN
val initialConfirmUM = createTestConfirmUM()
val feeUM = createFeeTooHighUM()
val feeSelectorUMV2 = createFeeTooHighUMV2()
// WHEN
val transformerV1 = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val transformerV2 = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUMV2,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val resultV1 = transformerV1.transform(initialConfirmUM)
val resultV2 = transformerV2.transform(initialConfirmUM)
// THEN
assertThat(resultV1).isInstanceOf(ConfirmUM.Content::class.java)
assertThat(resultV2).isInstanceOf(ConfirmUM.Content::class.java)
val contentV1 = resultV1 as ConfirmUM.Content
val contentV2 = resultV2 as ConfirmUM.Content
assertThat(contentV1.isPrimaryButtonEnabled).isTrue()
assertThat(contentV2.isPrimaryButtonEnabled).isTrue()
assertThat(contentV1.notifications).hasSize(1)
assertThat(contentV2.notifications).hasSize(1)
assertThat(contentV1.notifications.first()).isInstanceOf(NotificationUM.Warning.TooHigh::class.java)
assertThat(contentV2.notifications.first()).isInstanceOf(NotificationUM.Warning.TooHigh::class.java)
val tooHighV1 = contentV1.notifications.first() as NotificationUM.Warning.TooHigh
val tooHighV2 = contentV2.notifications.first() as NotificationUM.Warning.TooHigh
assertThat(tooHighV1.value).isEqualTo(tooHighV2.value)
assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter)
}
@Test
fun `GIVEN fee both too high and too low WHEN both transformers transform THEN they produce equal notifications`() =
runTest {
// GIVEN
val initialConfirmUM = createTestConfirmUM()
val feeUM = createFeeTooHighAndTooLowUM()
val feeSelectorUMV2 = createFeeTooHighAndTooLowUMV2()
// WHEN
val transformerV1 = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val transformerV2 = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUMV2,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val resultV1 = transformerV1.transform(initialConfirmUM)
val resultV2 = transformerV2.transform(initialConfirmUM)
// THEN
assertThat(resultV1).isInstanceOf(ConfirmUM.Content::class.java)
assertThat(resultV2).isInstanceOf(ConfirmUM.Content::class.java)
val contentV1 = resultV1 as ConfirmUM.Content
val contentV2 = resultV2 as ConfirmUM.Content
assertThat(contentV1.isPrimaryButtonEnabled).isTrue()
assertThat(contentV2.isPrimaryButtonEnabled).isTrue()
assertThat(contentV1.notifications).hasSize(2)
assertThat(contentV2.notifications).hasSize(2)
assertThat(contentV1.notifications.any { it is NotificationUM.Warning.FeeTooLow }).isTrue()
assertThat(contentV1.notifications.any { it is NotificationUM.Warning.TooHigh }).isTrue()
assertThat(contentV2.notifications.any { it is NotificationUM.Warning.FeeTooLow }).isTrue()
assertThat(contentV2.notifications.any { it is NotificationUM.Warning.TooHigh }).isTrue()
assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter)
verify(exactly = 2) { analyticsEventHandler.send(any()) }
}
@Test
fun `GIVEN normal fee WHEN both transformers transform THEN they produce equal notifications`() = runTest {
// GIVEN
val initialConfirmUM = createTestConfirmUM()
val feeUM = createNormalFeeUM()
val feeSelectorUMV2 = createNormalFeeSelectorUMV2()
// WHEN
val transformerV1 = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val transformerV2 = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUMV2,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val resultV1 = transformerV1.transform(initialConfirmUM)
val resultV2 = transformerV2.transform(initialConfirmUM)
// THEN
assertThat(resultV1).isInstanceOf(ConfirmUM.Content::class.java)
assertThat(resultV2).isInstanceOf(ConfirmUM.Content::class.java)
val contentV1 = resultV1 as ConfirmUM.Content
val contentV2 = resultV2 as ConfirmUM.Content
assertThat(contentV1.notifications).isEmpty()
assertThat(contentV2.notifications).isEmpty()
assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled)
assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter)
}
private fun createTestConfirmUM(): ConfirmUM.Content {
return ConfirmUM.Content(
isPrimaryButtonEnabled = true,
walletName = mockk(relaxed = true),
isSending = false,
showTapHelp = false,
sendingFooter = mockk(relaxed = true),
notifications = persistentListOf(),
)
}
private fun createTestFeeUM(): FeeUM.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Market,
selectedFee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
private fun createTestFeeSelectorUMV2(): FeeSelectorUMV2.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeSelectorUMV2.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Market(fee),
),
selectedFeeItem = FeeItem.Market(fee),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooLowUM(): FeeUM.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.0001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = fee,
priority = fee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = true,
notifications = persistentListOf(),
)
}
private fun createFeeTooLowUMV2(): FeeSelectorUMV2.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.0001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = fee,
priority = fee,
)
return FeeSelectorUMV2.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooHighUM(): FeeUM.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = true,
notifications = persistentListOf(),
)
}
private fun createFeeTooHighUMV2(): FeeSelectorUMV2.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeSelectorUMV2.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooHighAndTooLowUM(): FeeUM.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.008"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = true,
notifications = persistentListOf(),
)
}
private fun createFeeTooHighAndTooLowUMV2(): FeeSelectorUMV2.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.008"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeSelectorUMV2.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createNormalFeeUM(): FeeUM.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Market,
selectedFee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "TST",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
private fun createNormalFeeSelectorUMV2(): FeeSelectorUMV2.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "TST",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeSelectorUMV2.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Market(fee),
),
selectedFeeItem = FeeItem.Market(fee),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
companion object {
@JvmStatic
@BeforeAll
fun setUpLocale() {
Locale.setDefault(Locale.US)
}
}
}

View file

@ -0,0 +1,381 @@
package com.tangem.features.send.v2.send.confirm.model.transformers
import com.google.common.truth.Truth.assertThat
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformer
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import io.mockk.mockk
import io.mockk.verify
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.BigInteger
import java.util.Locale
class NFTSendConfirmationNotificationsTransformerTest {
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true)
private val appCurrency = AppCurrency(name = "US Dollar", code = "USD", symbol = "$")
private val analyticsCategoryName = "test_category"
@Test
fun `GIVEN non content state WHEN transform THEN returns original state`() = runTest {
// GIVEN
val feeUM: FeeUM = mockk(relaxed = true)
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState: ConfirmUM = ConfirmUM.Empty
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isEqualTo(initialState)
}
@Test
fun `GIVEN fee UM not content WHEN transform THEN returns original state`() = runTest {
// GIVEN
val feeUM: FeeUM = FeeUM.Empty()
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState: ConfirmUM.Content = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isEqualTo(initialState)
}
@Test
fun `GIVEN normal fee WHEN transform THEN returns state with footer and no notifications`() = runTest {
// GIVEN
val feeUM = createNormalFeeUM()
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).isEmpty()
assertThat(content.sendingFooter).isNotEqualTo(initialState.sendingFooter)
}
@Test
fun `GIVEN fee too high WHEN transform THEN returns state with too high notification`() = runTest {
// GIVEN
val feeUM = createFeeTooHighUM()
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(1)
assertThat(content.notifications.first()).isInstanceOf(NotificationUM.Warning.TooHigh::class.java)
}
@Test
fun `GIVEN fee too low WHEN transform THEN returns state with too low notification`() = runTest {
// GIVEN
val feeUM = createFeeTooLowUM()
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(1)
assertThat(content.notifications.first()).isInstanceOf(NotificationUM.Warning.FeeTooLow::class.java)
verify { analyticsEventHandler.send(any()) }
}
@Test
fun `GIVEN both fee too high and too low WHEN transform THEN returns state with both notifications`() = runTest {
// GIVEN
val feeUM = createFeeTooHighAndTooLowUM()
val transformer = NFTSendConfirmationNotificationsTransformer(
feeUM = feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(2)
assertThat(content.notifications.any { it is NotificationUM.Warning.TooHigh }).isTrue()
assertThat(content.notifications.any { it is NotificationUM.Warning.FeeTooLow }).isTrue()
}
private fun createTestConfirmUM(): ConfirmUM.Content {
return ConfirmUM.Content(
isPrimaryButtonEnabled = true,
walletName = mockk(relaxed = true),
isSending = false,
showTapHelp = false,
sendingFooter = mockk(relaxed = true),
notifications = persistentListOf(),
)
}
private fun createNormalFeeUM(): FeeUM.Content {
val fee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Market,
selectedFee = fee,
customValues = persistentListOf(),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
private fun createFeeTooHighUM(): FeeUM.Content {
val priorityFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
private fun createFeeTooLowUM(): FeeUM.Content {
val fee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.0001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = fee,
priority = fee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
private fun createFeeTooHighAndTooLowUM(): FeeUM.Content {
val priorityFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val customFee = Fee.Common(
amount = com.tangem.blockchain.common.Amount(
currencySymbol = "SOL",
value = BigDecimal("0.008"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeUM.Content(
feeSelectorUM = FeeSelectorUM.Content(
fees = transactionFee,
selectedType = FeeType.Custom,
selectedFee = customFee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
nonce = BigInteger.ZERO,
),
rate = BigDecimal("50000"),
isFeeConvertibleToFiat = true,
isFeeApproximate = false,
isTronToken = false,
isEditingDisabled = false,
isPrimaryButtonEnabled = true,
appCurrency = AppCurrency.Default,
isCustomSelected = false,
notifications = persistentListOf(),
)
}
companion object {
@JvmStatic
@BeforeAll
fun setUpLocale() {
Locale.setDefault(Locale.US)
}
}
}

View file

@ -0,0 +1,450 @@
package com.tangem.features.send.v2.send.confirm.model.transformers
import com.google.common.truth.Truth.assertThat
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.entity.*
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmationNotificationsTransformerV2
import io.mockk.mockk
import io.mockk.verify
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.BigInteger
import java.util.Locale
class NFTSendConfirmationNotificationsTransformerV2Test {
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true)
private val appCurrency = AppCurrency(name = "US Dollar", code = "USD", symbol = "$")
private val analyticsCategoryName = "test_category"
@Test
fun `GIVEN non content state WHEN transform THEN returns original state`() = runTest {
// GIVEN
val feeSelectorUM: FeeSelectorUM = mockk(relaxed = true)
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState: ConfirmUM = ConfirmUM.Empty
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isEqualTo(initialState)
}
@Test
fun `GIVEN fee selector not content WHEN transform THEN returns original state`() = runTest {
// GIVEN
val feeSelectorUM: FeeSelectorUM = FeeSelectorUM.Loading
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isEqualTo(initialState)
}
@Test
fun `GIVEN normal fee WHEN transform THEN returns state with footer and no notifications`() = runTest {
// GIVEN
val feeSelectorUM = createNormalFeeSelectorUM()
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).isEmpty()
assertThat(content.sendingFooter).isNotEqualTo(initialState.sendingFooter)
}
@Test
fun `GIVEN fee too high WHEN transform THEN returns state with too high notification`() = runTest {
// GIVEN
val feeSelectorUM = createFeeTooHighUM()
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(1)
assertThat(content.notifications.first()).isInstanceOf(NotificationUM.Warning.TooHigh::class.java)
}
@Test
fun `GIVEN fee too low WHEN transform THEN returns state with too low notification`() = runTest {
// GIVEN
val feeSelectorUM = createFeeTooLowUM()
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(1)
assertThat(content.notifications.first()).isInstanceOf(NotificationUM.Warning.FeeTooLow::class.java)
verify { analyticsEventHandler.send(any()) }
}
@Test
fun `GIVEN both fee too high and too low WHEN transform THEN returns state with both notifications`() = runTest {
// GIVEN
val feeSelectorUM = createFeeTooHighAndTooLowUM()
val transformer = NFTSendConfirmationNotificationsTransformerV2(
feeSelectorUM = feeSelectorUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrency,
appCurrency = appCurrency,
analyticsCategoryName = analyticsCategoryName,
)
val initialState = createTestConfirmUM()
// WHEN
val result = transformer.transform(initialState)
// THEN
assertThat(result).isInstanceOf(ConfirmUM.Content::class.java)
val content = result as ConfirmUM.Content
assertThat(content.notifications).hasSize(2)
assertThat(content.notifications.any { it is NotificationUM.Warning.TooHigh }).isTrue()
assertThat(content.notifications.any { it is NotificationUM.Warning.FeeTooLow }).isTrue()
}
private fun createTestConfirmUM(): ConfirmUM.Content {
return ConfirmUM.Content(
isPrimaryButtonEnabled = true,
walletName = mockk(relaxed = true),
isSending = false,
showTapHelp = false,
sendingFooter = mockk(relaxed = true),
notifications = persistentListOf(),
)
}
private fun createNormalFeeSelectorUM(): FeeSelectorUM.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Single(fee)
return FeeSelectorUM.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(FeeItem.Market(fee)),
selectedFeeItem = FeeItem.Market(fee),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooHighUM(): FeeSelectorUM.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeSelectorUM.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.01"),
decimals = 8,
),
),
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.01"),
decimals = 8,
),
),
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.01",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooLowUM(): FeeSelectorUM.Content {
val fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.0001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = fee,
priority = fee,
)
return FeeSelectorUM.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = fee,
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.0001",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
private fun createFeeTooHighAndTooLowUM(): FeeSelectorUM.Content {
val priorityFee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.001"),
decimals = 8,
),
)
val minimumFee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.01"),
decimals = 8,
),
)
val transactionFee = TransactionFee.Choosable(
minimum = minimumFee,
normal = minimumFee,
priority = priorityFee,
)
return FeeSelectorUM.Content(
isPrimaryButtonEnabled = true,
fees = transactionFee,
feeItems = persistentListOf(
FeeItem.Custom(
fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.008"),
decimals = 8,
),
),
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
),
selectedFeeItem = FeeItem.Custom(
fee = Fee.Common(
amount = Amount(
currencySymbol = "SOL",
value = BigDecimal("0.008"),
decimals = 8,
),
),
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.008",
onValueChange = {},
keyboardOptions = mockk(relaxed = true),
keyboardActions = mockk(relaxed = true),
symbol = "SOL",
decimals = 8,
title = mockk(relaxed = true),
footer = mockk(relaxed = true),
),
),
),
feeExtraInfo = FeeExtraInfo(
isFeeApproximate = false,
isFeeConvertibleToFiat = false,
isTronToken = false,
),
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("50000"),
appCurrency = appCurrency,
),
feeNonce = FeeNonce.Nonce(
nonce = BigInteger.ZERO,
onNonceChange = {},
),
)
}
companion object {
@JvmStatic
@BeforeAll
fun setUpLocale() {
Locale.setDefault(Locale.US)
}
}
}

View file

@ -27,7 +27,7 @@ import java.util.Locale
import com.tangem.domain.tokens.model.Amount as DomainAmount
import com.tangem.features.send.v2.api.entity.FeeSelectorUM as FeeSelectorUMV2
class TransformersComparisonTest {
class SendConfirmNotificationsTransformersComparisonTest {
private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true)
private val cryptoCurrency: CryptoCurrency = mockk(relaxed = true)