Updated on 2026-08-14
This commit is contained in:
parent
4df207e832
commit
d443530171
10 changed files with 197 additions and 5 deletions
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.onramp.*
|
import com.tangem.domain.onramp.*
|
||||||
import com.tangem.domain.onramp.repositories.*
|
import com.tangem.domain.onramp.repositories.*
|
||||||
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -264,12 +265,14 @@ internal object OnrampDomainModule {
|
||||||
onrampErrorResolver: OnrampErrorResolver,
|
onrampErrorResolver: OnrampErrorResolver,
|
||||||
onrampTransactionRepository: OnrampTransactionRepository,
|
onrampTransactionRepository: OnrampTransactionRepository,
|
||||||
settingsRepository: SettingsRepository,
|
settingsRepository: SettingsRepository,
|
||||||
|
promoRepository: PromoRepository,
|
||||||
): GetOnrampOffersUseCase {
|
): GetOnrampOffersUseCase {
|
||||||
return GetOnrampOffersUseCase(
|
return GetOnrampOffersUseCase(
|
||||||
onrampRepository = onrampRepository,
|
onrampRepository = onrampRepository,
|
||||||
errorResolver = onrampErrorResolver,
|
errorResolver = onrampErrorResolver,
|
||||||
onrampTransactionRepository = onrampTransactionRepository,
|
onrampTransactionRepository = onrampTransactionRepository,
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
|
promoRepository = promoRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.tangem.datasource.di
|
package com.tangem.datasource.di
|
||||||
|
|
||||||
import com.tangem.datasource.local.datastore.RuntimeDataStore
|
import com.tangem.datasource.local.datastore.RuntimeDataStore
|
||||||
|
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||||
|
import com.tangem.datasource.local.promo.DefaultPromoBannerStore
|
||||||
import com.tangem.datasource.local.promo.DefaultPromoStoriesStore
|
import com.tangem.datasource.local.promo.DefaultPromoStoriesStore
|
||||||
|
import com.tangem.datasource.local.promo.PromoBannerStore
|
||||||
import com.tangem.datasource.local.promo.PromoStoriesStore
|
import com.tangem.datasource.local.promo.PromoStoriesStore
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -18,4 +21,10 @@ object PromoStoreModule {
|
||||||
fun providePromoStoriesStore(): PromoStoriesStore {
|
fun providePromoStoriesStore(): PromoStoriesStore {
|
||||||
return DefaultPromoStoriesStore(dataStore = RuntimeDataStore())
|
return DefaultPromoStoriesStore(dataStore = RuntimeDataStore())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun providePromoBannerStore(): PromoBannerStore {
|
||||||
|
return DefaultPromoBannerStore(dataStore = RuntimeSharedStore())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.tangem.datasource.local.promo
|
||||||
|
|
||||||
|
import com.tangem.datasource.api.promotion.models.PromoBannerResponse
|
||||||
|
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||||
|
|
||||||
|
internal class DefaultPromoBannerStore(
|
||||||
|
private val dataStore: RuntimeSharedStore<Map<String, PromoBannerResponse>>,
|
||||||
|
) : PromoBannerStore {
|
||||||
|
|
||||||
|
override suspend fun getSyncOrNull(promoId: String): PromoBannerResponse? {
|
||||||
|
return dataStore.getSyncOrNull()?.get(promoId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun store(promoId: String, promoBanner: PromoBannerResponse) {
|
||||||
|
dataStore.update(emptyMap()) { current ->
|
||||||
|
current + (promoId to promoBanner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.tangem.datasource.local.promo
|
||||||
|
|
||||||
|
import com.tangem.datasource.api.promotion.models.PromoBannerResponse
|
||||||
|
|
||||||
|
interface PromoBannerStore {
|
||||||
|
|
||||||
|
suspend fun getSyncOrNull(promoId: String): PromoBannerResponse?
|
||||||
|
|
||||||
|
suspend fun store(promoId: String, promoBanner: PromoBannerResponse)
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import com.tangem.datasource.local.preferences.PreferencesKeys.getShouldShowStor
|
||||||
import com.tangem.datasource.local.preferences.utils.get
|
import com.tangem.datasource.local.preferences.utils.get
|
||||||
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
import com.tangem.datasource.local.preferences.utils.getSyncOrDefault
|
||||||
import com.tangem.datasource.local.preferences.utils.store
|
import com.tangem.datasource.local.preferences.utils.store
|
||||||
|
import com.tangem.datasource.local.promo.PromoBannerStore
|
||||||
import com.tangem.datasource.local.promo.PromoStoriesStore
|
import com.tangem.datasource.local.promo.PromoStoriesStore
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.promo.PromoRepository
|
import com.tangem.domain.promo.PromoRepository
|
||||||
|
|
@ -28,6 +29,7 @@ internal class DefaultPromoRepository(
|
||||||
private val tangemApi: TangemTechApi,
|
private val tangemApi: TangemTechApi,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val promoStoriesStore: PromoStoriesStore,
|
private val promoStoriesStore: PromoStoriesStore,
|
||||||
|
private val promoBannerStore: PromoBannerStore,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val referralRepository: ReferralRepository,
|
private val referralRepository: ReferralRepository,
|
||||||
) : PromoRepository {
|
) : PromoRepository {
|
||||||
|
|
@ -96,6 +98,18 @@ internal class DefaultPromoRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun isMoonpayPromoActive(): Boolean {
|
||||||
|
val banner = runCatching(dispatchers.io) {
|
||||||
|
val response = promoBannerStore.getSyncOrNull(MOONPAY_NAME) ?: run {
|
||||||
|
val apiResponse = tangemApi.getPromoBanner(MOONPAY_NAME).getOrThrow()
|
||||||
|
promoBannerStore.store(MOONPAY_NAME, apiResponse)
|
||||||
|
apiResponse
|
||||||
|
}
|
||||||
|
promoBannerConverter.convert(response)
|
||||||
|
}.getOrNull()
|
||||||
|
return banner?.isActive == true
|
||||||
|
}
|
||||||
|
|
||||||
override fun getStoryById(id: String): Flow<StoryContent?> = isReadyToShowStories(id).mapLatest {
|
override fun getStoryById(id: String): Flow<StoryContent?> = isReadyToShowStories(id).mapLatest {
|
||||||
getStoryByIdSync(id = id, refresh = false)
|
getStoryByIdSync(id = id, refresh = false)
|
||||||
}
|
}
|
||||||
|
|
@ -166,6 +180,7 @@ internal class DefaultPromoRepository(
|
||||||
const val SEPA_NAME = "sepa"
|
const val SEPA_NAME = "sepa"
|
||||||
const val VISA_NAME = "visa-waitlist"
|
const val VISA_NAME = "visa-waitlist"
|
||||||
const val BLACK_FRIDAY_NAME = "black-friday"
|
const val BLACK_FRIDAY_NAME = "black-friday"
|
||||||
|
const val MOONPAY_NAME = "moonpay"
|
||||||
const val STORIES_LOAD_DELAY = 1000L
|
const val STORIES_LOAD_DELAY = 1000L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.promo.di
|
||||||
import com.tangem.data.promo.DefaultPromoRepository
|
import com.tangem.data.promo.DefaultPromoRepository
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
|
import com.tangem.datasource.local.promo.PromoBannerStore
|
||||||
import com.tangem.datasource.local.promo.PromoStoriesStore
|
import com.tangem.datasource.local.promo.PromoStoriesStore
|
||||||
import com.tangem.domain.promo.PromoRepository
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.feature.referral.domain.ReferralRepository
|
import com.tangem.feature.referral.domain.ReferralRepository
|
||||||
|
|
@ -23,6 +24,7 @@ internal object PromoDataModule {
|
||||||
tangemTechApi: TangemTechApi,
|
tangemTechApi: TangemTechApi,
|
||||||
appPreferencesStore: AppPreferencesStore,
|
appPreferencesStore: AppPreferencesStore,
|
||||||
promoStoriesStore: PromoStoriesStore,
|
promoStoriesStore: PromoStoriesStore,
|
||||||
|
promoBannerStore: PromoBannerStore,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
referralRepository: ReferralRepository,
|
referralRepository: ReferralRepository,
|
||||||
): PromoRepository {
|
): PromoRepository {
|
||||||
|
|
@ -32,6 +34,7 @@ internal object PromoDataModule {
|
||||||
promoStoriesStore = promoStoriesStore,
|
promoStoriesStore = promoStoriesStore,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
referralRepository = referralRepository,
|
referralRepository = referralRepository,
|
||||||
|
promoBannerStore = promoBannerStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ dependencies {
|
||||||
api(projects.domain.core)
|
api(projects.domain.core)
|
||||||
api(projects.domain.settings)
|
api(projects.domain.settings)
|
||||||
implementation(deps.kotlin.serialization)
|
implementation(deps.kotlin.serialization)
|
||||||
|
implementation(projects.domain.promo)
|
||||||
|
|
||||||
/** Tests */
|
/** Tests */
|
||||||
testImplementation(deps.test.coroutine)
|
testImplementation(deps.test.coroutine)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||||
import com.tangem.domain.onramp.utils.calculateRateDif
|
import com.tangem.domain.onramp.utils.calculateRateDif
|
||||||
import com.tangem.domain.onramp.utils.compareOffersByRateSpeedAndPriority
|
import com.tangem.domain.onramp.utils.compareOffersByRateSpeedAndPriority
|
||||||
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
class GetOnrampOffersUseCase(
|
class GetOnrampOffersUseCase(
|
||||||
|
|
@ -21,14 +23,16 @@ class GetOnrampOffersUseCase(
|
||||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||||
private val errorResolver: OnrampErrorResolver,
|
private val errorResolver: OnrampErrorResolver,
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
|
private val promoRepository: PromoRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(): EitherFlow<OnrampError, List<OnrampOffersBlock>> {
|
operator fun invoke(): EitherFlow<OnrampError, List<OnrampOffersBlock>> {
|
||||||
return combine(
|
return combine(
|
||||||
onrampRepository.getQuotes(),
|
onrampRepository.getQuotes(),
|
||||||
onrampTransactionRepository.getAllTransactions(),
|
onrampTransactionRepository.getAllTransactions(),
|
||||||
) { quotes, transactions ->
|
flow { emit(promoRepository.isMoonpayPromoActive()) },
|
||||||
processOffers(quotes, transactions)
|
) { quotes, transactions, isMoonpayPromoActive ->
|
||||||
|
processOffers(quotes, transactions, isMoonpayPromoActive)
|
||||||
}
|
}
|
||||||
.map { offers -> offers.right() }
|
.map { offers -> offers.right() }
|
||||||
.catch { throwable -> errorResolver.resolve(throwable).left() }
|
.catch { throwable -> errorResolver.resolve(throwable).left() }
|
||||||
|
|
@ -37,6 +41,7 @@ class GetOnrampOffersUseCase(
|
||||||
private suspend fun processOffers(
|
private suspend fun processOffers(
|
||||||
quotes: List<OnrampQuote>,
|
quotes: List<OnrampQuote>,
|
||||||
transactions: List<OnrampTransaction>,
|
transactions: List<OnrampTransaction>,
|
||||||
|
isMoonpayPromoActive: Boolean,
|
||||||
): List<OnrampOffersBlock> {
|
): List<OnrampOffersBlock> {
|
||||||
val validQuotes = quotes.filterIsInstance<OnrampQuote.Data>()
|
val validQuotes = quotes.filterIsInstance<OnrampQuote.Data>()
|
||||||
if (validQuotes.isEmpty()) return emptyList()
|
if (validQuotes.isEmpty()) return emptyList()
|
||||||
|
|
@ -57,7 +62,7 @@ class GetOnrampOffersUseCase(
|
||||||
|
|
||||||
val recentOffer = findRecentOffer(offers, transactions)
|
val recentOffer = findRecentOffer(offers, transactions)
|
||||||
val bestRateOffer = findBestRateOffer(offers, isGooglePayAvailable)
|
val bestRateOffer = findBestRateOffer(offers, isGooglePayAvailable)
|
||||||
val fastestOffer = findFastestOffer(offers, isGooglePayAvailable)
|
val fastestOffer = findFastestOffer(offers, isGooglePayAvailable, isMoonpayPromoActive)
|
||||||
|
|
||||||
return buildOffersBlocks(
|
return buildOffersBlocks(
|
||||||
recentOffer = recentOffer,
|
recentOffer = recentOffer,
|
||||||
|
|
@ -85,8 +90,24 @@ class GetOnrampOffersUseCase(
|
||||||
return offers.maxWithOrNull(offerComparator(isGooglePayAvailable))
|
return offers.maxWithOrNull(offerComparator(isGooglePayAvailable))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findFastestOffer(offers: List<OnrampOffer>, isGooglePayAvailable: Boolean): OnrampOffer? {
|
private fun findFastestOffer(
|
||||||
val instantOffers = offers.filter { it.quote.paymentMethod.type.isInstant() }
|
offers: List<OnrampOffer>,
|
||||||
|
isGooglePayAvailable: Boolean,
|
||||||
|
isMoonpayPromoActive: Boolean,
|
||||||
|
): OnrampOffer? {
|
||||||
|
val moonpayPromoOffers = if (isMoonpayPromoActive) {
|
||||||
|
offers.filter {
|
||||||
|
it.quote.provider.id == MOONPAY_PROMO_PROVIDER_ID &&
|
||||||
|
it.quote.paymentMethod.type == PaymentMethodType.GOOGLE_PAY
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val instantOffers = moonpayPromoOffers.ifEmpty {
|
||||||
|
offers.filter { it.quote.paymentMethod.type.isInstant() }
|
||||||
|
}
|
||||||
|
|
||||||
return if (instantOffers.isNotEmpty()) {
|
return if (instantOffers.isNotEmpty()) {
|
||||||
instantOffers.maxWithOrNull(fastestOfferComparator(isGooglePayAvailable))
|
instantOffers.maxWithOrNull(fastestOfferComparator(isGooglePayAvailable))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -287,4 +308,8 @@ class GetOnrampOffersUseCase(
|
||||||
-> true
|
-> true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val MOONPAY_PROMO_PROVIDER_ID = "moonpay"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||||
|
import com.tangem.domain.promo.PromoRepository
|
||||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
|
@ -24,6 +25,7 @@ class GetOnrampOffersUseCaseTest {
|
||||||
private val errorResolver: OnrampErrorResolver = mockk(relaxUnitFun = true)
|
private val errorResolver: OnrampErrorResolver = mockk(relaxUnitFun = true)
|
||||||
private val settingsRepository: SettingsRepository = mockk(relaxUnitFun = true)
|
private val settingsRepository: SettingsRepository = mockk(relaxUnitFun = true)
|
||||||
private val cryptoCurrencyId: CryptoCurrency.ID = mockk(relaxUnitFun = true)
|
private val cryptoCurrencyId: CryptoCurrency.ID = mockk(relaxUnitFun = true)
|
||||||
|
private val promoRepository: PromoRepository = mockk(relaxUnitFun = true)
|
||||||
|
|
||||||
private lateinit var useCase: GetOnrampOffersUseCase
|
private lateinit var useCase: GetOnrampOffersUseCase
|
||||||
|
|
||||||
|
|
@ -35,6 +37,7 @@ class GetOnrampOffersUseCaseTest {
|
||||||
onrampTransactionRepository = onrampTransactionRepository,
|
onrampTransactionRepository = onrampTransactionRepository,
|
||||||
errorResolver = errorResolver,
|
errorResolver = errorResolver,
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
|
promoRepository = promoRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,6 +228,7 @@ class GetOnrampOffersUseCaseTest {
|
||||||
|
|
||||||
val transactions = emptyList<OnrampTransaction>()
|
val transactions = emptyList<OnrampTransaction>()
|
||||||
|
|
||||||
|
coEvery { promoRepository.isMoonpayPromoActive() } returns false
|
||||||
coEvery { settingsRepository.isGooglePayAvailability() } returns false
|
coEvery { settingsRepository.isGooglePayAvailability() } returns false
|
||||||
coEvery { onrampRepository.getQuotes() } returns flowOf(quotes)
|
coEvery { onrampRepository.getQuotes() } returns flowOf(quotes)
|
||||||
coEvery { onrampTransactionRepository.getAllTransactions() } returns flowOf(
|
coEvery { onrampTransactionRepository.getAllTransactions() } returns flowOf(
|
||||||
|
|
@ -245,6 +249,107 @@ class GetOnrampOffersUseCaseTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `invoke should fallback to standard instant offers when promo is active but no Moonpay offers exist`() =
|
||||||
|
runTest {
|
||||||
|
val instantMethod = createMockPaymentMethod("gpay", "Google Pay", PaymentMethodType.GOOGLE_PAY)
|
||||||
|
val slowMethod = createMockPaymentMethod("bank", "Bank Transfer", PaymentMethodType.CARD)
|
||||||
|
val provider = createMockProvider("other", "Other Provider")
|
||||||
|
|
||||||
|
val quotes = listOf(
|
||||||
|
createMockQuote(instantMethod, provider, BigDecimal("95.0")),
|
||||||
|
createMockQuote(slowMethod, provider, BigDecimal("100.0")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val transactions = emptyList<OnrampTransaction>()
|
||||||
|
|
||||||
|
coEvery { promoRepository.isMoonpayPromoActive() } returns true
|
||||||
|
coEvery { settingsRepository.isGooglePayAvailability() } returns true
|
||||||
|
coEvery { onrampRepository.getQuotes() } returns flowOf(quotes)
|
||||||
|
coEvery { onrampTransactionRepository.getAllTransactions() } returns flowOf(transactions)
|
||||||
|
|
||||||
|
val result = useCase()
|
||||||
|
|
||||||
|
result.collect { either ->
|
||||||
|
Truth.assertThat(either.isRight()).isTrue()
|
||||||
|
either.fold(
|
||||||
|
ifLeft = { error -> Truth.assertThat(error).isNull() },
|
||||||
|
ifRight = { offers ->
|
||||||
|
Truth.assertThat(offers).hasSize(1)
|
||||||
|
|
||||||
|
val recommendedBlock = offers.find { it.category == OnrampOfferCategory.Recommended }
|
||||||
|
Truth.assertThat(recommendedBlock).isNotNull()
|
||||||
|
Truth.assertThat(recommendedBlock?.offers).hasSize(2)
|
||||||
|
|
||||||
|
val fastestOffer =
|
||||||
|
recommendedBlock?.offers?.find { it.advantages == OnrampOfferAdvantages.Fastest }
|
||||||
|
Truth.assertThat(fastestOffer).isNotNull()
|
||||||
|
|
||||||
|
when (val quote = fastestOffer?.quote) {
|
||||||
|
is OnrampQuote.Data -> {
|
||||||
|
Truth.assertThat(quote.provider.id).isNotEqualTo("moonpay")
|
||||||
|
Truth.assertThat(quote.paymentMethod.type).isEqualTo(PaymentMethodType.GOOGLE_PAY)
|
||||||
|
}
|
||||||
|
else -> Truth.assertThat(false).isTrue()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `invoke should show Moonpay fastest offer when promo is active`() = runTest {
|
||||||
|
val moonpayGooglePayMethod = createMockPaymentMethod("moonpay-gpay", "Google Pay", PaymentMethodType.GOOGLE_PAY)
|
||||||
|
val otherGooglePayMethod = createMockPaymentMethod(
|
||||||
|
"other-gpay",
|
||||||
|
"Other Google Pay",
|
||||||
|
PaymentMethodType.GOOGLE_PAY,
|
||||||
|
)
|
||||||
|
val slowMethod = createMockPaymentMethod("bank", "Bank Transfer", PaymentMethodType.CARD)
|
||||||
|
val moonpayProvider = createMockProvider("moonpay", "Moonpay")
|
||||||
|
val otherProvider = createMockProvider("other", "Other Provider")
|
||||||
|
|
||||||
|
val quotes = listOf(
|
||||||
|
createMockQuote(moonpayGooglePayMethod, moonpayProvider, BigDecimal("100.0")),
|
||||||
|
createMockQuote(otherGooglePayMethod, otherProvider, BigDecimal("95.0")),
|
||||||
|
createMockQuote(slowMethod, otherProvider, BigDecimal("105.0")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val transactions = emptyList<OnrampTransaction>()
|
||||||
|
|
||||||
|
coEvery { promoRepository.isMoonpayPromoActive() } returns true
|
||||||
|
coEvery { settingsRepository.isGooglePayAvailability() } returns true
|
||||||
|
coEvery { onrampRepository.getQuotes() } returns flowOf(quotes)
|
||||||
|
coEvery { onrampTransactionRepository.getAllTransactions() } returns flowOf(transactions)
|
||||||
|
|
||||||
|
val result = useCase()
|
||||||
|
|
||||||
|
result.collect { either ->
|
||||||
|
Truth.assertThat(either.isRight()).isTrue()
|
||||||
|
either.fold(
|
||||||
|
ifLeft = { error -> Truth.assertThat(error).isNull() },
|
||||||
|
ifRight = { offers ->
|
||||||
|
Truth.assertThat(offers).hasSize(1)
|
||||||
|
|
||||||
|
val recommendedBlock = offers.find { it.category == OnrampOfferCategory.Recommended }
|
||||||
|
Truth.assertThat(recommendedBlock).isNotNull()
|
||||||
|
|
||||||
|
val fastestOffer = recommendedBlock?.offers?.find { it.advantages == OnrampOfferAdvantages.Fastest }
|
||||||
|
Truth.assertThat(fastestOffer).isNotNull()
|
||||||
|
|
||||||
|
when (val quote = fastestOffer?.quote) {
|
||||||
|
is OnrampQuote.Data -> {
|
||||||
|
Truth.assertThat(quote.provider.id).isEqualTo("moonpay")
|
||||||
|
Truth.assertThat(quote.paymentMethod.type).isEqualTo(PaymentMethodType.GOOGLE_PAY)
|
||||||
|
Truth.assertThat(quote.toAmount.value).isEqualTo(BigDecimal("100.0"))
|
||||||
|
}
|
||||||
|
else -> Truth.assertThat(false).isTrue()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createMockPaymentMethod(
|
private fun createMockPaymentMethod(
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ interface PromoRepository {
|
||||||
fun isMarketsStakingNotificationHideClicked(): Flow<Boolean>
|
fun isMarketsStakingNotificationHideClicked(): Flow<Boolean>
|
||||||
|
|
||||||
suspend fun setMarketsStakingNotificationHideClicked()
|
suspend fun setMarketsStakingNotificationHideClicked()
|
||||||
|
|
||||||
|
suspend fun isMoonpayPromoActive(): Boolean
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Stories
|
// region Stories
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue