Updated on 2026-08-14
This commit is contained in:
parent
cc6d2533bf
commit
6b05c5566e
22 changed files with 492 additions and 52 deletions
|
|
@ -147,7 +147,9 @@ abstract class BaseTestCase : TestCase(
|
|||
"NEW_ONRAMP_MAIN_ENABLED" to true,
|
||||
"HOT_WALLET_ENABLED" to true,
|
||||
"YIELD_SUPPLY_FEATURE_ENABLED" to true,
|
||||
"ACCOUNTS_FEATURE_ENABLED" to true
|
||||
"ACCOUNTS_FEATURE_ENABLED" to true,
|
||||
"FEED_ENABLED" to true,
|
||||
"GASLESS_TRANSACTIONS_ENABLED" to true,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package com.tangem.common.extensions
|
||||
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.components.buttons.actions.HasBadgeKey
|
||||
import com.tangem.core.ui.components.buttons.actions.IsDimmedKey
|
||||
import io.github.kakaocup.compose.node.element.KNode
|
||||
|
||||
fun assertElementDoesNotExist(
|
||||
|
|
@ -22,4 +26,20 @@ fun assertElementDoesNotExist(
|
|||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.assertIsDimmed(expectedValue: Boolean = true) {
|
||||
val matcher = SemanticsMatcher.expectValue(IsDimmedKey, expectedValue)
|
||||
when (this) {
|
||||
is KNode, is LazyListItemNode -> this.assert(matcher)
|
||||
else -> throw IllegalArgumentException("Unsupported type: ${this::class}")
|
||||
}
|
||||
}
|
||||
|
||||
fun Any.assertHasBadge(expectedValue: Boolean = true) {
|
||||
val matcher = SemanticsMatcher.expectValue(HasBadgeKey, expectedValue)
|
||||
when (this) {
|
||||
is KNode, is LazyListItemNode -> this.assert(matcher)
|
||||
else -> throw IllegalArgumentException("Unsupported type: ${this::class}")
|
||||
}
|
||||
}
|
||||
|
|
@ -235,6 +235,11 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val searchThroughMarketPlaceholder: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_search_header_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||
return lazyList.child {
|
||||
hasTestTag(MainScreenTestTags.TOKEN_LIST_ITEM)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ class MarketsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val searchThroughMarketPlaceholder: KNode = child {
|
||||
hasText(getResourceString(R.string.markets_search_header_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenWithTitle(title: String): KNode {
|
||||
return lazyList.child<KNode> {
|
||||
hasText(title)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.MarketTokenDetailsBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.features.onramp.impl.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
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
import androidx.compose.ui.test.hasText as withText
|
||||
|
||||
class MarketsTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<MarketsTokenDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val swapPortfolioQuickActionButton: KNode = child {
|
||||
hasTestTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_QUICK_ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_swap), substring = true)
|
||||
}
|
||||
|
||||
fun tokenWithTitle(title: String): KNode = child {
|
||||
hasAnyAncestor(withTestTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_TOKEN_ITEM))
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||
hasAnySibling(withTestTag(TokenElementsTestTags.TOKEN_ICON))
|
||||
hasAnyChild(withText(title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onMarketsTokenDetailsScreen(function: MarketsTokenDetailsPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
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.SearchBarTestTags
|
||||
import com.tangem.core.ui.test.SwapSelectTokenScreenTestTags
|
||||
import com.tangem.core.ui.test.TokenElementsTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
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.hasText as withText
|
||||
|
||||
class SwapSelectTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SwapSelectTokenPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.common_swap))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
}
|
||||
|
||||
val youSwapTitle: KNode = child {
|
||||
hasText(getResourceString(R.string.swapping_from_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val youSwapBlock: KNode = child {
|
||||
hasTestTag(SwapSelectTokenScreenTestTags.YOU_SWAP_BLOCK)
|
||||
hasAnyDescendant(withText(getResourceString(R.string.action_buttons_you_want_to_swap)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val youReceiveTitle: KNode = child {
|
||||
hasText(getResourceString(R.string.swapping_to_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val youReceiveBlock: KNode = child {
|
||||
hasTestTag(SwapSelectTokenScreenTestTags.YOU_SWAP_BLOCK)
|
||||
hasAnyDescendant(withText(getResourceString(R.string.action_buttons_you_want_to_receive)))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val searchBarIcon: KNode = child {
|
||||
hasTestTag(SearchBarTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val searchBarPlaceholderText: KNode = child {
|
||||
hasTestTag(SearchBarTestTags.PLACEHOLDER_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenWithName(tokenName: String): KNode = child {
|
||||
hasTestTag(TokenElementsTestTags.TOKEN_TITLE)
|
||||
hasAnyChild(withText(tokenName))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSwapSelectTokenScreen(function: SwapSelectTokenPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -13,6 +13,10 @@ import androidx.compose.ui.test.hasTestTag as withTestTag
|
|||
class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SwapTokenPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val container: KNode = child {
|
||||
hasTestTag(SwapTokenScreenTestTags.CONTAINER)
|
||||
}
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.common_swap))
|
||||
|
|
@ -78,6 +82,7 @@ class SwapTokenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
|
||||
fun tokenSymbol(symbol: String): KNode = child {
|
||||
hasTestTag(SwapTokenScreenTestTags.TOKEN_SYMBOL)
|
||||
hasText(symbol)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tests.actionButtons
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.assertIsDimmed
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
|
|
@ -60,8 +61,6 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun checkActionButtonsStateTest() {
|
||||
val tokenTitle = "Bitcoin"
|
||||
val actionButtonIsNotDimmed = "Action button is not dimmed"
|
||||
val actionButtonIsDimmed = "Action button is dimmed"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
|
|
@ -75,19 +74,19 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
|
||||
}
|
||||
step("Assert 'Receive' button is not dimmed") {
|
||||
onTokenDetailsScreen { receiveButton().assertContentDescriptionEquals(actionButtonIsNotDimmed) }
|
||||
onTokenDetailsScreen { receiveButton().assertIsDimmed(false) }
|
||||
}
|
||||
step("Assert 'Buy' button is not dimmed") {
|
||||
onTokenDetailsScreen { buyButton().assertContentDescriptionEquals(actionButtonIsNotDimmed) }
|
||||
onTokenDetailsScreen { buyButton().assertIsDimmed(false) }
|
||||
}
|
||||
step("Assert 'Send' button is not dimmed") {
|
||||
onTokenDetailsScreen { sendButton().assertContentDescriptionEquals(actionButtonIsNotDimmed) }
|
||||
onTokenDetailsScreen { sendButton().assertIsDimmed(false) }
|
||||
}
|
||||
step("Assert 'Swap' button is dimmed") {
|
||||
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { swapButton().assertIsDimmed() }
|
||||
}
|
||||
step("Assert 'Sell' button is dimmed") {
|
||||
onTokenDetailsScreen { sellButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { sellButton().assertIsDimmed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -130,7 +129,6 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun checkSwapButtonProviderErrorTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val actionButtonIsDimmed = "Action button is dimmed"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
|
|
@ -147,7 +145,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button is dimmed") {
|
||||
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { swapButton().assertIsDimmed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton().performClick() }
|
||||
|
|
@ -162,7 +160,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
onSwapIsNotSupportedDialog { okButton.performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button is dimmed") {
|
||||
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { swapButton().assertIsDimmed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -172,7 +170,6 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
@Test
|
||||
fun checkSwapButtonExpressErrorTest() {
|
||||
val tokenTitle = "Polygon"
|
||||
val actionButtonIsDimmed = "Action button is dimmed"
|
||||
val scenarioName = "express_api_assets"
|
||||
val scenarioState = "Error"
|
||||
|
||||
|
|
@ -198,7 +195,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button is dimmed") {
|
||||
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { swapButton().assertIsDimmed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton().performClick() }
|
||||
|
|
@ -213,7 +210,7 @@ class TokenDetailsScreenActionButtonsTest : BaseTestCase() {
|
|||
onOperationIsUnavailableDialog { okButton.performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button is dimmed") {
|
||||
onTokenDetailsScreen { swapButton().assertContentDescriptionEquals(actionButtonIsDimmed) }
|
||||
onTokenDetailsScreen { swapButton().assertIsDimmed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
package com.tangem.tests.swap
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
import com.tangem.screens.onSwapSelectTokenScreen
|
||||
import com.tangem.screens.onSwapStoriesScreen
|
||||
import com.tangem.screens.onSwapTokenScreen
|
||||
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 SwapSelectTokenScreenTest : BaseTestCase() {
|
||||
|
||||
@AllureId("2829")
|
||||
@DisplayName("Open 'Swap select token' screen from 'Main' screen")
|
||||
@Test
|
||||
fun openSwapSelectTokenScreenFromMainScreenTest() {
|
||||
val swapTokenName = "Ethereum"
|
||||
val receiveTokenName = "Polygon"
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onMainScreen { swapButton.performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap select token' screen title is displayed") {
|
||||
onSwapSelectTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'You swap' title is displayed") {
|
||||
onSwapSelectTokenScreen { youSwapTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'You swap' block is displayed") {
|
||||
onSwapSelectTokenScreen { youSwapBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert search icon is displayed") {
|
||||
onSwapSelectTokenScreen { searchBarIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert search placeholder is displayed") {
|
||||
onSwapSelectTokenScreen { searchBarPlaceholderText.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on token with name '$swapTokenName'") {
|
||||
onSwapSelectTokenScreen { tokenWithName(swapTokenName).performClick() }
|
||||
}
|
||||
step("Assert 'You receive' title is displayed") {
|
||||
onSwapSelectTokenScreen { youReceiveTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'You receive' block is displayed") {
|
||||
onSwapSelectTokenScreen { youReceiveBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on token with name '$receiveTokenName'") {
|
||||
onSwapSelectTokenScreen { tokenWithName(receiveTokenName).performClick() }
|
||||
}
|
||||
step("Assert 'Swap token' screen is opened") {
|
||||
onSwapTokenScreen { container.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
package com.tangem.tests.swap
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.assertHasBadge
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.*
|
||||
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 SwapStoriesTest : BaseTestCase() {
|
||||
|
||||
@AllureId("5453")
|
||||
@DisplayName("Check 'Swap' button badge on 'Main' screen")
|
||||
@Test
|
||||
fun checkMainScreenSwapButtonBadgeTest() {
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert 'Swap' button has badge") {
|
||||
onMainScreen { swapButton.assertHasBadge() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onMainScreen { swapButton.performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap' screen title is displayed") {
|
||||
onSwapTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Close' button") {
|
||||
onSwapTokenScreen { closeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button has not badge") {
|
||||
onMainScreen { swapButton.assertHasBadge(false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("5454")
|
||||
@DisplayName("Check 'Swap' button badge on token details screen")
|
||||
@Test
|
||||
fun checkTokenDetailsScreenSwapButtonTest() {
|
||||
val tokenName = "Ethereum"
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button has badge") {
|
||||
onTokenDetailsScreen { swapButton().assertHasBadge() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton().performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap' screen title is displayed") {
|
||||
onSwapTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Close' button") {
|
||||
onSwapTokenScreen { closeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button has not badge") {
|
||||
onTokenDetailsScreen { swapButton().assertHasBadge(false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("5455")
|
||||
@DisplayName("Check 'Swap' button badge on token details in 'Market' screen")
|
||||
@Test
|
||||
fun checkMarketTokenDetailsScreenSwapButtonTest() {
|
||||
val tokenName = "Ethereum"
|
||||
val badgeShown = "Badge shown"
|
||||
val badgeHidden = "Badge hidden"
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Markets' screen") {
|
||||
onMainScreen { searchThroughMarketPlaceholder.performClick() }
|
||||
waitForIdle()
|
||||
}
|
||||
step("") {
|
||||
onMarketsScreen { searchThroughMarketPlaceholder.performClick() }
|
||||
}
|
||||
step("Click on $tokenName token") {
|
||||
waitForIdle()
|
||||
onMarketsScreen { tokenWithTitle(tokenName).clickWithAssertion() }
|
||||
}
|
||||
step("Click on $tokenName token") {
|
||||
waitForIdle()
|
||||
onMarketsTokenDetailsScreen { tokenWithTitle(tokenName).performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button has badge") {
|
||||
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertIsDisplayed() }
|
||||
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeShown) }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap' screen title is displayed") {
|
||||
onSwapTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Close' button") {
|
||||
onSwapTokenScreen { closeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Swap' button has not badge") {
|
||||
onMarketsTokenDetailsScreen { swapPortfolioQuickActionButton.assertContentDescriptionEquals(badgeHidden) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.tests
|
||||
package com.tangem.tests.swap
|
||||
|
||||
import androidx.compose.ui.test.hasText
|
||||
import com.tangem.common.BaseTestCase
|
||||
|
|
@ -19,7 +19,7 @@ import io.qameta.allure.kotlin.junit4.DisplayName
|
|||
import org.junit.Test
|
||||
|
||||
@HiltAndroidTest
|
||||
class SwapTokenTest : BaseTestCase() {
|
||||
class SwapTokenScreenTest : BaseTestCase() {
|
||||
|
||||
@ApiEnv(
|
||||
ApiEnvConfig(ApiConfig.ID.Express, ApiEnvironment.PROD)
|
||||
|
|
@ -43,7 +43,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
step("Assert title: '$tokenTitle' is displayed") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
|
|
@ -123,7 +123,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
step("Assert title: '$tokenTitle' is displayed") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Turn off Wi-Fi and Mobile Data") {
|
||||
|
|
@ -171,7 +171,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
step("Assert title: '$tokenTitle' is displayed") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
|
|
@ -239,4 +239,55 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("2828")
|
||||
@DisplayName("Swap: network fee")
|
||||
@Test
|
||||
fun goToTokenSwapTest() {
|
||||
val swapTokenSymbol = "POL"
|
||||
val receiveTokenSymbol = "ETH"
|
||||
val tokenTitle = "Polygon"
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
resetWireMockScenarios()
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
step("Assert title: '$tokenTitle' is displayed") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton().performClick() }
|
||||
}
|
||||
step("Close 'Stories' screen") {
|
||||
onSwapStoriesScreen { closeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Swap' screen title is displayed") {
|
||||
onSwapTokenScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Close' button is displayed") {
|
||||
onSwapTokenScreen { closeButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Swap tokens on screen' button is displayed") {
|
||||
onSwapTokenScreen {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
swapTokensOnscreenButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
}
|
||||
step("Assert token symbol: '$swapTokenSymbol' is displayed") {
|
||||
onSwapTokenScreen { tokenSymbol(swapTokenSymbol).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert token symbol: '$receiveTokenSymbol' is displayed") {
|
||||
onSwapTokenScreen { tokenSymbol(receiveTokenSymbol).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.core.ui.components.buttons.actions
|
||||
|
||||
import androidx.compose.ui.semantics.SemanticsPropertyKey
|
||||
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
|
||||
|
||||
val IsDimmedKey = SemanticsPropertyKey<Boolean>("IsDimmed")
|
||||
val HasBadgeKey = SemanticsPropertyKey<Boolean>("HasBadge")
|
||||
|
||||
var SemanticsPropertyReceiver.isDimmed by IsDimmedKey
|
||||
var SemanticsPropertyReceiver.hasBadge by HasBadgeKey
|
||||
|
|
@ -22,7 +22,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -136,11 +135,8 @@ fun ActionBaseButton(
|
|||
}
|
||||
.clip(shape)
|
||||
.semantics {
|
||||
contentDescription = if (config.shouldDimContent) {
|
||||
"Action button is dimmed"
|
||||
} else {
|
||||
"Action button is not dimmed"
|
||||
}
|
||||
isDimmed = config.shouldDimContent
|
||||
hasBadge = config.shouldShowBadge
|
||||
}
|
||||
.combinedClickable(
|
||||
enabled = config.isEnabled,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import com.tangem.core.ui.extensions.resourceReference
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.BaseSearchBarTestTags
|
||||
import com.tangem.core.ui.test.SearchBarTestTags
|
||||
|
||||
@Composable
|
||||
fun SearchBar(
|
||||
|
|
@ -126,7 +127,9 @@ private fun DecorationBox(
|
|||
contentPadding = PaddingValues(all = TangemTheme.dimens.spacing12),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
modifier = Modifier.size(TangemTheme.dimens.size20),
|
||||
modifier = Modifier
|
||||
.size(TangemTheme.dimens.size20)
|
||||
.testTag(SearchBarTestTags.ICON),
|
||||
painter = painterResource(id = R.drawable.ic_search_24),
|
||||
tint = TangemTheme.colors.icon.informative,
|
||||
contentDescription = null,
|
||||
|
|
@ -137,6 +140,7 @@ private fun DecorationBox(
|
|||
state = state,
|
||||
focusManager = focusManager,
|
||||
keyboardController = keyboardController,
|
||||
modifier = Modifier.testTag(SearchBarTestTags.CLEAR_BUTTON),
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
|
|
@ -146,6 +150,7 @@ private fun DecorationBox(
|
|||
style = TangemTheme.typography.body2,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.testTag(SearchBarTestTags.PLACEHOLDER_TEXT),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object MarketTokenDetailsBottomSheetTestTags {
|
||||
const val PORTFOLIO_QUICK_ACTION_BUTTON = "MARKET_TOKEN_DETAILS_BOTTOM_SHEET_PORTFOLIO_QUICK_ACTION_BUTTON"
|
||||
const val PORTFOLIO_QUICK_ACTION_BUTTON_TITLE = "MARKET_TOKEN_DETAILS_BOTTOM_SHEET_PORTFOLIO_QUICK_ACTION_BUTTON_TITLE"
|
||||
const val PORTFOLIO_QUICK_ACTION_BUTTON_ICON = "MARKET_TOKEN_DETAILS_BOTTOM_SHEET_PORTFOLIO_QUICK_ACTION_BUTTON_ICON"
|
||||
const val PORTFOLIO_TOKEN_ITEM = "MARKET_TOKEN_DETAILS_BOTTOM_SHEET_PORTFOLIO_TOKEN_ITEM"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object SearchBarTestTags {
|
||||
const val ICON = "SEARCH_BAR_ICON"
|
||||
const val CLEAR_BUTTON = "SEARCH_BAR_CLEAR_BUTTON"
|
||||
const val PLACEHOLDER_TEXT = "SEARCH_BAR_PLACEHOLDER_TEXT"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object SwapSelectTokenScreenTestTags {
|
||||
const val YOU_SWAP_BLOCK = "SWAP_SELECT_TOKEN_SCREEN_YOU_SWAP_BLOCK"
|
||||
const val CHOOSE_TOKEN_TEXT = "SWAP_SELECT_TOKEN_SCREEN_CHOOSE_TOKEN_TEXT"
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.core.ui.test
|
||||
|
||||
object SwapTokenScreenTestTags {
|
||||
const val CONTAINER = "SWAP_TOKEN_SCREEN_CONTAINER"
|
||||
const val SWAP_BLOCK_HEADER = "SWAP_TOKEN_SCREEN_SWAP_BLOCK"
|
||||
const val BALANCE = "SWAP_TOKEN_SCREEN_BALANCE"
|
||||
const val SWAP_TEXT_FIELD = "SWAP_TOKEN_SCREEN_SWAP_TEXT_FIELD"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
|
|
@ -17,6 +18,7 @@ import com.tangem.core.ui.haptic.TangemHapticEffect
|
|||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.MarketTokenDetailsBottomSheetTestTags
|
||||
import com.tangem.features.feed.components.market.details.portfolio.impl.ui.preview.PreviewMyPortfolioUMProvider
|
||||
import com.tangem.features.feed.components.market.details.portfolio.impl.ui.state.PortfolioTokenUM
|
||||
import com.tangem.features.feed.impl.R
|
||||
|
|
@ -49,6 +51,7 @@ internal fun PortfolioItem(state: PortfolioTokenUM, lastInList: Boolean, modifie
|
|||
start = TangemTheme.dimens.spacing10,
|
||||
end = TangemTheme.dimens.spacing12,
|
||||
),
|
||||
modifier = Modifier.testTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_TOKEN_ITEM),
|
||||
)
|
||||
|
||||
PortfolioQuickActions(
|
||||
|
|
|
|||
|
|
@ -1,45 +1,29 @@
|
|||
package com.tangem.features.feed.components.market.details.portfolio.impl.ui
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.AnimatedVisibilityScope
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -51,6 +35,7 @@ import com.tangem.core.ui.haptic.TangemHapticEffect
|
|||
import com.tangem.core.ui.res.LocalHapticManager
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.test.MarketTokenDetailsBottomSheetTestTags
|
||||
import com.tangem.features.feed.components.market.details.portfolio.impl.ui.state.QuickActionUM
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -151,7 +136,8 @@ private fun AnimatedVisibilityScope.QuickActionItem(
|
|||
onClick()
|
||||
},
|
||||
)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing14, vertical = TangemTheme.dimens.spacing4),
|
||||
.padding(horizontal = TangemTheme.dimens.spacing14, vertical = TangemTheme.dimens.spacing4)
|
||||
.testTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_QUICK_ACTION_BUTTON),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing18),
|
||||
) {
|
||||
|
|
@ -168,6 +154,7 @@ private fun AnimatedVisibilityScope.QuickActionItem(
|
|||
text = state.title.resolveReference(),
|
||||
style = TangemTheme.typography.body2,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
modifier = Modifier.testTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_QUICK_ACTION_BUTTON_TITLE),
|
||||
)
|
||||
Text(
|
||||
text = state.description.resolveReference(),
|
||||
|
|
@ -192,6 +179,13 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
shape = CircleShape,
|
||||
)
|
||||
.size(TangemTheme.dimens.size32)
|
||||
.semantics {
|
||||
contentDescription = if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
"Badge shown"
|
||||
} else {
|
||||
"Badge hidden"
|
||||
}
|
||||
}
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
if (state is QuickActionUM.Exchange && state.shouldShowBadge) {
|
||||
|
|
@ -202,7 +196,8 @@ private fun AnimatedVisibilityScope.QuickActionIcon(state: QuickActionUM) {
|
|||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(TangemTheme.dimens.size16),
|
||||
.requiredSize(TangemTheme.dimens.size16)
|
||||
.testTag(MarketTokenDetailsBottomSheetTestTags.PORTFOLIO_QUICK_ACTION_BUTTON_ICON),
|
||||
imageVector = ImageVector.vectorResource(id = state.icon),
|
||||
contentDescription = null,
|
||||
tint = TangemTheme.colors.button.primary,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -30,6 +31,7 @@ import com.tangem.core.ui.components.token.state.TokenItemState
|
|||
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.SwapSelectTokenScreenTestTags
|
||||
import com.tangem.core.ui.utils.dashedBorder
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.swap.entity.ExchangeCardUM
|
||||
|
|
@ -50,7 +52,8 @@ internal fun ExchangeCard(state: ExchangeCardUM, isBalanceHidden: Boolean, modif
|
|||
.fillMaxWidth()
|
||||
.heightIn(min = 116.dp)
|
||||
.clip(TangemTheme.shapes.roundedCornersXMedium)
|
||||
.background(TangemTheme.colors.background.primary),
|
||||
.background(TangemTheme.colors.background.primary)
|
||||
.testTag(SwapSelectTokenScreenTestTags.YOU_SWAP_BLOCK),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Title(
|
||||
|
|
@ -157,6 +160,7 @@ private fun EmptyTokenBlock(text: TextReference, modifier: Modifier = Modifier)
|
|||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = TangemTheme.typography.body2,
|
||||
modifier = Modifier.testTag(SwapSelectTokenScreenTestTags.CHOOSE_TOKEN_TEXT),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import com.tangem.common.ui.bottomsheet.permission.GiveTxPermissionBottomSheet
|
||||
import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionBottomSheetConfig
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.SwapTokenScreenTestTags
|
||||
import com.tangem.core.ui.utils.WindowInsetsZero
|
||||
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
|
||||
import com.tangem.feature.swap.models.SwapStateHolder
|
||||
|
|
@ -50,7 +52,9 @@ internal fun SwapScreen(stateHolder: SwapStateHolder, feeSelectorBlockComponent:
|
|||
} else {
|
||||
null
|
||||
},
|
||||
modifier = Modifier.padding(scaffoldPaddings),
|
||||
modifier = Modifier
|
||||
.padding(scaffoldPaddings)
|
||||
.testTag(SwapTokenScreenTestTags.CONTAINER),
|
||||
)
|
||||
|
||||
if (stateHolder.bottomSheetConfig != null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue