Updated on 2026-08-14
This commit is contained in:
parent
db08399066
commit
ae809ece30
28 changed files with 939 additions and 10 deletions
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.features.wallet.deeplink
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
interface PromoDeeplinkHandler {
|
||||
|
||||
interface Factory {
|
||||
fun create(coroutineScope: CoroutineScope, queryParams: Map<String, String>): PromoDeeplinkHandler
|
||||
}
|
||||
}
|
||||
|
|
@ -121,6 +121,8 @@ dependencies {
|
|||
implementation(projects.common.ui)
|
||||
|
||||
/** Test libraries */
|
||||
implementation(deps.test.junit)
|
||||
implementation(deps.test.truth)
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(deps.test.mockk)
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
package com.tangem.feature.wallet.deeplink
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.PROMO_CODE_KEY
|
||||
import com.tangem.core.decompose.di.GlobalUiMessageSender
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.mask
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.GlobalLoadingMessage
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.wallets.PromoCodeActivationResult
|
||||
import com.tangem.domain.wallets.PromoCodeActivationResult.*
|
||||
import com.tangem.domain.wallets.models.errors.ActivatePromoCodeError
|
||||
import com.tangem.domain.wallets.usecase.ActivateBitcoinPromocodeUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import com.tangem.features.wallet.deeplink.PromoDeeplinkHandler
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultPromoDeeplinkHandler @AssistedInject constructor(
|
||||
@Assisted private val scope: CoroutineScope,
|
||||
@Assisted private val queryParams: Map<String, String>,
|
||||
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
|
||||
private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase,
|
||||
private val activateBitcoinPromocodeUseCase: ActivateBitcoinPromocodeUseCase,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
) : PromoDeeplinkHandler {
|
||||
|
||||
init {
|
||||
val promoCode = queryParams[PROMO_CODE_KEY].orEmpty()
|
||||
if (promoCode.isEmpty()) {
|
||||
showAlert(InvalidPromoCode)
|
||||
} else {
|
||||
findSelectedWallet(promoCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findSelectedWallet(promoCode: String) {
|
||||
getSelectedWalletSyncUseCase().fold(
|
||||
ifLeft = {
|
||||
Timber.tag(LOG_TAG).e("Error on getting user wallet: $it")
|
||||
showAlert(Failed)
|
||||
},
|
||||
ifRight = { userWallet ->
|
||||
Timber.tag(LOG_TAG).d("SelectedUserWallet ${userWallet.walletId.stringValue.mask()}")
|
||||
findBitcoinAddress(userWallet = userWallet, promoCode = promoCode)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun findBitcoinAddress(userWallet: UserWallet, promoCode: String) {
|
||||
scope.launch {
|
||||
getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(userWallet.walletId).onRight { currencies ->
|
||||
val bitcoinAddress = currencies.find { it.currency.id.rawNetworkId == Blockchain.Bitcoin.id }
|
||||
?.value
|
||||
?.networkAddress
|
||||
?.defaultAddress
|
||||
?.value
|
||||
|
||||
if (bitcoinAddress != null) {
|
||||
Timber.tag(LOG_TAG).d(
|
||||
"Start activation promoCode ${promoCode.mask()} address ${bitcoinAddress.mask()}",
|
||||
)
|
||||
activatePromoCode(bitcoinAddress = bitcoinAddress, promoCode = promoCode)
|
||||
} else {
|
||||
Timber.tag(LOG_TAG).d("no Bitcoin address")
|
||||
showAlert(NoBitcoinAddress)
|
||||
}
|
||||
}.onLeft {
|
||||
Timber.tag(LOG_TAG).e("Error on getting userWallet currencies: $it")
|
||||
showAlert(Failed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun activatePromoCode(bitcoinAddress: String, promoCode: String) {
|
||||
uiMessageSender.send(GlobalLoadingMessage(true))
|
||||
activateBitcoinPromocodeUseCase(bitcoinAddress, promoCode).onRight {
|
||||
uiMessageSender.send(GlobalLoadingMessage(false))
|
||||
delay(DEFAULT_MESSAGE_SENDER_DELAY)
|
||||
Timber.tag(LOG_TAG).d("${promoCode.mask()} activation success on address ${bitcoinAddress.mask()}")
|
||||
showAlert(Activated)
|
||||
}.onLeft { error ->
|
||||
uiMessageSender.send(GlobalLoadingMessage(false))
|
||||
delay(DEFAULT_MESSAGE_SENDER_DELAY)
|
||||
Timber.tag(LOG_TAG).d("${promoCode.mask()} activation failed $error")
|
||||
val alertType = when (error) {
|
||||
ActivatePromoCodeError.ActivationFailed -> Failed
|
||||
ActivatePromoCodeError.InvalidPromoCode -> InvalidPromoCode
|
||||
ActivatePromoCodeError.NoBitcoinAddress -> NoBitcoinAddress
|
||||
ActivatePromoCodeError.PromocodeAlreadyUsed -> PromoCodeAlreadyUsed
|
||||
}
|
||||
showAlert(alertType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAlert(type: PromoCodeActivationResult) {
|
||||
val (title, message) = when (type) {
|
||||
Failed -> resourceReference(R.string.bitcoin_promo_activation_error_title) to
|
||||
resourceReference(R.string.bitcoin_promo_activation_error)
|
||||
InvalidPromoCode -> resourceReference(R.string.bitcoin_promo_invalid_code_title) to
|
||||
resourceReference(R.string.bitcoin_promo_invalid_code)
|
||||
NoBitcoinAddress -> resourceReference(R.string.bitcoin_promo_no_address_title) to
|
||||
resourceReference(R.string.bitcoin_promo_no_address)
|
||||
PromoCodeAlreadyUsed -> resourceReference(R.string.bitcoin_promo_already_activated_title) to
|
||||
resourceReference(R.string.bitcoin_promo_already_activated)
|
||||
Activated -> resourceReference(R.string.bitcoin_promo_activation_success_title) to
|
||||
resourceReference(R.string.bitcoin_promo_activation_success)
|
||||
}
|
||||
uiMessageSender.send(
|
||||
DialogMessage(
|
||||
title = title,
|
||||
message = message,
|
||||
dismissOnFirstAction = true,
|
||||
firstActionBuilder = {
|
||||
okAction { }
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : PromoDeeplinkHandler.Factory {
|
||||
override fun create(
|
||||
coroutineScope: CoroutineScope,
|
||||
queryParams: Map<String, String>,
|
||||
): DefaultPromoDeeplinkHandler
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LOG_TAG = "PromoCodeActivation"
|
||||
private const val DEFAULT_MESSAGE_SENDER_DELAY = 500L
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.feature.wallet.deeplink.di
|
||||
|
||||
import com.tangem.feature.wallet.deeplink.DefaultPromoDeeplinkHandler
|
||||
import com.tangem.feature.wallet.deeplink.DefaultWalletDeepLinkActionTrigger
|
||||
import com.tangem.feature.wallet.deeplink.DefaultWalletDeepLinkHandler
|
||||
import com.tangem.features.wallet.deeplink.PromoDeeplinkHandler
|
||||
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
|
||||
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionTrigger
|
||||
import com.tangem.features.wallet.deeplink.WalletDeepLinkHandler
|
||||
|
|
@ -19,6 +21,10 @@ internal interface WalletDeepLinkModule {
|
|||
@Singleton
|
||||
fun bindWalletDeepLinkHandlerFactory(impl: DefaultWalletDeepLinkHandler.Factory): WalletDeepLinkHandler.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindPromoDeepLinkHandlerFactory(impl: DefaultPromoDeeplinkHandler.Factory): PromoDeeplinkHandler.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindWalletDeepLinkActionTrigger(impl: DefaultWalletDeepLinkActionTrigger): WalletDeepLinkActionTrigger
|
||||
|
|
|
|||
|
|
@ -0,0 +1,331 @@
|
|||
package com.tangem.feature.wallet.presentation.wallet.deeplink
|
||||
|
||||
import arrow.core.Either
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst
|
||||
import com.tangem.core.decompose.ui.UiMessage
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.GetUserWalletError
|
||||
import com.tangem.domain.wallets.models.errors.ActivatePromoCodeError
|
||||
import com.tangem.domain.wallets.usecase.ActivateBitcoinPromocodeUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
||||
import com.tangem.feature.wallet.deeplink.DefaultPromoDeeplinkHandler
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
import io.mockk.CapturingSlot
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.slot
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestDispatcher
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.resetMain
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
class DefaultPromoDeeplinkHandlerTest {
|
||||
|
||||
@MockK(relaxed = true)
|
||||
private lateinit var uiMessageSender: UiMessageSender
|
||||
|
||||
@MockK
|
||||
private lateinit var getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase
|
||||
|
||||
@MockK
|
||||
private lateinit var activateBitcoinPromocodeUseCase: ActivateBitcoinPromocodeUseCase
|
||||
|
||||
@MockK
|
||||
private lateinit var getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase
|
||||
|
||||
private lateinit var messageSlot: CapturingSlot<UiMessage>
|
||||
private lateinit var testDispatcher: TestDispatcher
|
||||
private lateinit var testScope: TestScope
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Before
|
||||
fun setUp() {
|
||||
testDispatcher = StandardTestDispatcher()
|
||||
testScope = TestScope(testDispatcher)
|
||||
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
|
||||
MockKAnnotations.init(this)
|
||||
messageSlot = slot()
|
||||
every { uiMessageSender.send(capture(messageSlot)) } just runs
|
||||
|
||||
Timber.uprootAll() // Disable Timber logging for tests
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@After
|
||||
fun tearDown() {
|
||||
Dispatchers.resetMain()
|
||||
testScope.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN empty promo code WHEN init THEN invalid promo code dialog is shown`() = runTest {
|
||||
val queryParams = emptyMap<String, String>()
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(resourceReference(R.string.bitcoin_promo_invalid_code_title))
|
||||
Truth.assertThat(sent.message).isEqualTo(resourceReference(R.string.bitcoin_promo_invalid_code))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallet fetch error WHEN getSelectedWalletUseCase THEN failed dialog is shown`() = runTest {
|
||||
val queryParams = mapOf(DeeplinkConst.PROMO_CODE_KEY to "PROMO123")
|
||||
every { getSelectedWalletSyncUseCase.invoke() } returns Either.Left(GetUserWalletError.UserWalletNotFound)
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_error_title))
|
||||
Truth.assertThat(sent.message).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_error))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN token status error WHEN getWalletCurrenciesScreen THEN failed dialog is shown`() = runTest {
|
||||
val queryParams = mapOf(DeeplinkConst.PROMO_CODE_KEY to "PROMO123")
|
||||
val userWallet = mockUserWallet("ABCDEF")
|
||||
every { getSelectedWalletSyncUseCase.invoke() } returns Either.Right(userWallet)
|
||||
coEvery { getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(userWallet.walletId) } returns Either.Left(
|
||||
TokenListError.DataError(Exception("boom")),
|
||||
)
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_error_title))
|
||||
Truth.assertThat(sent.message).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_error))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN no bitcoin address WHEN getWalletCurrenciesScreen THEN no bitcoin address dialog is shown`() = runTest {
|
||||
val queryParams = mapOf(DeeplinkConst.PROMO_CODE_KEY to "PROMO123")
|
||||
val userWallet = mockUserWallet("ABCDEF")
|
||||
every { getSelectedWalletSyncUseCase.invoke() } returns Either.Right(userWallet)
|
||||
// Return only ETH status so BTC is not found
|
||||
val ethStatus = buildStatusForNetwork(rawNetworkId = "ethereum", address = "0x123")
|
||||
coEvery { getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(userWallet.walletId) } returns Either.Right(
|
||||
listOf(ethStatus),
|
||||
)
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(resourceReference(R.string.bitcoin_promo_no_address_title))
|
||||
Truth.assertThat(sent.message).isEqualTo(resourceReference(R.string.bitcoin_promo_no_address))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN activation success WHEN activatePromoCode THEN activated dialog is shown`() = runTest {
|
||||
val promoCode = "PROMO123"
|
||||
val queryParams = mapOf(DeeplinkConst.PROMO_CODE_KEY to promoCode)
|
||||
val userWallet = mockUserWallet("ABCDEF")
|
||||
every { getSelectedWalletSyncUseCase.invoke() } returns Either.Right(userWallet)
|
||||
val btcStatus = buildStatusForNetwork(rawNetworkId = Blockchain.Bitcoin.id, address = "bc1qxyz")
|
||||
coEvery { getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(userWallet.walletId) } returns Either.Right(
|
||||
listOf(btcStatus),
|
||||
)
|
||||
coEvery { activateBitcoinPromocodeUseCase.invoke("bc1qxyz", promoCode) } returns Either.Right("ok")
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_success_title))
|
||||
Truth.assertThat(sent.message).isEqualTo(resourceReference(R.string.bitcoin_promo_activation_success))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN activation invalid code WHEN activatePromoCode THEN invalid promo code dialog is shown`() = runTest {
|
||||
runActivationErrorCase(
|
||||
error = ActivatePromoCodeError.InvalidPromoCode,
|
||||
expectedTitle = resourceReference(R.string.bitcoin_promo_invalid_code_title),
|
||||
expectedMessage = resourceReference(R.string.bitcoin_promo_invalid_code),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN activation failed WHEN activatePromoCode THEN failed dialog is shown`() = runTest {
|
||||
runActivationErrorCase(
|
||||
error = ActivatePromoCodeError.ActivationFailed,
|
||||
expectedTitle = resourceReference(R.string.bitcoin_promo_activation_error_title),
|
||||
expectedMessage = resourceReference(R.string.bitcoin_promo_activation_error),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN activation no address WHEN activatePromoCode THEN no bitcoin address dialog is shown`() = runTest {
|
||||
runActivationErrorCase(
|
||||
error = ActivatePromoCodeError.NoBitcoinAddress,
|
||||
expectedTitle = resourceReference(R.string.bitcoin_promo_no_address_title),
|
||||
expectedMessage = resourceReference(R.string.bitcoin_promo_no_address),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN activation already used WHEN activatePromoCode THEN already activated dialog is shown`() = runTest {
|
||||
runActivationErrorCase(
|
||||
error = ActivatePromoCodeError.PromocodeAlreadyUsed,
|
||||
expectedTitle = resourceReference(R.string.bitcoin_promo_already_activated_title),
|
||||
expectedMessage = resourceReference(R.string.bitcoin_promo_already_activated),
|
||||
)
|
||||
}
|
||||
|
||||
private fun runActivationErrorCase(
|
||||
error: ActivatePromoCodeError,
|
||||
expectedTitle: TextReference,
|
||||
expectedMessage: TextReference,
|
||||
) = runTest {
|
||||
val promoCode = "PROMO123"
|
||||
val queryParams = mapOf(DeeplinkConst.PROMO_CODE_KEY to promoCode)
|
||||
val userWallet = mockUserWallet("ABCDEF")
|
||||
every { getSelectedWalletSyncUseCase.invoke() } returns Either.Right(userWallet)
|
||||
val btcStatus = buildStatusForNetwork(rawNetworkId = Blockchain.Bitcoin.id, address = "bc1qxyz")
|
||||
coEvery { getMultiCryptoCurrencyStatusUseCase.invokeMultiWalletSync(userWallet.walletId) } returns Either.Right(
|
||||
listOf(btcStatus),
|
||||
)
|
||||
coEvery { activateBitcoinPromocodeUseCase.invoke("bc1qxyz", promoCode) } returns Either.Left(error)
|
||||
|
||||
DefaultPromoDeeplinkHandler(
|
||||
scope = this,
|
||||
queryParams = queryParams,
|
||||
uiMessageSender = uiMessageSender,
|
||||
getMultiCryptoCurrencyStatusUseCase = getMultiCryptoCurrencyStatusUseCase,
|
||||
activateBitcoinPromocodeUseCase = activateBitcoinPromocodeUseCase,
|
||||
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
val sent = messageSlot.captured as DialogMessage
|
||||
Truth.assertThat(sent.title).isEqualTo(expectedTitle)
|
||||
Truth.assertThat(sent.message).isEqualTo(expectedMessage)
|
||||
}
|
||||
|
||||
private fun mockUserWallet(id: String): UserWallet {
|
||||
val userWallet = mockk<UserWallet>(relaxed = true)
|
||||
every { userWallet.walletId } returns UserWalletId(id)
|
||||
return userWallet
|
||||
}
|
||||
|
||||
private fun buildStatusForNetwork(rawNetworkId: String, address: String): CryptoCurrencyStatus {
|
||||
val networkId = Network.ID(Network.RawID(rawNetworkId), Network.DerivationPath.None)
|
||||
val network = Network(
|
||||
id = networkId,
|
||||
backendId = rawNetworkId,
|
||||
name = rawNetworkId,
|
||||
currencySymbol = rawNetworkId.take(3).uppercase(),
|
||||
derivationPath = Network.DerivationPath.None,
|
||||
isTestnet = false,
|
||||
standardType = Network.StandardType.Unspecified("UNSPECIFIED"),
|
||||
hasFiatFeeRate = false,
|
||||
canHandleTokens = false,
|
||||
transactionExtrasType = Network.TransactionExtrasType.NONE,
|
||||
)
|
||||
|
||||
val currencyId = CryptoCurrency.ID(
|
||||
prefix = CryptoCurrency.ID.Prefix.TOKEN_PREFIX,
|
||||
body = CryptoCurrency.ID.Body.NetworkId(rawNetworkId),
|
||||
suffix = CryptoCurrency.ID.Suffix.RawID(rawNetworkId),
|
||||
)
|
||||
|
||||
val coin = CryptoCurrency.Coin(
|
||||
id = currencyId,
|
||||
network = network,
|
||||
name = rawNetworkId,
|
||||
symbol = network.currencySymbol,
|
||||
decimals = 8,
|
||||
iconUrl = null,
|
||||
isCustom = false,
|
||||
)
|
||||
|
||||
val value = CryptoCurrencyStatus.NoQuote(
|
||||
amount = BigDecimal.ZERO,
|
||||
yieldBalance = null,
|
||||
hasCurrentNetworkTransactions = false,
|
||||
pendingTransactions = emptySet(),
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(
|
||||
value = address,
|
||||
type = NetworkAddress.Address.Type.Primary,
|
||||
),
|
||||
),
|
||||
sources = CryptoCurrencyStatus.Sources(),
|
||||
)
|
||||
|
||||
return CryptoCurrencyStatus(
|
||||
currency = coin,
|
||||
value = value,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue