Updated on 2026-08-14
This commit is contained in:
parent
3bde764060
commit
4e1b562e82
20 changed files with 690 additions and 19 deletions
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.common
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.ui.test.isRoot
|
||||
import androidx.compose.ui.test.junit4.createEmptyComposeRule
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.compose.ui.test.printToLog
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.espresso.intent.Intents
|
||||
|
|
@ -121,6 +121,8 @@ abstract class BaseTestCase : TestCase(
|
|||
/**
|
||||
* Prints the Compose semantics tree to logcat for debugging UI tests.
|
||||
*
|
||||
* @param rootIndex Use rootIndex > 0, if you need to print semantics tree for bottom sheet.
|
||||
* Default: 0.
|
||||
* @param useUnmergedTree When true, shows unmerged tree with all individual nodes.
|
||||
* Use for accessing inner elements of compound components.
|
||||
* Default: false (merged tree - accessibility view).
|
||||
|
|
@ -129,11 +131,13 @@ abstract class BaseTestCase : TestCase(
|
|||
* Default: Int.MAX_VALUE (unlimited depth).
|
||||
*/
|
||||
fun printSemanticTree(
|
||||
rootIndex: Int = 0,
|
||||
useUnmergedTree: Boolean = false,
|
||||
tag: String = "SEMANTIC_TREE",
|
||||
maxDepth: Int = Int.MAX_VALUE)
|
||||
{
|
||||
composeTestRule.onRoot(useUnmergedTree = useUnmergedTree).printToLog(tag, maxDepth)
|
||||
maxDepth: Int = Int.MAX_VALUE
|
||||
) {
|
||||
composeTestRule.onAllNodes(isRoot(), useUnmergedTree = useUnmergedTree)[rootIndex]
|
||||
.printToLog(tag, maxDepth)
|
||||
}
|
||||
|
||||
fun waitForIdle() = composeTestRule.waitForIdle()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ object TestConstants {
|
|||
const val TOTAL_BALANCE = "$3,299.18"
|
||||
|
||||
const val RECIPIENT_ADDRESS = "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"
|
||||
const val BITCOIN_ADDRESS = "bc1qtg9aa6jcpqtvun0pe0uct7sxm8nq2nsxfmfxm3"
|
||||
const val CARDANO_ADDRESS = "addr1q8f9499e58k4hhfd9vhawprxt3xd94x7rmlyp33ee4xkatakcl2zgkrg0p6ceqkndtkw4cumfe9enhdph8yhuswn785srksm9p"
|
||||
|
||||
const val WAIT_UNTIL_TIMEOUT = 20_000L
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.common.utils
|
|||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
|
||||
fun getClipboardText(context: Context): String? {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
|
|
@ -17,4 +18,21 @@ fun setClipboardText(context: Context, text: String?) {
|
|||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText("label", text)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
}
|
||||
|
||||
fun clearClipboard(
|
||||
context: Context = ApplicationProvider.getApplicationContext()
|
||||
) {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.clearPrimaryClip()
|
||||
}
|
||||
|
||||
fun assertClipboardTextEquals(
|
||||
expected: String,
|
||||
context: Context = ApplicationProvider.getApplicationContext()
|
||||
) {
|
||||
val actual = getClipboardText(context)
|
||||
assert(actual == expected) {
|
||||
"Clipboard text mismatch.\nExpected: '$expected'\nActual: '$actual'"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import androidx.test.uiautomator.UiObject2
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.kaspersky.kaspresso.screens.KScreen
|
||||
|
||||
object ChromeBrowserPageObject : KScreen<ChromeBrowserPageObject>() {
|
||||
|
||||
override val layoutId: Int? = null
|
||||
override val viewClass: Class<*>? = null
|
||||
|
||||
private val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
private const val TIMEOUT = 10000L
|
||||
|
||||
fun assertChromeIsOpened() {
|
||||
val chromePackage = "com.android.chrome"
|
||||
device.wait(Until.hasObject(By.pkg(chromePackage).depth(0)), TIMEOUT)
|
||||
assert(device.hasObject(By.pkg(chromePackage))) {
|
||||
"Chrome browser is not opened"
|
||||
}
|
||||
}
|
||||
|
||||
fun assertUrlContains(expectedUrl: String) {
|
||||
val urlBar = device.findObject(
|
||||
By.res("com.android.chrome:id/url_bar")
|
||||
)
|
||||
urlBar?.let {
|
||||
assert(it.text.contains(expectedUrl)) {
|
||||
"URL doesn't contain expected: $expectedUrl, actual: ${it.text}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findElementByText(text: String): UiObject2? {
|
||||
device.wait(Until.hasObject(By.text(text)), TIMEOUT)
|
||||
return device.findObject(By.text(text))
|
||||
}
|
||||
|
||||
fun assertElementWithTextExists(text: String) {
|
||||
val element = findElementByText(text)
|
||||
assert(element != null) { "Element with text '$text' not found" }
|
||||
}
|
||||
|
||||
fun isElementWithTextExists(text: String): Boolean {
|
||||
return device.wait(Until.hasObject(By.text(text)), TIMEOUT)
|
||||
}
|
||||
|
||||
fun clickOnElementWithText(text: String) {
|
||||
findElementByText(text)?.click()
|
||||
?: throw AssertionError("Cannot click - element with text '$text' not found")
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import io.github.kakaocup.compose.node.element.lazylist.KLazyListNode
|
|||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<MainScreenPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -200,6 +201,10 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val snackbarCopiedAddressMessage: KNode = child {
|
||||
hasText(getResourceString(CoreUiR.string.wallet_notification_address_copied))
|
||||
}
|
||||
|
||||
/**
|
||||
* Find token list item with title and address
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,20 +3,19 @@ package com.tangem.screens
|
|||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class BaseBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<BaseBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
class ReceiveAssetsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<ReceiveAssetsBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val hideButton: KNode = child {
|
||||
hasText(getResourceString(R.string.token_details_hide_token))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_TITLE)
|
||||
val showQrCodeButton: KNode = child {
|
||||
hasText(getResourceString(R.string.token_receive_show_qr_code_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onBottomSheet(function: BaseBottomSheetPageObject.() -> Unit) =
|
||||
internal fun BaseTestCase.onReceiveAssetsBottomSheet(function: ReceiveAssetsBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -71,6 +71,10 @@ class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
hasText(getResourceString(R.string.common_swap))
|
||||
}
|
||||
|
||||
fun tokenSymbol(symbol: String): KNode = child {
|
||||
hasTestTag(SwapTokenScreenTestTags.TOKEN_SYMBOL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSwapTokenScreen(function: SwapTokenPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class TokenActionsBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<TokenActionsBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val analyticsButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_analytics)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val copyAddressButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_copy_address)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val receiveButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_receive)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val sendButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_send)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val swapButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_swap)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val buyButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_buy)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val sellButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.common_sell)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val hideTokenButton: KNode = child {
|
||||
hasAnyChild(withText(getResourceString(R.string.token_details_hide_token)))
|
||||
hasTestTag(BaseBottomSheetTestTags.ACTION_BUTTON)
|
||||
hasAnyChild(withTestTag(BaseBottomSheetTestTags.ACTION_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onTokenActionsBottomSheet(function: TokenActionsBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
||||
import com.tangem.wallet.R
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class TokenReceiveQrCodeBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<TokenReceiveQrCodeBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(BaseBottomSheetTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val qrCode: KNode = child {
|
||||
hasTestTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val addressTitle: KNode = child {
|
||||
hasText(getResourceString(R.string.wc_common_address))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val address: KNode = child {
|
||||
hasTestTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val copyButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_copy))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val shareButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_share))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onTokenReceiveQrCodeBottomSheet(function: TokenReceiveQrCodeBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onComposeScreen
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
|
||||
class TokenReceiveWarningBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<TokenReceiveWarningBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val bottomSheet: KNode = child {
|
||||
hasTestTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET)
|
||||
}
|
||||
|
||||
val gotItButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_got_it))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onTokenReceiveWarningBottomSheet(function: TokenReceiveWarningBottomSheetPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,405 @@
|
|||
package com.tangem.tests.actionButtons
|
||||
|
||||
import androidx.compose.ui.test.longClick
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.BITCOIN_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.assertClipboardTextEquals
|
||||
import com.tangem.common.utils.clearClipboard
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.onTokenActionsBottomSheet
|
||||
import com.tangem.screens.onBuyTokenDetailsScreen
|
||||
import com.tangem.screens.onDialog
|
||||
import com.tangem.screens.onMainScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class MainScreenActionButtonsTest : BaseTestCase() {
|
||||
|
||||
@AllureId("79")
|
||||
@DisplayName("Action buttons (long tap): validate UI")
|
||||
@Test
|
||||
fun actionButtonsValidateLongTapUiTest() {
|
||||
val tokenTitle = "Ethereum"
|
||||
val balance = TOTAL_BALANCE
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Analytics' button is displayed") {
|
||||
onTokenActionsBottomSheet { analyticsButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Copy address' button is displayed") {
|
||||
onTokenActionsBottomSheet { copyAddressButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Receive' button is displayed") {
|
||||
onTokenActionsBottomSheet { receiveButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' button is displayed") {
|
||||
onTokenActionsBottomSheet { sendButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Swap' button is displayed") {
|
||||
onTokenActionsBottomSheet { swapButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onTokenActionsBottomSheet { buyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Sell' button is displayed") {
|
||||
onTokenActionsBottomSheet { sellButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Hide token' button is displayed") {
|
||||
onTokenActionsBottomSheet { hideTokenButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("84")
|
||||
@DisplayName("Action buttons (long tap): check 'Copy address' button")
|
||||
@Test
|
||||
fun clickOnCopyAddressButtonTest() {
|
||||
val tokenTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
val bitcoinAddress = BITCOIN_ADDRESS
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
clearClipboard()
|
||||
},
|
||||
additionalAfterSection = {
|
||||
clearClipboard()
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Copy address' button is displayed") {
|
||||
onTokenActionsBottomSheet { copyAddressButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Copy address' button") {
|
||||
onTokenActionsBottomSheet { copyAddressButton.performClick() }
|
||||
}
|
||||
step("Assert snack bar message is displayed") {
|
||||
onMainScreen { snackbarCopiedAddressMessage.assertIsDisplayed() }
|
||||
}
|
||||
step("Check clipboard has '$tokenTitle' address '$bitcoinAddress'") {
|
||||
waitForIdle()
|
||||
assertClipboardTextEquals(expected = bitcoinAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("82")
|
||||
@DisplayName("Action buttons (long tap): check 'Buy' button")
|
||||
@Test
|
||||
fun clickOnBuyButtonTest() {
|
||||
val tokenTitle = "Bitcoin"
|
||||
val tokenSymbol = "BTC"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onTokenActionsBottomSheet { buyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onTokenActionsBottomSheet { buyButton.performClick() }
|
||||
}
|
||||
step("Click on 'Confirm' button in 'Dialog'") {
|
||||
waitForIdle()
|
||||
onDialog { confirmButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert top app bar title contains '$tokenTitle'") {
|
||||
onBuyTokenDetailsScreen { topBarTitle.assertTextContains("Buy $tokenTitle") }
|
||||
}
|
||||
step("Assert fiat currency text field is displayed") {
|
||||
onBuyTokenDetailsScreen { fiatAmountTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat currency icon is displayed") {
|
||||
onBuyTokenDetailsScreen { fiatCurrencyIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert token amount field is displayed") {
|
||||
onBuyTokenDetailsScreen { tokenAmountField.assertTextContains(tokenSymbol, substring = true) }
|
||||
}
|
||||
step("Assert 'Continue' button") {
|
||||
onBuyTokenDetailsScreen { continueButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("87")
|
||||
@DisplayName("Action buttons (long tap): check 'Swap' button")
|
||||
@Test
|
||||
fun clickOnSwapButtonTest() {
|
||||
val tokenTitle = "Ethereum"
|
||||
val tokenSymbol = "ETH"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Swap' button is displayed") {
|
||||
onTokenActionsBottomSheet { swapButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenActionsBottomSheet { swapButton.performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap' screen title is displayed") {
|
||||
onSwapTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert token symbol: '$tokenSymbol' is displayed") {
|
||||
onSwapTokenScreen { tokenSymbol(tokenSymbol).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("83")
|
||||
@DisplayName("Action buttons (long tap): check 'Send' button")
|
||||
@Test
|
||||
fun clickOnSendButtonTest() {
|
||||
val tokenTitle = "Ethereum"
|
||||
val tokenSymbol = "ETH"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Send' button is displayed") {
|
||||
onTokenActionsBottomSheet { sendButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Send' button") {
|
||||
onTokenActionsBottomSheet { sendButton.performClick() }
|
||||
}
|
||||
step("Assert amount input text field contains token symbol: '$tokenSymbol'") {
|
||||
onSendScreen {
|
||||
amountInputTextField.assertTextContains(value = tokenSymbol, substring = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("86")
|
||||
@DisplayName("Action buttons (long tap): check 'Receive' button")
|
||||
@Test
|
||||
fun clickOnReceiveButtonTest() {
|
||||
val tokenTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Receive' button is displayed") {
|
||||
onTokenActionsBottomSheet { receiveButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Receive' button") {
|
||||
onTokenActionsBottomSheet { receiveButton.performClick() }
|
||||
}
|
||||
step("Assert 'Token receive warning' bottom sheet is displayed") {
|
||||
onTokenReceiveWarningBottomSheet { bottomSheet.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Got it' button") {
|
||||
onTokenReceiveWarningBottomSheet { gotItButton.performClick() }
|
||||
}
|
||||
step("Click on 'Show QR code' button") {
|
||||
onReceiveAssetsBottomSheet { showQrCodeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert bottom sheet with QR code title is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert QR code is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { qrCode.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert address title is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { addressTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert address is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { address.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Copy' button is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { copyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Share' button is displayed") {
|
||||
onTokenReceiveQrCodeBottomSheet { shareButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("85")
|
||||
@DisplayName("Action buttons (long tap): check 'Sell' button")
|
||||
@Test
|
||||
fun clickOnSellButtonTest() {
|
||||
val tokenTitle = "Ethereum"
|
||||
val tokenSymbol = "ETH"
|
||||
val balance = TOTAL_BALANCE
|
||||
val url = "sell.moonpay.com"
|
||||
val useWithoutAccount = "Use without an account"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Receive' button is displayed") {
|
||||
onTokenActionsBottomSheet { sellButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Receive' button") {
|
||||
onTokenActionsBottomSheet { sellButton.performClick() }
|
||||
}
|
||||
step("Assert Chrome Browser is opened") {
|
||||
ChromeBrowserPageObject { assertChromeIsOpened() }
|
||||
}
|
||||
if (ChromeBrowserPageObject.isElementWithTextExists(useWithoutAccount)) {
|
||||
step("Click on '$useWithoutAccount' button on Chrome browser") {
|
||||
ChromeBrowserPageObject { clickOnElementWithText(useWithoutAccount) }
|
||||
}
|
||||
}
|
||||
step("Assert url contains: '$url'") {
|
||||
ChromeBrowserPageObject { assertUrlContains(url) }
|
||||
}
|
||||
step("Assert token symbol '$tokenSymbol' is displayed") {
|
||||
ChromeBrowserPageObject { assertElementWithTextExists(tokenSymbol) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("77")
|
||||
@DisplayName("Action buttons (long tap): assert 'Sell' button is not displayed if token doesn't support it")
|
||||
@Test
|
||||
fun assertSellButtonIsNotDisplayedTest() {
|
||||
val tokenTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
position = center,
|
||||
durationMillis = 1000L
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert 'Sell' button is not displayed") {
|
||||
onTokenActionsBottomSheet { sellButton.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Click 'Hide token' button") {
|
||||
onBottomSheet { hideButton.clickWithAssertion() }
|
||||
onTokenActionsBottomSheet { hideTokenButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click 'Hide' button in dialog") {
|
||||
onDialog {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ fun SimpleSettingsRow(
|
|||
onItemsClick()
|
||||
}
|
||||
},
|
||||
).testTag(BaseBottomSheetTestTags.ACTION_TITLE),
|
||||
).testTag(BaseBottomSheetTestTags.ACTION_BUTTON),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
|
|
@ -48,7 +48,8 @@ fun SimpleSettingsRow(
|
|||
painter = painterResource(id = icon),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = if (redesign) TangemTheme.dimens.spacing12 else TangemTheme.dimens.spacing20),
|
||||
.padding(horizontal = if (redesign) TangemTheme.dimens.spacing12 else TangemTheme.dimens.spacing20)
|
||||
.testTag(BaseBottomSheetTestTags.ACTION_ICON),
|
||||
tint = rowColors.iconColor(enabled = enabled).value,
|
||||
)
|
||||
Column(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object BaseBottomSheetTestTags {
|
||||
const val ACTION_TITLE = "BASE_BOTTOM_SHEET_ACTION_TITLE"
|
||||
const val ACTION_BUTTON = "BASE_BOTTOM_SHEET_ACTION_BUTTON"
|
||||
const val ACTION_ICON = "BASE_BOTTOM_SHEET_ACTION_ICON"
|
||||
const val TITLE = "BASE_BOTTOM_SHEET_TITLE"
|
||||
const val SUBTITLE = "BASE_BOTTOM_SHEET_SUBTITLE"
|
||||
const val CLOSE_BUTTON = "BASE_BOTTOM_SHEET_CLOSE_BUTTON"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ object SwapTokenScreenTestTags {
|
|||
const val PROVIDERS_BLOCK = "SWAP_TOKEN_SCREEN_PROVIDERS_BLOCK"
|
||||
const val SWAP_BUTTON = "SWAP_TOKEN_SCREEN_SWAP_BUTTON"
|
||||
const val TOKEN = "SWAP_TOKEN_SCREEN_TOKEN"
|
||||
const val TOKEN_NAME = "SWAP_TOKEN_SCREEN_TOKEN_NAME"
|
||||
const val TOKEN_SYMBOL = "SWAP_TOKEN_SCREEN_TOKEN_SYMBOL"
|
||||
const val TOKEN_ICON = "SWAP_TOKEN_SCREEN_TOKEN_ICON"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object TokenReceiveQrCodeBottomSheetTestTags {
|
||||
const val TITLE = "TOKEN_RECEIVE_QR_CODE_BOTTOM_SHEET_TITLE"
|
||||
const val QR_CODE = "TOKEN_RECEIVE_QR_CODE_BOTTOM_SHEET_QR_CODE"
|
||||
const val ADDRESS = "TOKEN_RECEIVE_QR_CODE_BOTTOM_SHEET_ADDRESS"
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object TokenReceiveWarningBottomSheetTestTags {
|
||||
const val BOTTOM_SHEET = "TOKEN_RECEIVE_WARNING_BOTTOM_SHEET"
|
||||
}
|
||||
|
|
@ -390,7 +390,7 @@ fun Token(
|
|||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.defaultMinSize(minWidth = TangemTheme.dimens.size80)
|
||||
.testTag(SwapTokenScreenTestTags.TOKEN_NAME),
|
||||
.testTag(SwapTokenScreenTestTags.TOKEN_SYMBOL),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import androidx.compose.ui.layout.ContentScale
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -32,6 +33,7 @@ import com.tangem.core.ui.components.*
|
|||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenReceiveQrCodeBottomSheetTestTags
|
||||
import com.tangem.features.tokenreceive.impl.R
|
||||
import com.tangem.features.tokenreceive.ui.state.QrCodeUM
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -88,6 +90,7 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.h3,
|
||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.TITLE),
|
||||
)
|
||||
|
||||
SpacerH(20.dp)
|
||||
|
|
@ -99,7 +102,8 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
|||
color = TangemTheme.colors.icon.constant,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
)
|
||||
.padding(8.dp),
|
||||
.padding(8.dp)
|
||||
.testTag(TokenReceiveQrCodeBottomSheetTestTags.QR_CODE),
|
||||
|
||||
) {
|
||||
Image(
|
||||
|
|
@ -126,6 +130,7 @@ private fun QrCodePage(addressFullName: TextReference, addressValue: String, net
|
|||
color = TangemTheme.colors.text.primary1,
|
||||
textAlign = TextAlign.Center,
|
||||
style = TangemTheme.typography.subtitle1,
|
||||
modifier = Modifier.testTag(TokenReceiveQrCodeBottomSheetTestTags.ADDRESS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -25,6 +26,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
|
|||
import com.tangem.core.ui.res.TangemColorPalette
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.TokenReceiveWarningBottomSheetTestTags
|
||||
import com.tangem.features.tokenreceive.impl.R
|
||||
import com.tangem.features.tokenreceive.ui.state.WarningUM
|
||||
|
||||
|
|
@ -40,7 +42,7 @@ internal fun TokenReceiveWarningContent(warningUM: WarningUM) {
|
|||
start = 16.dp,
|
||||
end = 16.dp,
|
||||
bottom = 16.dp,
|
||||
),
|
||||
).testTag(TokenReceiveWarningBottomSheetTestTags.BOTTOM_SHEET),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
CurrencyIcon(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue