Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-01 09:56:03 +02:00
commit a65b0ab877
120 changed files with 4083 additions and 255 deletions

View file

@ -283,6 +283,8 @@ dependencies {
implementation(projects.features.onboardingV2.impl)
implementation(projects.features.stories.api)
implementation(projects.features.stories.impl)
implementation(projects.features.survey.api)
implementation(projects.features.survey.impl)
implementation(projects.features.txhistory.api)
implementation(projects.features.txhistory.impl)
implementation(projects.features.biometry.api)

View file

@ -183,6 +183,7 @@ abstract class BaseTestCase : TestCase(
"GASLESS_APPROVAL_ENABLED" to true,
"MAIN_SCREEN_QR_SCANNING_ENABLED" to true,
"ADD_AND_MANAGE_TOKENS_ENABLED" to true,
"ASSETS_DISCOVERY_ENABLED" to true,
"VISA_ONBOARDING_ENABLED" to true,
"AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING" to true,
"AND_15310_ADD_FUNDS_STAGE1" to true,

View file

@ -48,6 +48,10 @@ object TestConstants {
const val USER_TOKENS_API_SCENARIO = "user_tokens_api"
const val REFERRAL_API_SCENARIO = "referral_api"
const val QUOTES_API_SCENARIO = "quotes_api"
const val CREATE_USER_WALLET_API_SCENARIO = "create_user_wallet_api"
const val WALLET_TOKENS_API_SCENARIO = "wallet_tokens_api"
const val MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO = "moralis_evm_token_balances_api"
const val PROVIDERS_API_SCENARIO = "networks_providers"
const val SEED_PHRASE_12 = "they cram join fantasy unfair observe true theory buffalo bus exchange walk"
const val SEED_PHRASE_15 = "genuine try deer upset connect sausage diary rule price shallow fit faculty leopard " +
@ -60,6 +64,9 @@ object TestConstants {
"bread much nature basic fun iron benefit egg error prosper"
const val SVS_SEED_PHRASE_12 = "diagram thunder merit soup muscle amused refuse usual ring couch popular wash"
const val SEED_PHRASE_HAPPY_PATH =
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
const val TANGEM_PAY_ELIGIBILITY_SCENARIO = "tangem_pay_eligibility"
const val TANGEM_PAY_ACCESS_CODE = "517384"
}

View file

@ -4,6 +4,7 @@ import androidx.compose.ui.semantics.SemanticsProperties
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.swipeUp
import com.tangem.common.BaseTestCase
@ -23,7 +24,7 @@ import androidx.compose.ui.test.hasText as withText
import com.tangem.core.res.R as CoreResR
import com.tangem.core.ui.R as CoreUiR
class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
class MainScreenPageObject(private val semanticsProvider: SemanticsNodeInteractionsProvider) :
ComposeScreen<MainScreenPageObject>(semanticsProvider = semanticsProvider) {
private val lazyList = KLazyListNode(
@ -100,6 +101,22 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
}
}
val restoringProgressText: KNode = child {
hasTestTag(MainScreenTestTags.SYNC_PROGRESS_TEXT)
useUnmergedTree = true
}
val walletImportedBanner: KNode = child {
hasTestTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER)
useUnmergedTree = true
}
val walletImportedBannerCheckHereButton: KNode = child {
hasAnyAncestor(withTestTag(WalletNotificationTestTags.ASSETS_DISCOVERY_BANNER))
hasText(getResourceString(CoreResR.string.main_manage_tokens))
useUnmergedTree = true
}
@OptIn(ExperimentalTestApi::class)
fun marketPriceBlock(): LazyListItemNode {
collapseHeader()
@ -253,6 +270,15 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
}
}
@OptIn(ExperimentalTestApi::class)
fun tokenRowWithTitle(tokenTitle: String): LazyListItemNode {
return lazyList.childWith<LazyListItemNode> {
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
hasText(tokenTitle)
useUnmergedTree = true
}
}
/**
* Find token list item with title and address
*/
@ -350,6 +376,12 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
}
}
}
fun assertTokensCount(expectedCount: Int) {
semanticsProvider
.onAllNodes(withTestTag(TokenElementsTestTags.TOKEN_PRICE))
.assertCountEquals(expectedCount)
}
}
internal fun BaseTestCase.onMainScreen(function: MainScreenPageObject.() -> Unit) =

View file

@ -0,0 +1,251 @@
package com.tangem.tests.hotWallet
import androidx.test.InstrumentationRegistry.getTargetContext
import com.tangem.common.BaseTestCase
import com.tangem.common.constants.TestConstants.CREATE_USER_WALLET_API_SCENARIO
import com.tangem.common.constants.TestConstants.MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO
import com.tangem.common.constants.TestConstants.PROVIDERS_API_SCENARIO
import com.tangem.common.constants.TestConstants.SEED_PHRASE_12
import com.tangem.common.constants.TestConstants.SEED_PHRASE_HAPPY_PATH
import com.tangem.common.constants.TestConstants.USER_TOKENS_API_SCENARIO
import com.tangem.common.constants.TestConstants.WALLET_TOKENS_API_SCENARIO
import com.tangem.common.extensions.clickWithAssertion
import com.tangem.common.extensions.restartApp
import com.tangem.common.utils.resetWireMockScenarioState
import com.tangem.common.utils.setWireMockScenarioState
import com.tangem.scenarios.openMainScreenWithExistingHotWallet
import com.tangem.screens.*
import com.tangem.screens.accounts.onAccountDetailsScreen
import dagger.hilt.android.testing.HiltAndroidTest
import io.github.kakaocup.kakao.common.utilities.getResourceString
import io.qameta.allure.kotlin.AllureId
import io.qameta.allure.kotlin.junit4.DisplayName
import org.junit.Test
import com.tangem.core.ui.R as CoreUiR
@HiltAndroidTest
class AssetsDiscoveryTest : BaseTestCase() {
private companion object {
const val DISCOVERY_TIMEOUT_MILLIS = 120_000L
const val SCENARIO_STATE_STARTED = "Started"
const val SCENARIO_STATE_EMPTY = "Empty"
const val SCENARIO_STATE_ALREADY_EXISTS = "AlreadyExists"
const val SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT = "AssetsDiscoveryRedirect"
const val SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH = "AssetsDiscoveryHappyPath"
const val SCENARIO_STATE_NON_ZERO_EVM_BALANCES = "NonZeroEvmBalances"
const val SCENARIO_STATE_NON_ZERO_EVM_BALANCES_SLOW = "NonZeroEvmBalancesSlow"
val EXPECTED_DISCOVERED_TOKENS = listOf(
"Ethereum",
"Polygon",
"Tether",
)
val TOKENS_THAT_MUST_NOT_APPEAR = listOf(
"Solana",
"USDC",
)
val BACKEND_PRE_POPULATED_TOKENS = listOf(
"Bitcoin",
"Ethereum",
"Polygon",
)
}
@AllureId("9280")
@DisplayName("Hot wallet: new import — Discovery → Sync → Banner → Check here happy path")
@Test
fun newHotWalletImportHappyPathTest() {
val packageName = getTargetContext().packageName
setupHooks(
additionalBeforeAppLaunchSection = {
setWireMockScenarioState(PROVIDERS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT)
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_STARTED)
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH)
setWireMockScenarioState(WALLET_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
setWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO, state = SCENARIO_STATE_NON_ZERO_EVM_BALANCES)
},
additionalAfterSection = {
resetWireMockScenarioState(PROVIDERS_API_SCENARIO)
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(WALLET_TOKENS_API_SCENARIO)
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
},
).run {
step("Import a new hot wallet from seed phrase") {
openMainScreenWithExistingHotWallet(SEED_PHRASE_HAPPY_PATH)
}
step("Assert 'Restoring' progress loader is shown (discovery is in flight)") {
onMainScreen { restoringProgressText.assertIsDisplayed() }
}
step("Wait for 'Wallet successfully imported' banner (discovery completes)") {
flakySafely(timeoutMs = DISCOVERY_TIMEOUT_MILLIS) {
onMainScreen { walletImportedBanner.assertIsDisplayed() }
}
}
step("Assert expected discovered tokens are visible in the assets list") {
onMainScreen {
EXPECTED_DISCOVERED_TOKENS.forEach { token ->
tokenRowWithTitle(token).assertIsDisplayed()
}
}
}
step("Tap 'Check here' (Manage tokens) on the banner") {
onMainScreen { walletImportedBannerCheckHereButton.clickWithAssertion() }
}
step("Assert 'Manage Tokens' screen is opened") {
onManageTokensScreen { searchField.assertIsDisplayed() }
}
step("Return to main screen") {
device.uiDevice.pressBack()
waitForIdle()
}
step("Assert banner is hidden after navigating into Manage Tokens") {
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
}
step("Force-close and re-launch the app") {
restartApp(packageName)
}
step("Assert banner is NOT shown again after relaunch") {
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
}
step("Assert previously discovered tokens still appear in the assets list") {
onMainScreen {
EXPECTED_DISCOVERED_TOKENS.forEach { token ->
tokenRowWithTitle(token).assertIsDisplayed()
}
}
}
step("Assert zero-balance and spam tokens are NOT shown in the assets list") {
onMainScreen {
TOKENS_THAT_MUST_NOT_APPEAR.forEach { token ->
assertTokenDoesNotExist(token)
}
}
}
}
}
@AllureId("9284")
@DisplayName("Hot wallet: token added manually during Discovery — no duplicate created")
@Test
fun manualTokenAddDuringDiscoveryNoDuplicateTest() {
val tetherTitle = "Tether"
val ethereumNetworkTitle = "ETHEREUM"
val accountName = getResourceString(CoreUiR.string.account_main_account_title)
val expectedTokensCount = 4
setupHooks(
additionalBeforeAppLaunchSection = {
setWireMockScenarioState(PROVIDERS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_REDIRECT)
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_STARTED)
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_ASSETS_DISCOVERY_HAPPY_PATH)
setWireMockScenarioState(WALLET_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
setWireMockScenarioState(
MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO,
state = SCENARIO_STATE_NON_ZERO_EVM_BALANCES_SLOW,
)
},
additionalAfterSection = {
resetWireMockScenarioState(PROVIDERS_API_SCENARIO)
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(WALLET_TOKENS_API_SCENARIO)
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
},
).run {
step("Import a new hot wallet from seed phrase") {
openMainScreenWithExistingHotWallet(SEED_PHRASE_HAPPY_PATH)
}
step("Assert 'Restoring' progress loader is shown (discovery is in flight)") {
onMainScreen { restoringProgressText.assertIsDisplayed() }
}
step("Open wallet details from top bar") {
onMainScreenTopBar { moreButton.clickWithAssertion() }
}
step("Open 'Wallet settings'") {
onDetailsScreen { walletNameButton.performClick() }
}
step("Open account: '$accountName'") {
onWalletSettingsScreen { accountItem(accountName).performClick() }
}
step("Open 'Manage Tokens' from account details") {
onAccountDetailsScreen { manageTokensButton.performClick() }
}
step("Search for '$tetherTitle' in Manage Tokens") {
onManageTokensScreen {
searchField.performClick()
searchField.performTextInput(tetherTitle)
}
device.uiDevice.pressBack()
waitForIdle()
}
step("Expand '$tetherTitle'") {
onManageTokensScreen { tokenItem(tetherTitle).clickWithAssertion() }
waitForIdle()
}
step("Enable the $ethereumNetworkTitle network") {
onManageTokensScreen { networkSwitch(ethereumNetworkTitle).clickWithAssertion() }
}
step("Save Manage Tokens changes") {
onManageTokensScreen { saveButton.clickWithAssertion() }
waitForIdle()
}
step("Navigate back to main screen") {
repeat(times = 3) {
device.uiDevice.pressBack()
waitForIdle()
}
}
step("Wait for 'Wallet successfully imported' banner (discovery completes after delay)") {
flakySafely(timeoutMs = DISCOVERY_TIMEOUT_MILLIS) {
onMainScreen { walletImportedBanner.assertIsDisplayed() }
}
}
step("Assert '$tetherTitle' is in the assets list (manual add + discovery merged)") {
onMainScreen { tokenRowWithTitle(tetherTitle).assertIsDisplayed() }
}
step("Assert assets list contains exactly $expectedTokensCount tokens (no duplicate after merge)") {
onMainScreen { assertTokensCount(expectedTokensCount) }
}
}
}
@AllureId("9282")
@DisplayName("Hot wallet: re-import existing wallet — 200 OK, no Discovery, tokens from backend")
@Test
fun reimportExistingHotWalletTest() {
setupHooks(
additionalBeforeAppLaunchSection = {
setWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO, state = SCENARIO_STATE_ALREADY_EXISTS)
setWireMockScenarioState(USER_TOKENS_API_SCENARIO, state = SCENARIO_STATE_STARTED)
setWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO, state = SCENARIO_STATE_EMPTY)
},
additionalAfterSection = {
resetWireMockScenarioState(CREATE_USER_WALLET_API_SCENARIO)
resetWireMockScenarioState(USER_TOKENS_API_SCENARIO)
resetWireMockScenarioState(MORALIS_EVM_TOKEN_BALANCES_API_SCENARIO)
},
).run {
step("Import an existing hot wallet from seed phrase") {
openMainScreenWithExistingHotWallet(SEED_PHRASE_12)
}
step("Assert tokens from backend are displayed immediately") {
BACKEND_PRE_POPULATED_TOKENS.forEach { token ->
onMainScreen { tokenRowWithTitle(token).assertIsDisplayed() }
}
}
step("Assert 'Restoring' loader is NOT displayed (discovery did not start)") {
onMainScreen { restoringProgressText.assertIsNotDisplayed() }
}
step("Assert 'Wallet successfully imported' banner is NOT displayed") {
onMainScreen { walletImportedBanner.assertIsNotDisplayed() }
}
}
}
}

View file

@ -210,6 +210,17 @@
android:scheme="tangem" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="survey"
android:scheme="tangem" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

View file

@ -5,6 +5,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.SignIn
import com.tangem.domain.card.analytics.IntroductionProcess
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
class HotWalletContextInterceptor(
val parent: ParamsInterceptor? = null,
@ -18,6 +19,7 @@ class HotWalletContextInterceptor(
is SignIn.ButtonAddWallet,
is SignIn.ButtonUnlockAllWithBiometric,
is IntroductionProcess.ButtonScanCard,
is TokenScreenAnalyticsEvent.ButtonQuickTopUp,
-> false
is SignIn.ErrorBiometricUpdated -> !event.isFromUnlockAll
else -> true

View file

@ -6,6 +6,8 @@ import android.net.Uri
import androidx.core.net.toUri
import com.tangem.common.routing.DeepLinkScheme
import com.tangem.common.uri.ExternalUrlValidator
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.core.navigation.deeplink.DeeplinkLauncher
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.utils.logging.TangemLogger
@ -17,6 +19,7 @@ import com.tangem.utils.logging.TangemLogger
internal class DefaultDeeplinkLauncher(
private val context: Context,
private val urlOpener: UrlOpener,
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
) : DeeplinkLauncher {
override fun launch(link: String) {
@ -58,11 +61,33 @@ internal class DefaultDeeplinkLauncher(
}
private fun launchDeepLink(uri: Uri) {
context.startActivity(createDeepLinkIntent(uri))
val intent = createDeepLinkIntent(uri)
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
TangemLogger.i(
"""
No match found for deep link
|- Received URI: $uri
""".trimIndent(),
)
analyticsExceptionHandler.sendException(
ExceptionAnalyticsEvent(
exception = UnresolvedDeeplinkException(uri),
params = mapOf(
"uri_scheme" to uri.scheme.orEmpty(),
"uri_host" to uri.host.orEmpty(),
),
),
)
}
}
private fun createDeepLinkIntent(uri: Uri): Intent = Intent(Intent.ACTION_VIEW, uri).apply {
setPackage(context.packageName)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
}
internal class UnresolvedDeeplinkException(uri: Uri) :
RuntimeException("Deeplink has no matching activity: scheme=${uri.scheme}, host=${uri.host}")

View file

@ -1,6 +1,7 @@
package com.tangem.tap.di
import android.content.Context
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.tap.common.deeplink.DefaultDeeplinkLauncher
import com.tangem.core.navigation.deeplink.DeeplinkLauncher
import com.tangem.core.navigation.finisher.AppFinisher
@ -55,7 +56,10 @@ internal interface UtilsModule {
@Provides
@Singleton
fun provideDeeplinkLauncher(@ApplicationContext context: Context, urlOpener: UrlOpener): DeeplinkLauncher =
DefaultDeeplinkLauncher(context, urlOpener)
fun provideDeeplinkLauncher(
@ApplicationContext context: Context,
urlOpener: UrlOpener,
analyticsExceptionHandler: AnalyticsExceptionHandler,
): DeeplinkLauncher = DefaultDeeplinkLauncher(context, urlOpener, analyticsExceptionHandler)
}
}

View file

@ -21,6 +21,7 @@ import com.tangem.features.feed.entry.components.FeedEntryRoute
import com.tangem.features.home.api.HomeComponent
import com.tangem.features.hotwallet.*
import com.tangem.features.kyc.KycComponent
import com.tangem.features.survey.SurveyComponent
import com.tangem.features.managetokens.component.ChooseManagedTokensComponent
import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.managetokens.component.ManageTokensMode
@ -112,6 +113,7 @@ internal class ChildFactory @Inject constructor(
private val tangemPayOnboardingComponentFactory: TangemPayOnboardingComponent.Factory,
private val tangemPayWalletOnboardingComponentFactory: TangemPayHotWalletOnboardingComponent.Factory,
private val kycComponentFactory: KycComponent.Factory,
private val surveyComponentFactory: SurveyComponent.Factory,
private val yieldSupplyEntryComponentFactory: YieldSupplyEntryComponent.Factory,
private val feedEntryComponentFactory: FeedEntryComponent.Factory,
private val addFundsComponentFactory: AddFundsComponent.Factory,
@ -216,6 +218,7 @@ internal class ChildFactory @Inject constructor(
userWalletId = route.userWalletId,
cryptoCurrency = route.currency,
source = route.source,
initialFiatAmount = route.initialFiatAmount,
),
componentFactory = onrampComponentFactory,
)
@ -701,6 +704,13 @@ internal class ChildFactory @Inject constructor(
componentFactory = kycComponentFactory,
)
}
is AppRoute.Survey -> {
createComponentChild(
context = context,
params = SurveyComponent.Params(token = route.token, displayId = route.displayId),
componentFactory = surveyComponentFactory,
)
}
is AppRoute.YieldSupplyEntry -> {
createComponentChild(
context = context,

View file

@ -19,6 +19,7 @@ import com.tangem.features.onramp.deeplink.SellDeepLinkHandler
import com.tangem.features.onramp.deeplink.SwapDeepLinkHandler
import com.tangem.features.send.v2.api.deeplink.SellRedirectDeepLinkHandler
import com.tangem.features.staking.api.deeplink.StakingDeepLinkHandler
import com.tangem.features.survey.deeplink.SurveyDeepLinkHandler
import com.tangem.features.tangempay.deeplink.OnboardVisaDeepLinkHandler
import com.tangem.features.tangempay.deeplink.TangemPayMainDeepLinkHandler
import com.tangem.features.tokendetails.deeplink.TokenDetailsDeepLinkHandler
@ -62,6 +63,7 @@ internal class DeepLinkFactory @Inject constructor(
private val newsDeepLink: NewsDeepLinkHandler.Factory,
private val earnDeepLink: EarnDeepLinkHandler.Factory,
private val yieldDeepLink: YieldDeepLinkHandler.Factory,
private val surveyDeepLink: SurveyDeepLinkHandler.Factory,
) {
private val permittedAppRoute = MutableStateFlow(false)
@ -175,6 +177,7 @@ internal class DeepLinkFactory @Inject constructor(
DeepLinkRoute.Earn.host -> earnDeepLink.create(queryParams)
DeepLinkRoute.Yield.host -> yieldDeepLink.create(coroutineScope, queryParams)
DeepLinkRoute.PayAppMain.host -> tangemPayMainDeepLink.create(coroutineScope, queryParams)
DeepLinkRoute.Survey.host -> surveyDeepLink.create(queryParams)
else -> {
TangemLogger.i(
"""

View file

@ -11,6 +11,7 @@ import com.tangem.features.feed.entry.deeplink.MarketsTokenExchangesDeepLinkHand
import com.tangem.features.feed.entry.deeplink.NewsDeepLinkHandler
import com.tangem.features.feed.entry.deeplink.NewsDetailsDeepLinkHandler
import com.tangem.features.feed.entry.deeplink.YieldDeepLinkHandler
import com.tangem.features.survey.deeplink.SurveyDeepLinkHandler
import com.tangem.features.onramp.deeplink.BuyDeepLinkHandler
import com.tangem.features.onramp.deeplink.OnrampDeepLinkHandler
import com.tangem.features.onramp.deeplink.SellDeepLinkHandler
@ -99,6 +100,10 @@ class DeepLinkFactoryTest {
every { create(any()) } returns mockk()
}
private val surveyDeepLinkFactory = mockk<SurveyDeepLinkHandler.Factory>(relaxed = true) {
every { create(any()) } returns mockk()
}
private val earnDeepLinkFactory = mockk<EarnDeepLinkHandler.Factory>(relaxed = true) {
every { create(any()) } returns mockk()
}
@ -140,6 +145,7 @@ class DeepLinkFactoryTest {
newsDeepLink = newsDeepLinkFactory,
earnDeepLink = earnDeepLinkFactory,
yieldDeepLink = yieldDeepLinkFactory,
surveyDeepLink = surveyDeepLinkFactory,
)
@OptIn(ExperimentalCoroutinesApi::class)