From 315d7c9d6cd78469149e98baf3aa17e588f51738 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jun 2025 12:06:26 +0300 Subject: [PATCH] Updated on 2026-08-14 --- app/build.gradle.kts | 16 +- .../kotlin/com/tangem/common/BaseTestCase.kt | 71 +++-- .../com/tangem/common/extensions/KNode.kt | 8 + .../tangem/common/extensions/TestDataUtils.kt | 9 - .../com/tangem/scenarios/MainPageScenario.kt | 27 -- .../scenarios/OpenMainScreenScenario.kt | 44 +++ .../kotlin/com/tangem/screens/DetailsPage.kt | 16 -- .../com/tangem/screens/DetailsTestScreen.kt | 51 ++++ .../com/tangem/screens/DisclaimerPage.kt | 9 - .../tangem/screens/DisclaimerTestScreen.kt | 17 ++ .../kotlin/com/tangem/screens/MainPage.kt | 9 - .../com/tangem/screens/MainTestScreen.kt | 11 + .../kotlin/com/tangem/screens/StoriesPage.kt | 10 - .../com/tangem/screens/StoriesTestScreen.kt | 32 +++ .../kotlin/com/tangem/screens/TestTopBar.kt | 16 ++ .../kotlin/com/tangem/screens/TopBarPage.kt | 9 - .../com/tangem/screens/WalletSettingsPage.kt | 13 - .../screens/WalletSettingsTestScreen.kt | 31 +++ .../com/tangem/tests/DetailsScreenTest.kt | 259 ++++++++++-------- .../kotlin/com/tangem/tests/MainScreenTest.kt | 21 ++ .../kotlin/com/tangem/tests/ScanErrorTest.kt | 56 ++-- .../kotlin/com/tangem/tests/StoriesTest.kt | 49 ++-- .../main/java/com/tangem/tap/MainActivity.kt | 6 +- domain/legacy/build.gradle.kts | 3 +- gradle/dependencies.toml | 10 +- 25 files changed, 482 insertions(+), 321 deletions(-) create mode 100644 app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/common/extensions/TestDataUtils.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/scenarios/MainPageScenario.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/scenarios/OpenMainScreenScenario.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/DetailsPage.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/DetailsTestScreen.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/DisclaimerPage.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/DisclaimerTestScreen.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/MainPage.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/MainTestScreen.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/StoriesPage.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/StoriesTestScreen.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/TestTopBar.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/TopBarPage.kt delete mode 100644 app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPage.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsTestScreen.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/tests/MainScreenTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 794229daee..18dfcd383d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -71,6 +71,10 @@ configurations.all { } } +configurations.androidTestImplementation { + exclude(module = "protobuf-lite") +} + dependencies { implementation(projects.domain.legacy) @@ -317,19 +321,13 @@ dependencies { testImplementation(deps.test.mockk) testImplementation(deps.test.truth) androidTestImplementation(deps.test.junit.android) - androidTestImplementation(deps.test.espresso){ - exclude(group = "com.google.protobuf", module = "protobuf-lite") //conflicting with firebasePerf - } + androidTestImplementation(deps.test.espresso) androidTestImplementation(deps.test.espresso.intents) - { - exclude(group = "com.google.protobuf", module = "protobuf-lite") //conflicting with firebasePerf - } + androidTestImplementation(deps.test.kaspresso) + androidTestImplementation(deps.test.kaspresso.compose) androidTestImplementation(deps.test.compose.junit) androidTestImplementation(deps.test.hamcrest) androidTestImplementation(deps.test.hilt) - androidTestImplementation(deps.test.ultron.android) - androidTestImplementation(deps.test.ultron.compose) - androidTestImplementation(deps.test.ultron.allure) kaptAndroidTest(deps.test.hilt.compiler) /** Chucker */ diff --git a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt index b028458c9b..d404225116 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt @@ -1,66 +1,77 @@ package com.tangem.common import android.Manifest +import android.content.Context +import android.util.Log +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.datastore.dataStoreFile +import androidx.test.espresso.intent.Intents +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.GrantPermissionRule -import com.atiurin.ultron.core.compose.config.UltronComposeConfig -import com.atiurin.ultron.core.compose.createUltronComposeRule -import com.atiurin.ultron.core.compose.listeners.ComposDebugListener -import com.atiurin.ultron.core.config.UltronCommonConfig -import com.atiurin.ultron.core.config.UltronConfig -import com.atiurin.ultron.core.test.UltronTest +import com.kaspersky.components.composesupport.config.withComposeSupport +import com.kaspersky.kaspresso.kaspresso.Kaspresso +import com.kaspersky.kaspresso.testcases.api.testcase.TestCase import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.sdk.api.TangemSdkManager import com.tangem.tap.MainActivity import dagger.hilt.android.testing.HiltAndroidRule import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking -import org.junit.BeforeClass import org.junit.Rule +import org.junit.rules.RuleChain +import org.junit.rules.TestRule +import org.junit.runner.RunWith import javax.inject.Inject -abstract class BaseTestCase : UltronTest() { +abstract class BaseTestCase : TestCase( + kaspressoBuilder = Kaspresso.Builder.withComposeSupport() +) { + @Inject lateinit var tangemSdkManager: TangemSdkManager @Inject lateinit var appPreferencesStore: AppPreferencesStore - @get:Rule(order = 0) - val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant( + private val hiltRule = HiltAndroidRule(this) + private val permissionRule = GrantPermissionRule.grant( Manifest.permission.POST_NOTIFICATIONS, - Manifest.permission.CAMERA + Manifest.permission.CAMERA, ) - @get:Rule(order = 1) - val hiltRule = HiltAndroidRule(this) + val composeTestRule = createAndroidComposeRule() - @get:Rule (order = 2) - val injectionRule = ApplicationInjectionExecutionRule() + @Rule + @JvmField + val ruleChain: TestRule = RuleChain + .outerRule(hiltRule) + .around(ApplicationInjectionExecutionRule()) + .around(permissionRule) + .around(composeTestRule) - @get:Rule(order = 3) - val composeRule = createUltronComposeRule() - - override val beforeTest: () -> Unit = { + protected fun setupHooks( + additionalBeforeSection: () -> Unit = {}, + additionalAfterSection: () -> Unit = {}, + ) = before { hiltRule.inject() + Intents.init() + additionalBeforeSection() + runBlocking { delay(INIT_DELAY) } - } - override val afterTest: () -> Unit = { + }.after { runBlocking { appPreferencesStore.editData { prefs -> prefs.clear() } } + + additionalAfterSection() + Intents.release() } companion object { - @BeforeClass - @JvmStatic - fun config() { - UltronConfig.applyRecommended() - UltronComposeConfig.applyRecommended() - UltronCommonConfig.addListener(ComposDebugListener()) - } - - private const val INIT_DELAY = 2000L + private const val INIT_DELAY = 1000L } + } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt b/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt new file mode 100644 index 0000000000..a7baa714a4 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/common/extensions/KNode.kt @@ -0,0 +1,8 @@ +package com.tangem.common.extensions + +import io.github.kakaocup.compose.node.element.KNode + +fun KNode.clickWithAssertion() { + assertIsDisplayed() + performClick() +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/common/extensions/TestDataUtils.kt b/app/src/androidTest/kotlin/com/tangem/common/extensions/TestDataUtils.kt deleted file mode 100644 index 671c7e4c60..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/common/extensions/TestDataUtils.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.common.extensions - -import androidx.test.platform.app.InstrumentationRegistry - -object TestDataUtils { - fun getResourceString(resourceId: Int): String { - return InstrumentationRegistry.getInstrumentation().targetContext.resources.getString(resourceId) - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/MainPageScenario.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/MainPageScenario.kt deleted file mode 100644 index 2513c160b0..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/scenarios/MainPageScenario.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.scenarios - -import com.atiurin.ultron.allure.step.step -import com.atiurin.ultron.extensions.assertIsDisplayed -import com.atiurin.ultron.extensions.click -import com.tangem.domain.models.scan.ProductType -import com.tangem.screens.DisclaimerPage -import com.tangem.screens.MainPage -import com.tangem.screens.StoriesPage -import com.tangem.tap.domain.sdk.mocks.MockProvider - -object MainPageScenario { - fun open(productType: ProductType? = null) { - if (productType != null) { - MockProvider.setMocks(productType) - } - step("Click on \"Accept\" button") { - DisclaimerPage.acceptButton.click() - } - step("Click on \"Scan\" button emulating scan error") { - StoriesPage.scanButton.click() - } - step("Assert: main is displayed") { - MainPage.container.assertIsDisplayed() - } - } -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/scenarios/OpenMainScreenScenario.kt b/app/src/androidTest/kotlin/com/tangem/scenarios/OpenMainScreenScenario.kt new file mode 100644 index 0000000000..cd966f6a0f --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/scenarios/OpenMainScreenScenario.kt @@ -0,0 +1,44 @@ +package com.tangem.scenarios + +import androidx.compose.ui.test.junit4.ComposeTestRule +import com.kaspersky.kaspresso.testcases.api.scenario.Scenario +import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.domain.models.scan.ProductType +import com.tangem.screens.DisclaimerTestScreen +import com.tangem.screens.MainTestScreen +import com.tangem.screens.StoriesTestScreen +import com.tangem.screens.TestTopBar +import com.tangem.tap.domain.sdk.mocks.MockProvider +import io.github.kakaocup.compose.node.element.ComposeScreen + +class OpenMainScreenScenario( + private val testRule: ComposeTestRule, + private val productType: ProductType? = null, +) : Scenario() { + override val steps: TestContext.() -> Unit = { + if (productType != null) { + MockProvider.setMocks(productType) + } + ComposeScreen.onComposeScreen(testRule) { + step("Click on \"Accept\" button") { + acceptButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(testRule) { + step("Click on \"Scan\" button") { + scanButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(testRule) { + step("Make sure wallet screen is visible") { + assertIsDisplayed() + } + } + ComposeScreen.onComposeScreen(testRule) { + step("Close Markets tooltip"){ + performClick() + } + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DetailsPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/DetailsPage.kt deleted file mode 100644 index 990f09205c..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/DetailsPage.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasText -import com.atiurin.ultron.page.Page -import com.tangem.common.extensions.TestDataUtils.getResourceString -import com.tangem.wallet.R - -object DetailsPage : Page() { - val walletConnectButton = hasText(getResourceString(R.string.wallet_connect_title)) - val walletNameButton = hasText(getResourceString(R.string.manage_tokens_network_selector_wallet)) - val scanCardButton = hasText(getResourceString(R.string.scan_card_settings_button)) - val buyTangemButton = hasText(getResourceString(R.string.details_buy_wallet)) - val appSettingsButton = hasText(getResourceString(R.string.app_settings_title)) - val contactSupportButton = hasText(getResourceString(R.string.details_row_title_contact_to_support)) - val toSButton = hasText(getResourceString(R.string.disclaimer_title)) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DetailsTestScreen.kt b/app/src/androidTest/kotlin/com/tangem/screens/DetailsTestScreen.kt new file mode 100644 index 0000000000..528989a4e3 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/DetailsTestScreen.kt @@ -0,0 +1,51 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import com.tangem.wallet.R +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.compose.node.element.KNode +import io.github.kakaocup.kakao.common.utilities.getResourceString + +class DetailsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.DETAILS_SCREEN) } + ) { + + val walletConnectButton: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + hasText(getResourceString(R.string.wallet_connect_title)) + } + + private val walletBlock: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + } + + val walletNameButton: KNode = walletBlock.child { + hasClickAction() + hasPosition(0) + } + + val scanCardButton: KNode = walletBlock.child { + hasText(getResourceString(R.string.scan_card_settings_button)) + } + + val buyTangemButton: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + hasText(getResourceString(R.string.details_buy_wallet)) + } + + val appSettingsButton: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + hasText(getResourceString(R.string.app_settings_title)) + } + val contactSupportButton: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + hasText(getResourceString(R.string.details_row_title_contact_to_support)) + } + val toSButton: KNode = child { + hasTestTag(TestTags.DETAILS_SCREEN_ITEM) + hasText(getResourceString(R.string.disclaimer_title)) + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerPage.kt deleted file mode 100644 index b8dbd41150..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerPage.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasTestTag -import com.atiurin.ultron.page.Page -import com.tangem.core.ui.test.TestTags - -object DisclaimerPage : Page() { - val acceptButton = hasTestTag(TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerTestScreen.kt b/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerTestScreen.kt new file mode 100644 index 0000000000..4af7f33d51 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/DisclaimerTestScreen.kt @@ -0,0 +1,17 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.compose.node.element.KNode + +class DisclaimerTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.DISCLAIMER_SCREEN_CONTAINER) } + ) { + + val acceptButton: KNode = child { + hasTestTag(TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON) + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MainPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/MainPage.kt deleted file mode 100644 index f9016b3f69..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/MainPage.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasTestTag -import com.atiurin.ultron.page.Page -import com.tangem.core.ui.test.TestTags - -object MainPage : Page() { - val container = hasTestTag(TestTags.MAIN_SCREEN) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/MainTestScreen.kt b/app/src/androidTest/kotlin/com/tangem/screens/MainTestScreen.kt new file mode 100644 index 0000000000..a342754478 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/MainTestScreen.kt @@ -0,0 +1,11 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import io.github.kakaocup.compose.node.element.ComposeScreen + +class MainTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN) } + ) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/StoriesPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/StoriesPage.kt deleted file mode 100644 index 51f472521a..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/StoriesPage.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasTestTag -import com.atiurin.ultron.page.Page -import com.tangem.core.ui.test.TestTags - -object StoriesPage : Page() { - val scanButton = hasTestTag(TestTags.STORIES_SCREEN_SCAN_BUTTON) - val orderButton = hasTestTag(TestTags.STORIES_SCREEN_ORDER_BUTTON) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/StoriesTestScreen.kt b/app/src/androidTest/kotlin/com/tangem/screens/StoriesTestScreen.kt new file mode 100644 index 0000000000..9dd1a415e9 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/StoriesTestScreen.kt @@ -0,0 +1,32 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import com.tangem.wallet.R +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.compose.node.element.KNode +import io.github.kakaocup.kakao.common.views.KView +import io.github.kakaocup.kakao.text.KButton + +class StoriesTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.STORIES_SCREEN) } + ) { + + val scanButton: KNode = child { + hasTestTag(TestTags.STORIES_SCREEN_SCAN_BUTTON) + } + + val orderButton: KNode = child { + hasTestTag(TestTags.STORIES_SCREEN_ORDER_BUTTON) + } + + val enableNFCAlert: KView = KView { + withId(R.id.alertTitle) + } + + val cancelButton: KButton = KButton { + withId(android.R.id.button2) + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/TestTopBar.kt b/app/src/androidTest/kotlin/com/tangem/screens/TestTopBar.kt new file mode 100644 index 0000000000..83d2e8a6a9 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/TestTopBar.kt @@ -0,0 +1,16 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.compose.node.element.KNode + +class TestTopBar(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.MAIN_SCREEN_TOP_BAR) } + ) { + val moreButton: KNode = child { + hasTestTag(TestTags.MAIN_SCREEN_MORE_BUTTON) + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/TopBarPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/TopBarPage.kt deleted file mode 100644 index 2505ffae8b..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/TopBarPage.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasTestTag -import com.atiurin.ultron.page.Page -import com.tangem.core.ui.test.TestTags - -object TopBarPage : Page() { - val moreButton = hasTestTag(TestTags.MAIN_SCREEN_MORE_BUTTON) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPage.kt b/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPage.kt deleted file mode 100644 index a38559a523..0000000000 --- a/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsPage.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.tangem.screens - -import androidx.compose.ui.test.hasText -import com.atiurin.ultron.page.Page -import com.tangem.common.extensions.TestDataUtils.getResourceString -import com.tangem.wallet.R - -object WalletSettingsPage : Page() { - val linkMoreCardsButton = hasText(getResourceString(R.string.details_row_title_create_backup)) - val cardSettingsButton = hasText(getResourceString(R.string.card_settings_title)) - val referralProgramButton = hasText(getResourceString(R.string.details_referral_title)) - val forgetWalletButton = hasText(getResourceString(R.string.settings_forget_wallet)) -} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsTestScreen.kt b/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsTestScreen.kt new file mode 100644 index 0000000000..1b31bd509c --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/screens/WalletSettingsTestScreen.kt @@ -0,0 +1,31 @@ +package com.tangem.screens + +import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import com.tangem.core.ui.test.TestTags +import com.tangem.wallet.R +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.compose.node.element.KNode +import io.github.kakaocup.kakao.common.utilities.getResourceString + +class WalletSettingsTestScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : + ComposeScreen( + semanticsProvider = semanticsProvider, + viewBuilderAction = { hasTestTag(TestTags.WALLET_SETTINGS_SCREEN) } + ) { + private val walletSettingsItem: KNode = child { + hasTestTag(TestTags.WALLET_SETTINGS_SCREEN_ITEM) + } + + val linkMoreCardsButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.details_row_title_create_backup)) + } + val cardSettingsButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.card_settings_title)) + } + val referralProgramButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.details_referral_title)) + } + val forgetWalletButton: KNode = walletSettingsItem.child { + hasText(getResourceString(R.string.settings_forget_wallet)) + } +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/DetailsScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/DetailsScreenTest.kt index 1951caf4d7..dd86a046cc 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/DetailsScreenTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/DetailsScreenTest.kt @@ -1,138 +1,157 @@ package com.tangem.tests -import com.atiurin.ultron.allure.step.step -import com.atiurin.ultron.extensions.assertIsDisplayed -import com.atiurin.ultron.extensions.assertIsNotDisplayed -import com.atiurin.ultron.extensions.click import com.tangem.common.BaseTestCase +import com.tangem.common.extensions.clickWithAssertion import com.tangem.domain.models.scan.ProductType -import com.tangem.scenarios.MainPageScenario -import com.tangem.screens.DetailsPage -import com.tangem.screens.TopBarPage -import com.tangem.screens.WalletSettingsPage +import com.tangem.scenarios.OpenMainScreenScenario +import com.tangem.screens.DetailsTestScreen +import com.tangem.screens.TestTopBar +import com.tangem.screens.WalletSettingsTestScreen import dagger.hilt.android.testing.HiltAndroidTest +import io.github.kakaocup.compose.node.element.ComposeScreen import org.junit.Test @HiltAndroidTest class DetailsScreenTest : BaseTestCase() { @Test - fun walletWithoutBackupDetails() { - MainPageScenario.open() - step("Open wallet details") { - TopBarPage.moreButton.click() + fun walletWithoutBackupDetails() = + setupHooks().run { + scenario(OpenMainScreenScenario(composeTestRule)) + ComposeScreen.onComposeScreen(composeTestRule) { + step("Open wallet details") { + moreButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert wallet connect button is visible") { + walletConnectButton.assertIsDisplayed() + } + step("Assert scan card button is visible") { + scanCardButton.assertIsDisplayed() + } + step("Assert buy Tangem card button is visible") { + buyTangemButton.assertIsDisplayed() + } + step("Assert app settings button is visible") { + appSettingsButton.assertIsDisplayed() + } + step("Assert contact support button is visible") { + contactSupportButton.assertIsDisplayed() + } + step("Assert terms or service button is visible") { + toSButton.assertIsDisplayed() + } + step("Open wallet settings screen") { + walletNameButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert Link more cards button is visible") { + linkMoreCardsButton.assertIsDisplayed() + } + step("Assert Card Settings button is visible") { + cardSettingsButton.assertIsDisplayed() + } + step("Assert Referral program button is visible") { + referralProgramButton.assertIsDisplayed() + } + step("Assert Forget wallet button is visible") { + forgetWalletButton.assertIsDisplayed() + } + } } - step("Assert wallet connect button is visible") { - DetailsPage.walletConnectButton.assertIsDisplayed() - } - step("Assert scan card button is visible") { - DetailsPage.scanCardButton.assertIsDisplayed() - } - step("Assert buy Tangem card button is visible") { - DetailsPage.buyTangemButton.assertIsDisplayed() - } - step("Assert app settings button is visible") { - DetailsPage.appSettingsButton.assertIsDisplayed() - } - step("Assert contact support button is visible") { - DetailsPage.contactSupportButton.assertIsDisplayed() - } - step("Assert terms or service button is visible") { - DetailsPage.toSButton.assertIsDisplayed() - } - step("Open wallet settings screen") { - DetailsPage.walletNameButton.click() - } - step("Assert Link more cards button is visible") { - WalletSettingsPage.linkMoreCardsButton.assertIsDisplayed() - } - step("Assert Card Settings button is visible") { - WalletSettingsPage.cardSettingsButton.assertIsDisplayed() - } - step("Assert Referral program button is visible") { - WalletSettingsPage.referralProgramButton.assertIsDisplayed() - } - step("Assert Forget wallet button is visible") { - WalletSettingsPage.forgetWalletButton.assertIsDisplayed() - } - } @Test - fun wallet2Details() { - MainPageScenario.open(ProductType.Wallet2) - step("Open wallet details") { - TopBarPage.moreButton.click() + fun wallet2Details() = + setupHooks().run { + scenario(OpenMainScreenScenario(composeTestRule, ProductType.Wallet2)) + ComposeScreen.onComposeScreen(composeTestRule) { + step("Open wallet details") { + moreButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert wallet connect button is visible") { + walletConnectButton.assertIsDisplayed() + } + step("Assert scan card button is visible") { + scanCardButton.assertIsDisplayed() + } + step("Assert buy Tangem card button is visible") { + buyTangemButton.assertIsDisplayed() + } + step("Assert app settings button is visible") { + appSettingsButton.assertIsDisplayed() + } + step("Assert contact support button is visible") { + contactSupportButton.assertIsDisplayed() + } + step("Assert terms or service button is visible") { + toSButton.assertIsDisplayed() + } + step("Open wallet settings screen") { + walletNameButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert Link more cards button does not exist") { + linkMoreCardsButton.assertIsNotDisplayed() + } + step("Assert Card Settings button is visible") { + cardSettingsButton.assertIsDisplayed() + } + step("Assert Referral program button is visible") { + referralProgramButton.assertIsDisplayed() + } + step("Assert Forget wallet button is visible") { + forgetWalletButton.assertIsDisplayed() + } + } } - step("Assert wallet connect button is visible") { - DetailsPage.walletConnectButton.assertIsDisplayed() - } - step("Assert scan card button is visible") { - DetailsPage.scanCardButton.assertIsDisplayed() - } - step("Assert buy Tangem card button is visible") { - DetailsPage.buyTangemButton.assertIsDisplayed() - } - step("Assert app settings button is visible") { - DetailsPage.appSettingsButton.assertIsDisplayed() - } - step("Assert contact support button is visible") { - DetailsPage.contactSupportButton.assertIsDisplayed() - } - step("Assert terms or service button is visible") { - DetailsPage.toSButton.assertIsDisplayed() - } - step("Open wallet settings screen") { - DetailsPage.walletNameButton.click() - } - step("Assert Link more cards button does not exist") { - WalletSettingsPage.linkMoreCardsButton.assertIsNotDisplayed() - } - step("Assert Card Settings button is visible") { - WalletSettingsPage.cardSettingsButton.assertIsDisplayed() - } - step("Assert Referral program button is visible") { - WalletSettingsPage.referralProgramButton.assertIsDisplayed() - } - step("Assert Forget wallet button is visible") { - WalletSettingsPage.forgetWalletButton.assertIsDisplayed() - } - } @Test - fun noteDetails() { - MainPageScenario.open(ProductType.Note) - step("Open wallet details") { - TopBarPage.moreButton.click() + fun noteDetails() = + setupHooks().run { + scenario(OpenMainScreenScenario(composeTestRule, ProductType.Note)) + ComposeScreen.onComposeScreen(composeTestRule) { + step("Open wallet details") { + moreButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert wallet connect button does not exist") { + walletConnectButton.assertIsNotDisplayed() + } + step("Assert scan card button is visible") { + scanCardButton.assertIsDisplayed() + } + step("Assert buy Tangem card button is visible") { + buyTangemButton.assertIsDisplayed() + } + step("Assert app settings button is visible") { + appSettingsButton.assertIsDisplayed() + } + step("Assert contact support button is visible") { + contactSupportButton.assertIsDisplayed() + } + step("Assert terms or service button is visible") { + toSButton.assertIsDisplayed() + } + step("Open wallet settings screen") { + walletNameButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Assert Card Settings button is visible") { + cardSettingsButton.assertIsDisplayed() + } + step("Assert Referral program button does not exist") { + referralProgramButton.assertIsNotDisplayed() + } + step("Assert Forget wallet button is visible") { + forgetWalletButton.assertIsDisplayed() + } + } } - step("Assert wallet connect button does not exist") { - DetailsPage.walletConnectButton.assertIsNotDisplayed() - } - step("Assert scan card button is visible") { - DetailsPage.scanCardButton.assertIsDisplayed() - } - step("Assert buy Tangem card button is visible") { - DetailsPage.buyTangemButton.assertIsDisplayed() - } - step("Assert app settings button is visible") { - DetailsPage.appSettingsButton.assertIsDisplayed() - } - step("Assert contact support button is visible") { - DetailsPage.contactSupportButton.assertIsDisplayed() - } - step("Assert terms or service button is visible") { - DetailsPage.toSButton.assertIsDisplayed() - } - step("Open wallet settings screen") { - DetailsPage.walletNameButton.click() - } - step("Assert Card Settings button is visible") { - WalletSettingsPage.cardSettingsButton.assertIsDisplayed() - } - step("Assert Referral program button does not exist") { - WalletSettingsPage.referralProgramButton.assertIsNotDisplayed() - } - step("Assert Forget wallet button is visible") { - WalletSettingsPage.forgetWalletButton.assertIsDisplayed() - } - } -} +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/MainScreenTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/MainScreenTest.kt new file mode 100644 index 0000000000..fd3a2df953 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/tests/MainScreenTest.kt @@ -0,0 +1,21 @@ +package com.tangem.tests + +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import com.tangem.common.BaseTestCase +import com.tangem.scenarios.OpenMainScreenScenario +import com.tangem.tap.MainActivity +import dagger.hilt.android.testing.HiltAndroidTest +import org.junit.Rule +import org.junit.Test + +@HiltAndroidTest +class MainScreenTest : BaseTestCase() { + + @Test + fun goToMain() { + setupHooks().run { + scenario(OpenMainScreenScenario(composeTestRule)) + } + } + +} \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt index de198088d3..da686950a7 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/ScanErrorTest.kt @@ -1,42 +1,40 @@ package com.tangem.tests -import com.atiurin.ultron.allure.step.step -import com.atiurin.ultron.extensions.assertIsDisplayed -import com.atiurin.ultron.extensions.assertIsNotDisplayed -import com.atiurin.ultron.extensions.click import com.tangem.common.BaseTestCase -import com.tangem.screens.DisclaimerPage -import com.tangem.screens.MainPage -import com.tangem.screens.StoriesPage +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.screens.DisclaimerTestScreen +import com.tangem.screens.MainTestScreen +import com.tangem.screens.StoriesTestScreen import com.tangem.tap.domain.sdk.mocks.MockProvider import dagger.hilt.android.testing.HiltAndroidTest +import io.github.kakaocup.compose.node.element.ComposeScreen import org.junit.Test @HiltAndroidTest class ScanErrorTest : BaseTestCase() { @Test - fun goToMain() { - step("Click on \"Accept\" button") { - DisclaimerPage.acceptButton.click() + fun goToMain() = + setupHooks().run { + ComposeScreen.onComposeScreen(composeTestRule) { + step("Click on \"Accept\" button") { + acceptButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Click on \"Scan\" button emulating scan error") { + MockProvider.setEmulateError() + scanButton.clickWithAssertion() + } + step("Click on \"Scan\" button again without emulating error") { + MockProvider.resetEmulateError() + scanButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Make sure wallet screen is visible") { + assertIsDisplayed() + } + } } - step("Emulate scan error") { - MockProvider.setEmulateError() - } - step("Click on \"Scan\" button emulating scan error") { - StoriesPage.scanButton.click() - } - step("Assert: Error is displayed") { - MainPage.container.assertIsNotDisplayed() - } - step("Emulate success scan") { - MockProvider.resetEmulateError() - } - step("Click on \"Scan\" button") { - StoriesPage.scanButton.click() - } - step("Assert: wallet screen is displayed") { - MainPage.container.assertIsDisplayed() - } - } } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt b/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt index 5adaaeada1..eab4389f6b 100644 --- a/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt +++ b/app/src/androidTest/kotlin/com/tangem/tests/StoriesTest.kt @@ -1,36 +1,41 @@ package com.tangem.tests import android.content.Intent.ACTION_VIEW -import androidx.test.espresso.intent.Intents -import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction -import androidx.test.espresso.intent.matcher.IntentMatchers.hasData -import com.atiurin.ultron.allure.step.step -import com.atiurin.ultron.core.config.UltronConfig.UiAutomator.Companion.uiDevice -import com.atiurin.ultron.extensions.click +import androidx.test.espresso.intent.matcher.UriMatchers import com.tangem.common.BaseTestCase -import com.tangem.screens.DisclaimerPage -import com.tangem.screens.StoriesPage +import com.tangem.common.extensions.clickWithAssertion +import com.tangem.screens.DisclaimerTestScreen +import com.tangem.screens.StoriesTestScreen import com.tangem.tap.features.home.redux.HomeMiddleware.NEW_BUY_WALLET_URL import dagger.hilt.android.testing.HiltAndroidTest -import org.hamcrest.core.AllOf.allOf +import io.github.kakaocup.compose.node.element.ComposeScreen +import io.github.kakaocup.kakao.intent.KIntent +import org.hamcrest.Matchers import org.junit.Test @HiltAndroidTest class StoriesTest : BaseTestCase() { @Test - fun checkOrderButton() { - Intents.init() - step("Click Accept on ToS") { - DisclaimerPage.acceptButton.click() + fun clickOnOrderButton() = + setupHooks().run { + ComposeScreen.onComposeScreen(composeTestRule) { + step("Click on \"Accept\" button") { + acceptButton.clickWithAssertion() + } + } + ComposeScreen.onComposeScreen(composeTestRule) { + step("Click on \"Order\" button") { + orderButton.clickWithAssertion() + } + step("Assert: browser opened") { + val expectedIntent = KIntent { + hasAction(ACTION_VIEW) + hasData { toString().startsWith(NEW_BUY_WALLET_URL) } + } + expectedIntent.intended() + device.uiDevice.pressBack() + } + } } - step("Click order button ") { - StoriesPage.orderButton.click() - } - step("Assert: browser is opened ") { - Intents.intended(allOf(hasAction(ACTION_VIEW), hasData(NEW_BUY_WALLET_URL))) - uiDevice.pressBack() - Intents.release() - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 557f69fdd0..3a4577ab02 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -77,6 +77,7 @@ import com.tangem.tap.routing.utils.DeepLinkFactory import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler import com.tangem.utils.extensions.uriValidate +import com.tangem.wallet.BuildConfig import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -353,7 +354,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { intentProcessor.removeAll() // workaround: kill process when activity destroy to avoid state when lock() wallets // and navigation to unlock screen was skipped because system kills activity but not process - android.os.Process.killProcess(android.os.Process.myPid()) + if (BuildConfig.BUILD_TYPE != MOCKED_BUILD_TYPE) { + android.os.Process.killProcess(android.os.Process.myPid()) + } super.onDestroy() } @@ -556,5 +559,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder { companion object { private const val APP_THEME_LOAD_TIMEOUT = 2 + private const val MOCKED_BUILD_TYPE = "mocked" } } \ No newline at end of file diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index e109af45b0..1326610ec7 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -52,6 +52,5 @@ dependencies { testImplementation(deps.test.mockk) testImplementation(deps.test.truth) testImplementation(projects.common.test) - androidTestImplementation(deps.test.junit.android) - androidTestImplementation(deps.test.espresso) + } \ No newline at end of file diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 2473ea55b9..0839acc10f 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -107,9 +107,8 @@ junitAndroidExt = "1.1.5" mockk = "1.13.4" turbine = "1.2.0" truth = "1.1.3" -ultron-android = "2.5.4" -ultron-compose = "2.5.4" -ultron-allure ="2.5.4" +kaspresso = "1.5.4" +kaspresso-compose = "1.5.4" compose-junit = "1.6.2" hamcrest = "2.2" # endregion Testing @@ -207,9 +206,8 @@ test-junit-android = { module = "androidx.test.ext:junit", version.ref = "junitA test-truth = { module = "com.google.truth:truth", version.ref = "truth" } test-mockk = { module = "io.mockk:mockk", version.ref = "mockk" } test-turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } -test-ultron-android = { module = "com.atiurin:ultron-android", version.ref = "ultron-android" } -test-ultron-compose = { module = "com.atiurin:ultron-compose", version.ref = "ultron-compose" } -test-ultron-allure = { module = "com.atiurin:ultron-allure", version.ref = "ultron-allure" } +test-kaspresso = { module = "com.kaspersky.android-components:kaspresso", version.ref = "kaspresso" } +test-kaspresso-compose = { module = "com.kaspersky.android-components:kaspresso-compose-support", version.ref = "kaspresso-compose" } test-compose-junit = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "compose-junit" } test-hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } test-hilt = { module = "com.google.dagger:hilt-android-testing", version.ref = "hilt" }