Updated on 2026-08-14
This commit is contained in:
commit
a0c9ace219
1607 changed files with 40580 additions and 16776 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -12,6 +12,7 @@
|
|||
**/build/outputs/**
|
||||
**/build/reports/**
|
||||
**/build/tmp/**
|
||||
**/test-results/**
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
|
|
|||
33
.idea/codeStyles/Project.xml
generated
33
.idea/codeStyles/Project.xml
generated
|
|
@ -5,6 +5,39 @@
|
|||
<JavaCodeStyleSettings>
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="5" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="3" />
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="false" module="true" />
|
||||
<package name="android" withSubpackages="true" static="true" />
|
||||
<package name="androidx" withSubpackages="true" static="true" />
|
||||
<package name="com" withSubpackages="true" static="true" />
|
||||
<package name="junit" withSubpackages="true" static="true" />
|
||||
<package name="net" withSubpackages="true" static="true" />
|
||||
<package name="org" withSubpackages="true" static="true" />
|
||||
<package name="java" withSubpackages="true" static="true" />
|
||||
<package name="javax" withSubpackages="true" static="true" />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
<emptyLine />
|
||||
<package name="android" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="androidx" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="com" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="junit" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="net" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="org" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
</value>
|
||||
</option>
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
|
|
|
|||
40
.idea/file.template.settings.xml
generated
Normal file
40
.idea/file.template.settings.xml
generated
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<application>
|
||||
<component name="ExportableFileTemplateSettings">
|
||||
<default_templates>
|
||||
<template name="Decompose component.kt" file-name="${NAME}Component" reformat="true" live-template-enabled="false">
|
||||
<template name="Decompose component.kt.child.5.kt" file-name="di/${NAME}ModelModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.4.kt" file-name="di/${NAME}ComponentModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.0.kt" file-name="entity/${NAME}UM" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.1.kt" file-name="ui/${NAME}Content" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.2.kt" file-name="model/${NAME}Model" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.3.kt" file-name="Default${NAME}Component" reformat="true" live-template-enabled="false" />
|
||||
</template>
|
||||
<template name="Decompose component.kt.child.0.kt" file-name="entity/${NAME}UM" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.1.kt" file-name="ui/${NAME}Content" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.2.kt" file-name="model/${NAME}Model" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.3.kt" file-name="Default${NAME}Component" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.4.kt" file-name="di/${NAME}ComponentModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="Decompose component.kt.child.5.kt" file-name="di/${NAME}ModelModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FeatureToggles.kt" file-name="${NAME}FeatureToggles" reformat="true" live-template-enabled="false">
|
||||
<template name="FeatureToggles.kt.child.0.kt" file-name="Default${NAME}FeatureToggles" reformat="true" live-template-enabled="false" />
|
||||
</template>
|
||||
<template name="FeatureToggles.kt.child.0.kt" file-name="Default${NAME}FeatureToggles" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt" file-name="producer/${NAME}Producer" reformat="true" live-template-enabled="false">
|
||||
<template name="FlowPackaging.kt.child.0.kt" file-name="di/${NAME}FetcherModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.1.kt" file-name="di/${NAME}ProducerFactoryModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.2.kt" file-name="di/${NAME}SupplierModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.3.kt" file-name="fetcher/Default${NAME}Fetcher" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.4.kt" file-name="producer/Default${NAME}Producer" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.5.kt" file-name="fetcher/${NAME}Fetcher" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.6.kt" file-name="supplier/${NAME}Supplier" reformat="true" live-template-enabled="false" />
|
||||
</template>
|
||||
<template name="FlowPackaging.kt.child.0.kt" file-name="di/${NAME}FetcherModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.1.kt" file-name="di/${NAME}ProducerFactoryModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.2.kt" file-name="di/${NAME}SupplierModule" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.3.kt" file-name="fetcher/Default${NAME}Fetcher" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.4.kt" file-name="producer/Default${NAME}Producer" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.5.kt" file-name="fetcher/${NAME}Fetcher" reformat="true" live-template-enabled="false" />
|
||||
<template name="FlowPackaging.kt.child.6.kt" file-name="supplier/${NAME}Supplier" reformat="true" live-template-enabled="false" />
|
||||
</default_templates>
|
||||
</component>
|
||||
</application>
|
||||
13
.idea/fileTemplates/Decompose component.kt
generated
Normal file
13
.idea/fileTemplates/Decompose component.kt
generated
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end
|
||||
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
|
||||
interface ${NAME}Component : ComposableContentComponent {
|
||||
|
||||
data class Params(
|
||||
val data: Any, // TODO("Not yet implemented")
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, ${NAME}Component>
|
||||
}
|
||||
5
.idea/fileTemplates/Decompose component.kt.child.0.kt
generated
Normal file
5
.idea/fileTemplates/Decompose component.kt.child.0.kt
generated
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.entity#end
|
||||
|
||||
internal data class ${NAME}UM(
|
||||
val onBackClick: () -> Unit,
|
||||
)
|
||||
56
.idea/fileTemplates/Decompose component.kt.child.1.kt
generated
Normal file
56
.idea/fileTemplates/Decompose component.kt.child.1.kt
generated
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.ui#end
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import ${PACKAGE_NAME}.entity.${NAME}UM
|
||||
|
||||
@Composable
|
||||
internal fun ${NAME}Content(state: ${NAME}UM, modifier: Modifier = Modifier) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.background(color = TangemTheme.colors.background.secondary)
|
||||
.fillMaxSize()
|
||||
.imePadding()
|
||||
.systemBarsPadding(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
AppBarWithBackButton(
|
||||
onBackClick = state.onBackClick,
|
||||
modifier = Modifier.height(TangemTheme.dimens.size56),
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.weight(1f),
|
||||
|
||||
) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 360)
|
||||
@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ${NAME}ContentPreview(@PreviewParameter(PreviewStateProvider::class) state: ${NAME}UM) {
|
||||
TangemThemePreview {
|
||||
${NAME}Content(state = state)
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewStateProvider : CollectionPreviewParameterProvider<${NAME}UM>(
|
||||
buildList {
|
||||
TODO("Not yet implemented")
|
||||
},
|
||||
)
|
||||
31
.idea/fileTemplates/Decompose component.kt.child.2.kt
generated
Normal file
31
.idea/fileTemplates/Decompose component.kt.child.2.kt
generated
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.model#end
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.core.decompose.ui.UiMessageSender
|
||||
import ${PACKAGE_NAME}.${NAME}Component
|
||||
import ${PACKAGE_NAME}.entity.${NAME}UM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
@ModelScoped
|
||||
internal class ${NAME}Model @Inject constructor(
|
||||
paramsContainer: ParamsContainer,
|
||||
private val messageSender: UiMessageSender,
|
||||
private val router: Router,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<${NAME}Component.Params>()
|
||||
|
||||
val uiState: StateFlow<${NAME}UM>
|
||||
field: MutableStateFlow<${NAME}UM> = MutableStateFlow(getInitialState())
|
||||
|
||||
private fun getInitialState(): ${NAME}UM {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
39
.idea/fileTemplates/Decompose component.kt.child.3.kt
generated
Normal file
39
.idea/fileTemplates/Decompose component.kt.child.3.kt
generated
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import ${PACKAGE_NAME}.model.${NAME}Model
|
||||
import ${PACKAGE_NAME}.ui.${NAME}Content
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
internal class Default${NAME}Component @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted params: ${NAME}Component.Params,
|
||||
) : AppComponentContext by appComponentContext, ${NAME}Component {
|
||||
|
||||
private val model: ${NAME}Model = getOrCreateModel(params)
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
${NAME}Content(modifier = modifier, state = state)
|
||||
|
||||
BackHandler(onBack = state.onBackClick)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ${NAME}Component.Factory {
|
||||
override fun create(
|
||||
context: AppComponentContext,
|
||||
params: ${NAME}Component.Params,
|
||||
): Default${NAME}Component
|
||||
}
|
||||
}
|
||||
20
.idea/fileTemplates/Decompose component.kt.child.4.kt
generated
Normal file
20
.idea/fileTemplates/Decompose component.kt.child.4.kt
generated
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.di#end
|
||||
|
||||
import ${PACKAGE_NAME}.Default${NAME}Component
|
||||
import ${PACKAGE_NAME}.${NAME}Component
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ${NAME}ComponentModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bind${NAME}ComponentFactory(
|
||||
factory: Default${NAME}Component.Factory,
|
||||
): ${NAME}Component.Factory
|
||||
}
|
||||
20
.idea/fileTemplates/Decompose component.kt.child.5.kt
generated
Normal file
20
.idea/fileTemplates/Decompose component.kt.child.5.kt
generated
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.di#end
|
||||
|
||||
import com.tangem.core.decompose.di.ModelComponent
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import ${PACKAGE_NAME}.model.${NAME}Model
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
@InstallIn(ModelComponent::class)
|
||||
internal interface ${NAME}ModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(${NAME}Model::class)
|
||||
fun bind${NAME}Model(model: ${NAME}Model): Model
|
||||
}
|
||||
11
.idea/fileTemplates/FeatureToggles.kt
generated
Normal file
11
.idea/fileTemplates/FeatureToggles.kt
generated
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#if ($TOGGLE_NAME && $TOGGLE_NAME != "")
|
||||
#set($TOGGLE = $TOGGLE_NAME)
|
||||
#else
|
||||
#set($TOGGLE = "TODO")
|
||||
#end
|
||||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
|
||||
|
||||
interface ${NAME}FeatureToggles {
|
||||
|
||||
val isFeatureEnabled: Boolean
|
||||
}
|
||||
16
.idea/fileTemplates/FeatureToggles.kt.child.0.kt
generated
Normal file
16
.idea/fileTemplates/FeatureToggles.kt.child.0.kt
generated
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#if ($TOGGLE_NAME && $TOGGLE_NAME != "")
|
||||
#set($TOGGLE = $TOGGLE_NAME)
|
||||
#else
|
||||
#set($TOGGLE = "TODO")
|
||||
#end
|
||||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
|
||||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
|
||||
internal class Default${NAME}FeatureToggles(
|
||||
private val featureTogglesManager: FeatureTogglesManager,
|
||||
) : ${NAME}FeatureToggles {
|
||||
|
||||
override val isFeatureEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(name = "$TOGGLE")
|
||||
}
|
||||
17
.idea/fileTemplates/FlowPackaging.kt
generated
Normal file
17
.idea/fileTemplates/FlowPackaging.kt
generated
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#if ($FlowType && $FlowType != "")
|
||||
#set($Type = $FlowType)
|
||||
#else
|
||||
#set($Type = "TODO")
|
||||
#end
|
||||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.producer#end
|
||||
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
|
||||
interface ${NAME}Producer : FlowProducer<${FlowType}> {
|
||||
|
||||
data class Params(
|
||||
val id: String, // TODO("Not yet implemented")
|
||||
)
|
||||
|
||||
interface Factory : FlowProducer.Factory<Params, ${NAME}Producer>
|
||||
}
|
||||
18
.idea/fileTemplates/FlowPackaging.kt.child.0.kt
generated
Normal file
18
.idea/fileTemplates/FlowPackaging.kt.child.0.kt
generated
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.di#end
|
||||
|
||||
import ${PACKAGE_NAME}.fetcher.Default${NAME}Fetcher
|
||||
import ${PACKAGE_NAME}.fetcher.${NAME}Fetcher
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ${NAME}FetcherModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bind${NAME}Fetcher(impl: Default${NAME}Fetcher): ${NAME}Fetcher
|
||||
}
|
||||
20
.idea/fileTemplates/FlowPackaging.kt.child.1.kt
generated
Normal file
20
.idea/fileTemplates/FlowPackaging.kt.child.1.kt
generated
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.di#end
|
||||
|
||||
import ${PACKAGE_NAME}.producer.Default${NAME}Producer
|
||||
import ${PACKAGE_NAME}.producer.${NAME}Producer
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ${NAME}ProducerFactoryModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bind${NAME}ProducerFactory(
|
||||
impl: Default${NAME}Producer.Factory,
|
||||
): ${NAME}Producer.Factory
|
||||
}
|
||||
23
.idea/fileTemplates/FlowPackaging.kt.child.2.kt
generated
Normal file
23
.idea/fileTemplates/FlowPackaging.kt.child.2.kt
generated
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.di#end
|
||||
|
||||
import ${PACKAGE_NAME}.producer.${NAME}Producer
|
||||
import ${PACKAGE_NAME}.supplier.${NAME}Supplier
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object ${NAME}SupplierModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provide${NAME}Supplier(factory: ${NAME}Producer.Factory): ${NAME}Supplier {
|
||||
return object : ${NAME}Supplier(
|
||||
factory = factory,
|
||||
keyCreator = { TODO("Not yet implemented") },
|
||||
) {}
|
||||
}
|
||||
}
|
||||
14
.idea/fileTemplates/FlowPackaging.kt.child.3.kt
generated
Normal file
14
.idea/fileTemplates/FlowPackaging.kt.child.3.kt
generated
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.fetcher#end
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class Default${NAME}Fetcher @Inject constructor(
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ${NAME}Fetcher {
|
||||
|
||||
override suspend fun invoke(params: ${NAME}Fetcher.Params): Either<Throwable, Unit> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
31
.idea/fileTemplates/FlowPackaging.kt.child.4.kt
generated
Normal file
31
.idea/fileTemplates/FlowPackaging.kt.child.4.kt
generated
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#if ($FlowType && $FlowType != "")
|
||||
#set($Type = $FlowType)
|
||||
#else
|
||||
#set($Type = "TODO")
|
||||
#end
|
||||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.producer#end
|
||||
|
||||
import arrow.core.Option
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
internal class Default${NAME}Producer @AssistedInject constructor(
|
||||
@Assisted val params: ${NAME}Producer.Params,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : TestProducer {
|
||||
|
||||
override val fallback: Option<$Type>
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
override fun produce(): Flow<$Type> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : ${NAME}Producer.Factory {
|
||||
override fun create(params: ${NAME}Producer.Params): Default${NAME}Producer
|
||||
}
|
||||
}
|
||||
10
.idea/fileTemplates/FlowPackaging.kt.child.5.kt
generated
Normal file
10
.idea/fileTemplates/FlowPackaging.kt.child.5.kt
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.fetcher#end
|
||||
|
||||
import com.tangem.domain.core.flow.FlowFetcher
|
||||
|
||||
interface ${NAME}Fetcher : FlowFetcher<${NAME}Fetcher.Params> {
|
||||
|
||||
data class Params(
|
||||
val id: String, // TODO("Not yet implemented")
|
||||
)
|
||||
}
|
||||
15
.idea/fileTemplates/FlowPackaging.kt.child.6.kt
generated
Normal file
15
.idea/fileTemplates/FlowPackaging.kt.child.6.kt
generated
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#if ($FlowType && $FlowType != "")
|
||||
#set($Type = $FlowType)
|
||||
#else
|
||||
#set($Type = "TODO")
|
||||
#end
|
||||
#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME}.supplier#end
|
||||
|
||||
import ${PACKAGE_NAME}.producer.${NAME}Producer
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
abstract class ${NAME}Supplier(
|
||||
override val factory: ${NAME}Producer.Factory,
|
||||
override val keyCreator: (${NAME}Producer.Params) -> String,
|
||||
) : FlowCachingSupplier<${NAME}Producer, ${NAME}Producer.Params, $Type>()
|
||||
|
|
@ -28,6 +28,7 @@ android {
|
|||
packaging {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
excludes.add("lib/x86_64/libargon2.so")
|
||||
}
|
||||
resources.excludes.add("META-INF/LICENSE.md")
|
||||
resources.excludes.add("META-INF/NOTICE.md")
|
||||
|
|
@ -96,6 +97,9 @@ configurations.all {
|
|||
|
||||
force(
|
||||
"org.bouncycastle:bcpkix-jdk15on:1.70",
|
||||
deps.kotlin.coroutines,
|
||||
deps.kotlin.coroutines.jvm,
|
||||
deps.kotlin.coroutines.android,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -111,6 +115,7 @@ dependencies {
|
|||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.core)
|
||||
api(projects.domain.common)
|
||||
implementation(projects.domain.card)
|
||||
implementation(projects.domain.demo)
|
||||
implementation(projects.domain.demo.models)
|
||||
|
|
@ -154,6 +159,7 @@ dependencies {
|
|||
implementation(projects.domain.walletManager)
|
||||
implementation(projects.domain.walletManager.models)
|
||||
implementation(projects.domain.yieldSupply)
|
||||
implementation(projects.domain.blockaid)
|
||||
|
||||
implementation(projects.common)
|
||||
implementation(projects.common.routing)
|
||||
|
|
@ -267,6 +273,8 @@ dependencies {
|
|||
implementation(projects.features.welcome.impl)
|
||||
implementation(projects.features.createWalletSelection.api)
|
||||
implementation(projects.features.createWalletSelection.impl)
|
||||
implementation(projects.features.createWalletStart.api)
|
||||
implementation(projects.features.createWalletStart.impl)
|
||||
implementation(projects.features.home.api)
|
||||
implementation(projects.features.home.impl)
|
||||
implementation(projects.features.account.api)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class ApplicationInjectionExecutionRule : TestRule {
|
|||
OnComponentReadyRunner.addListener(
|
||||
tangemApplication, ApplicationEntryPoint::class.java
|
||||
) { _: ApplicationEntryPoint ->
|
||||
tangemApplication.preInit()
|
||||
tangemApplication.init()
|
||||
}
|
||||
base.evaluate()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -100,6 +100,12 @@ abstract class BaseTestCase : TestCase(
|
|||
value = false
|
||||
)
|
||||
}
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
mutablePreferences.set(
|
||||
key = PreferencesKeys.getShouldShowNotificationKey("EnablePushesReminderNotification"),
|
||||
value = false
|
||||
)
|
||||
}
|
||||
promoRepository.setNeverToShowWalletPromo(PromoId.Sepa)
|
||||
}
|
||||
apiEnvironmentRule.setup(apiConfigsManager)
|
||||
|
|
@ -115,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).
|
||||
|
|
@ -123,22 +131,23 @@ 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()
|
||||
|
||||
private fun setFeatureToggles() {
|
||||
runBlocking {
|
||||
with(featureTogglesManager as MutableFeatureTogglesManager) {
|
||||
changeToggle("WALLET_CONNECT_REDESIGN_ENABLED", true)
|
||||
changeToggle("NEW_TOKEN_RECEIVE_ENABLED", true)
|
||||
changeToggle("WALLET_BALANCE_FETCHER_ENABLED", true)
|
||||
changeToggle("SEND_VIA_SWAP_ENABLED", true)
|
||||
changeToggle("SWAP_REDESIGN_ENABLED", true)
|
||||
changeToggle("SEND_REDESIGN_ENABLED", true)
|
||||
changeToggle("NEW_ONRAMP_MAIN_ENABLED", true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@ 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
|
||||
const val WAIT_UNTIL_TIMEOUT_LONG = 30_000L
|
||||
|
||||
const val MARKETS_MAIN_NETWORK_SUFFIX = "MAIN"
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ fun BaseTestCase.pullToRefresh() {
|
|||
direction = SwipeDirection.DOWN,
|
||||
startHeightRatio = 0.2f,
|
||||
endHeightRatio = 0.8f,
|
||||
steps = 2000
|
||||
steps = 1000
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +53,31 @@ fun BaseTestCase.openTheAppFromRecents() {
|
|||
device.uiDevice.click(centerX, centerY)
|
||||
}
|
||||
|
||||
fun BaseTestCase.disableWiFi() {
|
||||
device.uiDevice.executeShellCommand("svc wifi disable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.disableMobileData() {
|
||||
device.uiDevice.executeShellCommand("svc data disable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.enableWiFi() {
|
||||
device.uiDevice.executeShellCommand("svc wifi enable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.enableMobileData() {
|
||||
device.uiDevice.executeShellCommand("svc data enable")
|
||||
}
|
||||
|
||||
fun BaseTestCase.stopApp(packageName: String) {
|
||||
device.apps.kill(packageName)
|
||||
}
|
||||
|
||||
fun BaseTestCase.launchApp(packageName: String) {
|
||||
device.apps.waitForAppLaunchAndReady(packageName = packageName)
|
||||
device.apps.launch(packageName)
|
||||
}
|
||||
|
||||
enum class SwipeDirection {
|
||||
UP, DOWN
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
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
|
||||
return if (clipboard.hasPrimaryClip()) {
|
||||
clipboard.primaryClip?.getItemAt(0)?.text?.toString()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
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'"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import androidx.compose.ui.test.hasText
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
|
|
@ -7,12 +8,14 @@ import com.tangem.screens.*
|
|||
import com.tangem.screens.AlreadyUsedWalletDialogPageObject.thisIsMyWalletButton
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.MockProvider
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.openMainScreen(
|
||||
fun BaseTestCase.scanCard(
|
||||
productType: ProductType? = null,
|
||||
mockContent: MockContent? = null,
|
||||
alreadyActivatedDialogIsShown : Boolean = false
|
||||
alreadyActivatedDialogIsShown: Boolean = false,
|
||||
isTwinsCard: Boolean = false,
|
||||
) {
|
||||
if (productType != null) {
|
||||
MockProvider.setMocks(productType)
|
||||
|
|
@ -28,10 +31,34 @@ fun BaseTestCase.openMainScreen(
|
|||
}
|
||||
if (alreadyActivatedDialogIsShown) {
|
||||
step("Click on 'This is my wallet' button") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
AlreadyUsedWalletDialogPageObject { thisIsMyWalletButton.click() }
|
||||
}
|
||||
}
|
||||
if (isTwinsCard) {
|
||||
step("Click on 'Continue' button") {
|
||||
onOnboardingScreen { continueButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Continue to my wallet' button") {
|
||||
onOnboardingScreen { continueToMyWalletButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openMainScreen(
|
||||
productType: ProductType? = null,
|
||||
mockContent: MockContent? = null,
|
||||
alreadyActivatedDialogIsShown: Boolean = false,
|
||||
isTwinsCard: Boolean = false,
|
||||
) {
|
||||
step("Scan card") {
|
||||
scanCard(
|
||||
productType = productType,
|
||||
mockContent = mockContent,
|
||||
alreadyActivatedDialogIsShown = alreadyActivatedDialogIsShown,
|
||||
isTwinsCard = isTwinsCard,
|
||||
)
|
||||
}
|
||||
step("Assert 'Main' screen is displayed") {
|
||||
onMainScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -40,17 +67,35 @@ fun BaseTestCase.openMainScreen(
|
|||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.synchronizeAddresses(balance: String) {
|
||||
fun BaseTestCase.synchronizeAddresses(
|
||||
balance: String? = null,
|
||||
isBalanceAvailable: Boolean = true
|
||||
) {
|
||||
step("Click on 'Synchronize addresses' button") {
|
||||
onMainScreen { synchronizeAddressesButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(balance) }
|
||||
|
||||
when {
|
||||
!isBalanceAvailable -> step("Assert wallet balance = '$DASH_SIGN'") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(DASH_SIGN) }
|
||||
}
|
||||
balance != null -> {
|
||||
step("Assert wallet balance != '$DASH_SIGN'") {
|
||||
onMainScreen { totalBalanceText.assert(!hasText(DASH_SIGN)) }
|
||||
}
|
||||
step("Assert wallet balance = '$balance'") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(balance) }
|
||||
}
|
||||
}
|
||||
else -> step("Assert wallet balance != '$DASH_SIGN'") {
|
||||
onMainScreen { totalBalanceText.assert(!hasText(DASH_SIGN)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openDeviceSettingsScreen() {
|
||||
step("Open wallet details") {
|
||||
waitForIdle()
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Open 'Wallet settings' screen") {
|
||||
|
|
@ -59,4 +104,13 @@ fun BaseTestCase.openDeviceSettingsScreen() {
|
|||
step("Click on 'Device settings' button") {
|
||||
onWalletSettingsScreen { deviceSettingsButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openWalletConnectScreen() {
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.screens.onMainScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkSingleCurrencyMainScreen(
|
||||
cardBlockchain: String,
|
||||
cardTitle: String,
|
||||
withTransactions: Boolean = false,
|
||||
withWalletImage: Boolean = true
|
||||
) {
|
||||
step("Assert card title equal '$cardTitle'") {
|
||||
onMainScreen { walletNameText.assertTextEquals(cardTitle) }
|
||||
}
|
||||
if (withWalletImage) {
|
||||
step("Assert card image is displayed") { //TODO: create assertion method for checking images
|
||||
onMainScreen { walletImage.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert card image is not displayed") {
|
||||
onMainScreen { walletImage.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Receive' button is displayed") {
|
||||
onMainScreen { receiveButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onMainScreen { buyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' button is displayed") {
|
||||
onMainScreen { sendButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Sell' button is displayed") {
|
||||
onMainScreen { sellButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Swap' button is not displayed") {
|
||||
onMainScreen { swapButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' on single card main screen is displayed") {
|
||||
onMainScreen { marketPriceBlock().assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' title equals $cardBlockchain Market Price") {
|
||||
onMainScreen { marketPriceText.assertTextContains("$cardBlockchain Market Price") }
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
if (withTransactions) {
|
||||
step("Assert 'Transactions' block is displayed") {
|
||||
onMainScreen { transactionsExplorerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Transactions' title is displayed") {
|
||||
onMainScreen { transactionsTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Explorer' icon is displayed") {
|
||||
onMainScreen { transactionsExplorerIcon.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert empty 'Transactions' block is displayed") {
|
||||
onMainScreen { emptyTransactionBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block icon is displayed") {
|
||||
onMainScreen { emptyTransactionBlockIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block text is displayed") {
|
||||
onMainScreen { emptyTransactionBlockText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert empty 'Transactions' block 'Explore' button is displayed") {
|
||||
onMainScreen { emptyTransactionBlockExploreButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert 'Organize tokens' button is not displayed") {
|
||||
onMainScreen { organizeTokensButtonWithoutLazySearch.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkMultiCurrencyMainScreen(
|
||||
devicesCount: String,
|
||||
cardTitle: String,
|
||||
withWalletImage: Boolean = true
|
||||
) {
|
||||
step("Assert card title equal '$cardTitle'") {
|
||||
onMainScreen { walletNameText.assertTextEquals(cardTitle) }
|
||||
}
|
||||
if (withWalletImage) {
|
||||
step("Assert card image is displayed") {
|
||||
onMainScreen { walletImage.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert card image is not displayed") {
|
||||
onMainScreen { walletImage.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
step("Assert devices count equal to '$devicesCount'") {
|
||||
onMainScreen { walletDevicesCount.assertTextContains(devicesCount) }
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onMainScreen { buyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Swap' button is displayed") {
|
||||
onMainScreen { swapButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Sell' button is displayed") {
|
||||
onMainScreen { sellButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' button is not displayed") {
|
||||
onMainScreen { sendButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Receive' button is not displayed") {
|
||||
onMainScreen { receiveButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.screens.onOnboardingScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkBackupScreen() {
|
||||
step("Assert 'Creating a backup' top bar title is displayed") {
|
||||
onOnboardingScreen { creatingBackupTobBarTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Prepare your scan or ring' title is displayed") {
|
||||
onOnboardingScreen { prepareYouCardOrRingTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Start backup' text is displayed") {
|
||||
onOnboardingScreen { startBackupText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Scan card' button is displayed") {
|
||||
onOnboardingScreen { scanCardButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Skip for later' button is not displayed") {
|
||||
onOnboardingScreen { skipForLaterButton.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkCreateWalletScreenForWalletNoWallets() {
|
||||
step("Assert 'Create wallet' tob bar title is displayed") {
|
||||
onOnboardingScreen { createWalletTopBarTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert top bar 'Back' button is displayed") {
|
||||
onOnboardingScreen { topBarBackButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert top bar 'More' button is displayed") {
|
||||
onOnboardingScreen { topBarMoreButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Create wallet' title is displayed") {
|
||||
onOnboardingScreen { createWalletTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Create wallet' text is displayed") {
|
||||
onOnboardingScreen { createWalletText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Create wallet' button is displayed") {
|
||||
onOnboardingScreen { createWalletButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.openAndCheckBackupScreenForWalletNoWallets() {
|
||||
step("Click on 'Create wallet' button") {
|
||||
onOnboardingScreen { createWalletButton.performClick() }
|
||||
}
|
||||
step("Assert 'Getting started' top bar title is displayed") {
|
||||
onOnboardingScreen { gettingStartedTobBarTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Backup wallet' title is displayed") {
|
||||
onOnboardingScreen { backupWalletTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Backup wallet' text is displayed") {
|
||||
onOnboardingScreen { backupWalletText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Backup now' button is displayed") {
|
||||
onOnboardingScreen { backupWalletButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Skip for later' button is not displayed") {
|
||||
onOnboardingScreen { skipForLaterButton.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkCreateWalletScreenForWallet2NoWallets() {
|
||||
step("Assert 'Create a wallet' top bar title is displayed") {
|
||||
onOnboardingScreen { createWalletTopBarTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert top bar 'Back' button is displayed") {
|
||||
onOnboardingScreen { topBarBackButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert top bar 'More' button is displayed") {
|
||||
onOnboardingScreen { topBarMoreButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Generate keys privately' title is displayed") {
|
||||
onOnboardingScreen { generateKeysPrivatelyTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Generate keys privately' text is displayed") {
|
||||
onOnboardingScreen { generateKeysPrivatelyText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Create wallet' button is displayed") {
|
||||
onOnboardingScreen { createWalletButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Other options' button is displayed") {
|
||||
onOnboardingScreen { otherOptionsButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
fun BaseTestCase.openAndCheckBackupScreenForWallet2NoWallets() {
|
||||
step("Click on 'Create wallet' button") {
|
||||
onOnboardingScreen { createWalletButton.performClick() }
|
||||
}
|
||||
step("Assert 'Creating a backup' top bar title is displayed") {
|
||||
onOnboardingScreen { creatingBackupTobBarTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'No backup devices' title is displayed") {
|
||||
onOnboardingScreen { noBackupDevicesTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'No backup devices' text is displayed") {
|
||||
onOnboardingScreen { noBackupDevicesText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Add card or ring' button is displayed") {
|
||||
onOnboardingScreen { addCardOrRingButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Finalize backup' button is displayed") {
|
||||
onOnboardingScreen { finalizeBackupButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Skip for later' button is not displayed") {
|
||||
onOnboardingScreen { skipForLaterButton.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package com.tangem.scenarios
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.screens.onSendScreen
|
||||
import com.tangem.screens.onStakingConfirmScreen
|
||||
import com.tangem.screens.onStakingDetailsScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkStakingDetailsScreen(withStaking: Boolean) {
|
||||
step("Assert 'Title' is displayed") {
|
||||
onStakingDetailsScreen { stakingTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Annual percentage rate' is displayed") {
|
||||
onStakingDetailsScreen { annualPercentageRate.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Available' block is displayed") {
|
||||
onStakingDetailsScreen { availableBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Unbonding Period' block is displayed") {
|
||||
onStakingDetailsScreen { unbondingPeriodBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward claiming' block is displayed") {
|
||||
onStakingDetailsScreen { rewardClaimingBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward schedule' block is displayed") {
|
||||
onStakingDetailsScreen { rewardScheduleBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'ToS' text is displayed") {
|
||||
onStakingDetailsScreen { toSText.assertIsDisplayed() }
|
||||
}
|
||||
if (withStaking) {
|
||||
step("Assert 'Rewards block' is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Rewards block' title is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlockTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Rewards block' text is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlockText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Active staking block' is displayed") {
|
||||
onStakingDetailsScreen { activeStakingBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Your stakes' title is displayed") {
|
||||
onStakingDetailsScreen { yourStakesTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake more' button is displayed") {
|
||||
onStakingDetailsScreen { stakeMoreButton.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert banner image is displayed") {
|
||||
onStakingDetailsScreen { bannerImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert banner text is displayed") {
|
||||
onStakingDetailsScreen { bannerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingDetailsScreen { stakeButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fun BaseTestCase.checkStakingScreen(stakingAmount: String) {
|
||||
step("Assert 'Staking' screen is displayed") {
|
||||
onSendScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert top app bar 'Close' button is displayed") {
|
||||
onSendScreen { closeButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' screen title is displayed") {
|
||||
onSendScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container title is displayed") {
|
||||
onSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert input text field is displayed") {
|
||||
onSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert token name is displayed") {
|
||||
onSendScreen { tokenName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onSendScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Type '$stakingAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(stakingAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$stakingAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
}
|
||||
step("Assert 'Max' button is displayed") {
|
||||
onSendScreen { maxButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Next' button is displayed") {
|
||||
onSendScreen { nextButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkStakingConfirmScreen() {
|
||||
step("Assert 'Staking confirm' screen title is displayed") {
|
||||
onStakingConfirmScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onStakingConfirmScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingConfirmScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Validator' block is displayed") {
|
||||
onStakingConfirmScreen { validatorBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Network Fee' block is displayed") {
|
||||
onStakingConfirmScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingConfirmScreen { stakeButton.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.screens.onWalletConnectScreen
|
|||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkWalletConnectBottomSheet() {
|
||||
waitForIdle()
|
||||
step("Assert 'Wallet Connect' bottom sheet title is displayed") {
|
||||
onWalletConnectBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -60,34 +61,64 @@ fun BaseTestCase.checkWalletConnectBottomSheet() {
|
|||
}
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkWalletConnectScreen() {
|
||||
fun BaseTestCase.checkWalletConnectScreen(withConnections: Boolean) {
|
||||
waitForIdle()
|
||||
step("Assert 'Wallet Connect' title is displayed") {
|
||||
onWalletConnectScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'More' button is displayed") {
|
||||
onWalletConnectScreen { moreButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet name is displayed") {
|
||||
onWalletConnectScreen { walletName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app icon is displayed") {
|
||||
onWalletConnectScreen { appIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app name is displayed") {
|
||||
onWalletConnectScreen { appName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert approve icon is displayed") {
|
||||
onWalletConnectScreen { approveIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app URL is displayed") {
|
||||
onWalletConnectScreen { appUrl.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'New Connection' button is displayed") {
|
||||
onWalletConnectScreen { newConnectionButton.assertIsDisplayed() }
|
||||
}
|
||||
if (withConnections) {
|
||||
step("Assert 'More' button is displayed") {
|
||||
onWalletConnectScreen { moreButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert wallet name is displayed") {
|
||||
onWalletConnectScreen { walletName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app icon is displayed") {
|
||||
onWalletConnectScreen { appIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app name is displayed") {
|
||||
onWalletConnectScreen { appName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert approve icon is displayed") {
|
||||
onWalletConnectScreen { approveIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert app URL is displayed") {
|
||||
onWalletConnectScreen { appUrl.assertIsDisplayed() }
|
||||
}
|
||||
} else {
|
||||
step("Assert wallet name is not displayed") {
|
||||
onWalletConnectScreen { walletName.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert app icon is not displayed") {
|
||||
onWalletConnectScreen { appIcon.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert app name is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert approve icon is not displayed") {
|
||||
onWalletConnectScreen { approveIcon.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert app URL is not displayed") {
|
||||
onWalletConnectScreen { appUrl.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' image is displayed") {
|
||||
onWalletConnectScreen { walletConnectImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'No session' title is displayed") {
|
||||
onWalletConnectScreen { noSessionTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'No session' text is displayed") {
|
||||
onWalletConnectScreen { noSessionText.assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun BaseTestCase.checkWalletConnectDetailsBottomSheet(dAppName: String) {
|
||||
waitForIdle()
|
||||
step("Assert connection details title is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -128,7 +159,7 @@ fun BaseTestCase.checkWalletConnectDetailsBottomSheet(dAppName: String) {
|
|||
onWalletConnectDetailsBottomSheet { connectedNetworkIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert connected dApp name: '$dAppName'") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkName.assertTextContains(dAppName) }
|
||||
onWalletConnectDetailsBottomSheet { appName.assertTextContains(dAppName) }
|
||||
}
|
||||
step("Assert connected network symbol is displayed") {
|
||||
onWalletConnectDetailsBottomSheet { connectedNetworkSymbol.assertIsDisplayed() }
|
||||
|
|
|
|||
|
|
@ -3,15 +3,13 @@ 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.BuyTokenDetailsScreenTestTags
|
||||
import com.tangem.core.ui.test.NotificationTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import com.tangem.core.ui.test.*
|
||||
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 com.tangem.features.onramp.impl.R as OnrampImplR
|
||||
|
||||
class BuyTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<BuyTokenDetailsPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -68,31 +66,65 @@ class BuyTokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProv
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val providerLoadingTitle: KNode = child {
|
||||
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TITLE)
|
||||
val recommendedTitle: KNode = child {
|
||||
hasText(getResourceString(OnrampImplR.string.onramp_recommended_title))
|
||||
}
|
||||
|
||||
val providerLoadingText: KNode = child {
|
||||
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_LOADING_TEXT)
|
||||
}
|
||||
|
||||
val providerTitle: KNode = child {
|
||||
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_TITLE)
|
||||
val bestRateIcon: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.BEST_RATE_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val providerText: KNode = child {
|
||||
hasTestTag(BuyTokenDetailsScreenTestTags.PROVIDER_TEXT)
|
||||
val bestRateTitle: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.BEST_RATE_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val offerTokenAmount: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.OFFER_TOKEN_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val timingIcon: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.TIMING_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val payWith: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.PAY_WITH)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val paymentMethodIcon: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.PAYMENT_METHOD_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val instantProcessingSpeedText: KNode = child {
|
||||
hasText(getResourceString(R.string.onramp_instant_status))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val providerName: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.PROVIDER_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val buyButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.BUTTON)
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_buy))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val toSBlock: KNode = child {
|
||||
hasTestTag(BuyTokenDetailsScreenTestTags.TOS_BLOCK)
|
||||
val continueButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_continue))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val allOffersButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.onramp_all_offers_button_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -44,10 +45,30 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
|
||||
val buyButton: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.MULTI_CURRENCY_ACTION_BUTTON)
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_buy))
|
||||
}
|
||||
|
||||
val sendButton: KNode = child {
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_send))
|
||||
}
|
||||
|
||||
val receiveButton: KNode = child {
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_receive))
|
||||
}
|
||||
|
||||
val sellButton: KNode = child {
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_sell))
|
||||
}
|
||||
|
||||
val swapButton: KNode = child {
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_swap))
|
||||
}
|
||||
|
||||
val walletNameText: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.CARD_TITLE)
|
||||
useUnmergedTree = true
|
||||
|
|
@ -58,11 +79,19 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val marketPriceBlock: KNode = child {
|
||||
hasTestTag(MarketPriceBlockTestTags.BLOCK)
|
||||
val walletDevicesCount: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.DEVICES_COUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
fun marketPriceBlock(): LazyListItemNode {
|
||||
return lazyList.childWith<LazyListItemNode> {
|
||||
hasTestTag(MarketPriceBlockTestTags.BLOCK)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
val marketPriceText: KNode = child {
|
||||
hasTestTag(MarketPriceBlockTestTags.TEXT)
|
||||
useUnmergedTree = true
|
||||
|
|
@ -79,12 +108,26 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun transactionsExplorer(): KNode {
|
||||
return child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_TEXT)
|
||||
hasText(getResourceString(R.string.common_explorer))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
val transactionsExplorerText: KNode = child {
|
||||
hasTestTag(TransactionHistoryBlockTestTags.EXPLORER_TEXT)
|
||||
hasText(getResourceString(R.string.common_explorer))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val emptyTransactionBlock: KNode = child {
|
||||
hasTestTag(EmptyTransactionBlockTestTags.BLOCK)
|
||||
}
|
||||
|
||||
val emptyTransactionBlockIcon: KNode = child {
|
||||
hasTestTag(EmptyTransactionBlockTestTags.ICON)
|
||||
}
|
||||
|
||||
val emptyTransactionBlockText: KNode = child {
|
||||
hasTestTag(EmptyTransactionBlockTestTags.TEXT)
|
||||
}
|
||||
|
||||
val emptyTransactionBlockExploreButton: KNode = child {
|
||||
hasTestTag(EmptyTransactionBlockTestTags.EXPLORE_BUTTON)
|
||||
}
|
||||
|
||||
val notificationContainer: KNode = child {
|
||||
|
|
@ -158,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
|
||||
*/
|
||||
|
|
@ -182,12 +229,10 @@ class MainScreenPageObject(semanticsProvider: SemanticsNodeInteractionsProvider)
|
|||
}
|
||||
}
|
||||
|
||||
fun organizeTokensButtonWithoutLazySearch(): KNode {
|
||||
return child {
|
||||
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
val organizeTokensButtonWithoutLazySearch: KNode = child {
|
||||
hasTestTag(MainScreenTestTags.ORGANIZE_TOKENS_BUTTON)
|
||||
hasText(getResourceString(R.string.organize_tokens_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun tokenNetworkGroupTitle(tokenNetwork: String): KNode {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
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
|
||||
import io.github.kakaocup.kakao.common.views.KView
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
import com.tangem.features.onboarding.v2.impl.R as OnboardingImplR
|
||||
|
||||
class OnboardingPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<OnboardingPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val topBarBackButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val continueButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_continue))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val continueToMyWalletButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.onboarding_button_continue_wallet))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val createWalletTopBarTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_header))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val createWalletTitle: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.TITLE)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_header))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val createWalletText: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_body))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val gettingStartedTobBarTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_getting_started))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val creatingBackupTobBarTitle: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_navbar_title_creating_backup))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val prepareYouCardOrRingTitle: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_title_scan_origin_card))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val startBackupText: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_subtitle_scan_primary))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val topBarMoreButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.MORE_BUTTON)
|
||||
}
|
||||
|
||||
val backupWalletTitle: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_wallet_info_title_first))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val backupWalletText: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_wallet_info_subtitle_first))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val generateKeysPrivatelyTitle: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_options_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val generateKeysPrivatelyText: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_options_message))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val noBackupDevicesTitle: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_subtitle_no_backup_cards))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val noBackupDevicesText: KNode = child {
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_title_no_backup_cards))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val createWalletButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_button_create_wallet))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val backupWalletButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_button_backup_now))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val scanCardButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_button_backup_card))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val otherOptionsButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_create_wallet_options_button_options))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val addCardOrRingButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_button_add_backup_card))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val finalizeBackupButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_button_finalize_backup))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val skipForLaterButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(OnboardingImplR.string.onboarding_button_skip_backup))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val enableNFCAlert: KView = KView {
|
||||
withId(R.id.alertTitle)
|
||||
}
|
||||
|
||||
val cancelButton: KButton = KButton {
|
||||
withId(android.R.id.button2)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onOnboardingScreen(function: OnboardingPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -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)
|
||||
|
|
@ -1,17 +1,14 @@
|
|||
package com.tangem.screens
|
||||
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.OnrampOffersBlockTestTags
|
||||
import com.tangem.core.ui.test.SelectPaymentMethodBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.TopAppBarTestTags
|
||||
import com.tangem.core.ui.utils.LazyListItemPositionSemantics
|
||||
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.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
|
||||
|
|
@ -19,30 +16,31 @@ import androidx.compose.ui.test.hasText as withText
|
|||
class SelectPaymentMethodPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SelectPaymentMethodPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
|
||||
private val lazyList = KLazyListNode(
|
||||
semanticsProvider = semanticsProvider,
|
||||
viewBuilderAction = { hasTestTag(SelectPaymentMethodBottomSheetTestTags.LAZY_LIST) },
|
||||
itemTypeBuilder = { itemType(::LazyListItemNode) },
|
||||
positionMatcher = { position ->
|
||||
SemanticsMatcher.expectValue(
|
||||
LazyListItemPositionSemantics,
|
||||
position
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.onramp_pay_with))
|
||||
hasTestTag(BaseBottomSheetTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.onramp_all_offers_button_title))
|
||||
}
|
||||
|
||||
fun paymentMethodWithNameAndIcon(name: String): KNode {
|
||||
return lazyList.child<KNode> {
|
||||
hasAnyDescendant(withText(name))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.PAYMENT_METHOD_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
val subtitle: KNode = child {
|
||||
hasTestTag(BaseBottomSheetTestTags.SUBTITLE)
|
||||
hasText(getResourceString(R.string.onramp_payment_method_subtitle))
|
||||
}
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(BaseBottomSheetTestTags.CLOSE_BUTTON)
|
||||
}
|
||||
|
||||
fun paymentMethodWithName(name: String): KNode = child {
|
||||
hasTestTag(SelectPaymentMethodBottomSheetTestTags.PAYMENT_METHOD)
|
||||
hasAnyDescendant(withText(name))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.PAYMENT_METHOD_ICON))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.TIMING_ICON))
|
||||
hasAnyDescendant(withTestTag(OnrampOffersBlockTestTags.TIMING_TEXT))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.TOKEN_AMOUNT))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.PROVIDER_COUNT_ICON))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.PROVIDER_COUNT_TEXT))
|
||||
hasAnyDescendant(withTestTag(SelectPaymentMethodBottomSheetTestTags.UP_TO_TEXT))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,87 +2,78 @@ package com.tangem.screens
|
|||
|
||||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.SelectProviderBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.BaseBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.OnrampOffersBlockTestTags
|
||||
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.hasText as withText
|
||||
import com.tangem.core.ui.R as CoreUiR
|
||||
|
||||
class SelectProviderPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SelectProviderPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasText(getResourceString(R.string.onramp_choose_provider_title_hint))
|
||||
hasTestTag(BaseBottomSheetTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.onramp_all_offers_button_title))
|
||||
}
|
||||
|
||||
val subtitle: KNode = child {
|
||||
hasTestTag(BaseBottomSheetTestTags.SUBTITLE)
|
||||
hasText(getResourceString(R.string.express_provider))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val bestRateIcon: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.BEST_RATE_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val bestRateTitle: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.BEST_RATE_TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val offerTokenAmount: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.OFFER_TOKEN_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val timingIcon: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.TIMING_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val payWith: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.PAY_WITH)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val youGetText: KNode = child {
|
||||
hasText(getResourceString(R.string.onramp_title_you_get))
|
||||
}
|
||||
|
||||
val paymentMethodIcon: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_ICON)
|
||||
hasTestTag(OnrampOffersBlockTestTags.PAYMENT_METHOD_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val paymentMethodTitle: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_NAME)
|
||||
val providerName: KNode = child {
|
||||
hasTestTag(OnrampOffersBlockTestTags.PROVIDER_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val paymentMethodName: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_NAME)
|
||||
|
||||
val instantProcessingSpeedText: KNode = child {
|
||||
hasText(getResourceString(com.tangem.core.ui.R.string.onramp_instant_status))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val paymentMethodExpandButton: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.PAYMENT_METHOD_EXPAND_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val availableProviderItem: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_ITEM)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val availableProviderName: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val tokenAmount: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.TOKEN_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val unavailableProviderItem: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_ITEM)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val unavailableProviderName: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.UNAVAILABLE_PROVIDER_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val moreProvidersIcon: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val moreProvidersText: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.MORE_PROVIDERS_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val bestRateLabel: KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.BEST_RATE_LABEL)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun availableProviderWithName(name: String, tokenAmount: String, rate: String): KNode = child {
|
||||
hasTestTag(SelectProviderBottomSheetTestTags.AVAILABLE_PROVIDER_ITEM)
|
||||
hasAnyChild(withText(name))
|
||||
hasAnyChild(withText(tokenAmount))
|
||||
hasAnyChild(withText(rate))
|
||||
val buyButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(CoreUiR.string.common_buy))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ 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.NotificationTestTags
|
||||
import com.tangem.core.ui.test.SendConfirmScreenTestTags
|
||||
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
|
||||
import com.tangem.common.ui.R as CommonUiR
|
||||
|
||||
class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendConfirmPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -24,6 +28,46 @@ class SendConfirmPageObject(semanticsProvider: SemanticsNodeInteractionsProvider
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
||||
val minimumSendAmountErrorTitle: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TITLE)
|
||||
hasText(getResourceString(CommonUiR.string.send_notification_invalid_amount_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val sendingText: KNode = child {
|
||||
hasTestTag(SendConfirmScreenTestTags.SENDING_TEXT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun minimumSendAmountErrorIcon(amount: String): KNode = child {
|
||||
hasAnySibling(
|
||||
withText(
|
||||
getResourceString(
|
||||
CommonUiR.string.send_notification_invalid_minimum_amount_text,
|
||||
amount,
|
||||
amount,
|
||||
)
|
||||
)
|
||||
)
|
||||
hasTestTag(NotificationTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun minimumSendAmountErrorMessage(
|
||||
amount: String,
|
||||
): KNode = child {
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(
|
||||
getResourceString(
|
||||
CommonUiR.string.send_notification_invalid_minimum_amount_text,
|
||||
amount,
|
||||
amount,
|
||||
)
|
||||
)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onSendConfirmScreen(function: SendConfirmPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import io.github.kakaocup.compose.node.element.ComposeScreen.Companion.onCompose
|
|||
import io.github.kakaocup.compose.node.element.KNode
|
||||
import io.github.kakaocup.kakao.common.utilities.getResourceString
|
||||
import com.tangem.features.send.v2.impl.R as SendR
|
||||
import androidx.compose.ui.test.hasTestTag as withTestTag
|
||||
|
||||
class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<SendPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
|
@ -19,6 +18,11 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
hasTestTag(SendScreenTestTags.SCREEN_CONTAINER)
|
||||
}
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(TopAppBarTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
|
|
@ -29,13 +33,18 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val amountContainerText: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.AMOUNT_CONTAINER_TEXT)
|
||||
val amountInputTextField: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.INPUT_TEXT_FIELD)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val amountInputTextField: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.INPUT_TEXT_FIELD)
|
||||
val tokenName: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.TOKEN_NAME)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val primaryAmount: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.PRIMARY_AMOUNT)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
@ -44,28 +53,11 @@ class SendPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val currencyButton: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(SendScreenTestTags.CURRENCY_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val fiatButton: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.CURRENCY_BUTTON)
|
||||
hasAnyChild(withTestTag(SendScreenTestTags.FIAT_ICON))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val maxButton: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.MAX_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val previousButton: KNode = child {
|
||||
hasTestTag(SendScreenTestTags.PREVIOUS_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val nextButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(SendR.string.common_next))
|
||||
|
|
|
|||
|
|
@ -3,18 +3,12 @@ package com.tangem.screens
|
|||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.core.ui.test.StoriesScreenTestTags
|
||||
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.views.KView
|
||||
import io.github.kakaocup.kakao.text.KButton
|
||||
|
||||
class StoriesPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<StoriesPageObject>(
|
||||
semanticsProvider = semanticsProvider,
|
||||
viewBuilderAction = { hasTestTag(StoriesScreenTestTags.SCREEN_CONTAINER) }
|
||||
) {
|
||||
ComposeScreen<StoriesPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val scanButton: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.SCAN_BUTTON)
|
||||
|
|
@ -23,14 +17,6 @@ class StoriesPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
|||
val orderButton: KNode = child {
|
||||
hasTestTag(StoriesScreenTestTags.ORDER_BUTTON)
|
||||
}
|
||||
|
||||
val enableNFCAlert: KView = KView {
|
||||
withId(R.id.alertTitle)
|
||||
}
|
||||
|
||||
val cancelButton: KButton = KButton {
|
||||
withId(android.R.id.button2)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onStoriesScreen(function: StoriesPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -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,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 ThirdPartyAppPageObject : KScreen<ThirdPartyAppPageObject>() {
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.ui.test.SemanticsMatcher
|
|||
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.utils.LazyListItemNode
|
||||
import com.tangem.core.ui.test.BaseActionButtonsBlockTestTags
|
||||
import com.tangem.core.ui.test.BaseButtonTestTags
|
||||
import com.tangem.core.ui.test.NotificationTestTags
|
||||
import com.tangem.core.ui.test.TokenDetailsScreenTestTags
|
||||
|
|
@ -85,7 +86,7 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
|
|||
|
||||
private val horizontalActionChips = KLazyListNode(
|
||||
semanticsProvider = semanticsProvider,
|
||||
viewBuilderAction = { hasTestTag(TokenDetailsScreenTestTags.HORIZONTAL_ACTION_CHIPS) },
|
||||
viewBuilderAction = { hasTestTag(BaseActionButtonsBlockTestTags.HORIZONTAL_ACTION_CHIPS) },
|
||||
itemTypeBuilder = { itemType(::LazyListItemNode) },
|
||||
positionMatcher = { position ->
|
||||
SemanticsMatcher.expectValue(
|
||||
|
|
@ -97,25 +98,25 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
|
|||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
val swapButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
|
||||
hasTestTag(TokenDetailsScreenTestTags.ACTION_BUTTON)
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_swap))
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
val sellButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
|
||||
hasTestTag(TokenDetailsScreenTestTags.ACTION_BUTTON)
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_sell))
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
val buyButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
|
||||
hasTestTag(TokenDetailsScreenTestTags.ACTION_BUTTON)
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_buy))
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
val sendButton: LazyListItemNode = horizontalActionChips.childWith<LazyListItemNode> {
|
||||
hasTestTag(TokenDetailsScreenTestTags.ACTION_BUTTON)
|
||||
hasTestTag(BaseActionButtonsBlockTestTags.ACTION_BUTTON)
|
||||
hasText(getResourceString(R.string.common_send))
|
||||
}
|
||||
|
||||
|
|
@ -131,6 +132,18 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val topUpYourWalletNotificationTitle: KNode = child {
|
||||
hasTestTag(NotificationTestTags.TITLE)
|
||||
hasText(getResourceString(R.string.warning_no_account_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val topUpYourWalletNotificationIcon: KNode = child {
|
||||
hasAnySibling(withText(getResourceString(R.string.warning_no_account_title)))
|
||||
hasTestTag(NotificationTestTags.ICON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun networkFeeNotificationMessage(
|
||||
currencyName: String,
|
||||
networkName: String,
|
||||
|
|
@ -151,6 +164,23 @@ class TokenDetailsPageObject(semanticsProvider: SemanticsNodeInteractionsProvide
|
|||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun topUpYourWalletNotificationMessage(
|
||||
networkName: String,
|
||||
amount: String,
|
||||
currencySymbol: String,
|
||||
): KNode = child {
|
||||
hasTestTag(NotificationTestTags.MESSAGE)
|
||||
hasText(
|
||||
getResourceString(
|
||||
R.string.no_account_generic,
|
||||
networkName,
|
||||
amount,
|
||||
currencySymbol,
|
||||
)
|
||||
)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
fun goToBuyCurrencyButton(feeCurrencySymbol: String): KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.common_buy_currency, feeCurrencySymbol))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -9,13 +9,11 @@ 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 com.tangem.features.walletconnect.impl.R as WalletConnectImplR
|
||||
|
||||
class WalletConnectBottomSheetPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<WalletConnectBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasText(getResourceString(WalletConnectImplR.string.wc_wallet_connect))
|
||||
hasTestTag(WalletConnectBottomSheetTestTags.TITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ 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.WalletConnectBottomSheetTestTags
|
||||
import com.tangem.core.ui.test.WalletConnectDetailsBottomSheetTestTags
|
||||
|
|
@ -15,18 +16,18 @@ class WalletConnectDetailsBottomSheetPageObject(semanticsProvider: SemanticsNode
|
|||
ComposeScreen<WalletConnectDetailsBottomSheetPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val title: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.TITLE)
|
||||
hasTestTag(BaseBottomSheetTestTags.TITLE)
|
||||
hasText(getResourceString(WalletConnectImplR.string.wc_connected_app_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val date: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.DATE)
|
||||
hasTestTag(BaseBottomSheetTestTags.SUBTITLE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val closeButton: KNode = child {
|
||||
hasTestTag(WalletConnectDetailsBottomSheetTestTags.CLOSE_BUTTON)
|
||||
hasTestTag(BaseBottomSheetTestTags.CLOSE_BUTTON)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,21 @@ class WalletConnectPageObject(semanticsProvider: SemanticsNodeInteractionsProvid
|
|||
hasText(getResourceString(R.string.wc_new_connection))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val walletConnectImage: KNode = child {
|
||||
hasTestTag(WalletConnectScreenTestTags.WALLET_CONNECT_IMAGE)
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val noSessionTitle: KNode = child {
|
||||
hasText(getResourceString(R.string.wc_no_sessions_title))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
|
||||
val noSessionText: KNode = child {
|
||||
hasText(getResourceString(R.string.wc_no_sessions_desc))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onWalletConnectScreen(function: WalletConnectPageObject.() -> Unit) =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
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 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 WalletConnectScanQrPageObject(semanticsProvider: SemanticsNodeInteractionsProvider) :
|
||||
ComposeScreen<WalletConnectScanQrPageObject>(semanticsProvider = semanticsProvider) {
|
||||
|
||||
val pasteFromClipboardButton: KNode = child {
|
||||
hasTestTag(BaseButtonTestTags.TEXT)
|
||||
hasText(getResourceString(R.string.wallet_connect_paste_from_clipboard))
|
||||
useUnmergedTree = true
|
||||
}
|
||||
}
|
||||
|
||||
internal fun BaseTestCase.onWalletConnectScanQrScreen(function: WalletConnectScanQrPageObject.() -> Unit) =
|
||||
onComposeScreen(composeTestRule, function)
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.steps
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.assertElementDoesNotExist
|
||||
import com.tangem.screens.onMainScreen
|
||||
import io.qameta.allure.kotlin.Allure.step
|
||||
|
||||
fun BaseTestCase.checkSingleCurrencyMainScreen(cardBlockchain: String, cardTitle: String) {
|
||||
step("Assert card title equal '$cardTitle'") {
|
||||
onMainScreen { walletNameText.assertTextEquals(cardTitle) }
|
||||
}
|
||||
step("Assert 'Transactions' block is displayed") {
|
||||
onMainScreen { transactionsExplorer().assertExists() }
|
||||
}
|
||||
step("Assert 'Transactions' title is displayer") {
|
||||
onMainScreen { transactionsTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Explorer Icon' is displayed") {
|
||||
onMainScreen { transactionsExplorerIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert card image is displayed") { //TODO: Придумать нормальную проверку / реализовать скриншот-тестинг
|
||||
onMainScreen { walletImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' on single card main screen is displayed") {
|
||||
onMainScreen { marketPriceBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Market Price' title equals $cardBlockchain Market Price") {
|
||||
onMainScreen { marketPriceText.assertTextContains("$cardBlockchain Market Price") }
|
||||
}
|
||||
step("Assert 'Organize tokens' button is not displayed") {
|
||||
onMainScreen {
|
||||
assertElementDoesNotExist({ organizeTokensButtonWithoutLazySearch() }, "Organize tokens button")
|
||||
}
|
||||
}
|
||||
}
|
||||
197
app/src/androidTest/kotlin/com/tangem/tests/BlockchainTest.kt
Normal file
197
app/src/androidTest/kotlin/com/tangem/tests/BlockchainTest.kt
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.CARDANO_ADDRESS
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.pullToRefresh
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
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 BlockchainTest : BaseTestCase() {
|
||||
|
||||
@AllureId("3644")
|
||||
@DisplayName("ADA: Checking the min amount/change = 1ADA")
|
||||
@Test
|
||||
fun adaCheckMinAmountTest() {
|
||||
val tokenName = "Cardano"
|
||||
val errorSendAmount = "0.1"
|
||||
val validSendAmount = "10"
|
||||
val minAmount = "ADA 1.00"
|
||||
val address = CARDANO_ADDRESS
|
||||
val scenarioName = "user_tokens_api"
|
||||
val scenarioState = "Cardano"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(scenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$scenarioName' to state: '$scenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = scenarioName, state = scenarioState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Send' button") {
|
||||
onTokenDetailsScreen { sendButton.performClick() }
|
||||
}
|
||||
step("Type '$errorSendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(errorSendAmount)
|
||||
}
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Type address in input text field") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(address) }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error title is displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error icon is displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorIcon(minAmount).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error message is displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorMessage(minAmount).assertIsDisplayed() }
|
||||
}
|
||||
step("Press system 'Back' button") {
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
step("Assert address text field is displayed") {
|
||||
onSendAddressScreen { addressTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Press system 'Back' button") {
|
||||
device.uiDevice.pressBack()
|
||||
}
|
||||
step("Type '$validSendAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(errorSendAmount)
|
||||
}
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert address text field is displayed") {
|
||||
onSendAddressScreen { addressTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error title is not displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorTitle.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error icon is not displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorIcon(minAmount).assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Invalid amount' error message is not displayed") {
|
||||
onSendConfirmScreen { minimumSendAmountErrorMessage(minAmount).assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("990")
|
||||
@DisplayName("XRP: Check warning")
|
||||
@Test
|
||||
fun xrpCheckWarningTest() {
|
||||
val tokenName = "XRP Ledger"
|
||||
val amount = "1.00"
|
||||
val currencySymbol = "XRP"
|
||||
val userTokensScenarioName = "user_tokens_api"
|
||||
val userTokensScenarioState = "XRP"
|
||||
val rippleAccountInfoScenarioName = "ripple_account_info"
|
||||
val rippleAccountInfoStartedState = "Started"
|
||||
val rippleAccountInfoErrorState = "AccountNotFound"
|
||||
val rippleAccountLinesScenarioName = "ripple_account_lines"
|
||||
val rippleAccountLinesStartedState = "Started"
|
||||
val rippleAccountLinesErrorState = "AccountNotFound"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
resetWireMockScenarioState(userTokensScenarioName)
|
||||
resetWireMockScenarioState(rippleAccountInfoScenarioName)
|
||||
resetWireMockScenarioState(rippleAccountLinesScenarioName)
|
||||
}
|
||||
).run {
|
||||
step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState)
|
||||
}
|
||||
step("Set WireMock scenario: '$rippleAccountInfoScenarioName' to state: '$rippleAccountInfoErrorState'") {
|
||||
setWireMockScenarioState(scenarioName = rippleAccountInfoScenarioName, state = rippleAccountInfoErrorState)
|
||||
}
|
||||
step("Set WireMock scenario: '$rippleAccountLinesScenarioName' to state: '$rippleAccountLinesErrorState'") {
|
||||
setWireMockScenarioState(scenarioName = rippleAccountLinesScenarioName, state = rippleAccountLinesErrorState)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).performClick() }
|
||||
}
|
||||
step("Assert 'Top up wallet' notification title is displayed") {
|
||||
onTokenDetailsScreen { topUpYourWalletNotificationTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Top up wallet' notification message is displayed") {
|
||||
onTokenDetailsScreen {
|
||||
topUpYourWalletNotificationMessage(
|
||||
networkName = tokenName,
|
||||
amount = amount,
|
||||
currencySymbol = currencySymbol,
|
||||
).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'Top up wallet' notification icon is displayed") {
|
||||
onTokenDetailsScreen { topUpYourWalletNotificationIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Set WireMock scenario: '$userTokensScenarioName' to state: '$userTokensScenarioState'") {
|
||||
setWireMockScenarioState(scenarioName = userTokensScenarioName, state = userTokensScenarioState)
|
||||
}
|
||||
step("Set WireMock scenario: '$rippleAccountInfoScenarioName' to state: '$rippleAccountInfoStartedState'") {
|
||||
setWireMockScenarioState(scenarioName = rippleAccountInfoScenarioName, state = rippleAccountInfoStartedState)
|
||||
}
|
||||
step("Set WireMock scenario: '$rippleAccountLinesScenarioName' to state: '$rippleAccountLinesStartedState'") {
|
||||
setWireMockScenarioState(scenarioName = rippleAccountLinesScenarioName, state = rippleAccountLinesStartedState)
|
||||
}
|
||||
step("Pull to refresh") {
|
||||
pullToRefresh()
|
||||
}
|
||||
step("Assert 'Top up wallet' notification title is not displayed") {
|
||||
onTokenDetailsScreen { topUpYourWalletNotificationTitle.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Assert 'Top up wallet' notification message not is displayed") {
|
||||
onTokenDetailsScreen {
|
||||
topUpYourWalletNotificationMessage(
|
||||
networkName = tokenName,
|
||||
amount = amount,
|
||||
currencySymbol = currencySymbol,
|
||||
).assertIsNotDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'Top up wallet' notification icon not is displayed") {
|
||||
onTokenDetailsScreen { topUpYourWalletNotificationIcon.assertIsNotDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.screens.*
|
||||
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
|
||||
|
|
@ -23,7 +21,6 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun errorInProvidersLoadingTest() {
|
||||
val scenarioName = "payment_methods"
|
||||
val tokenTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
|
|
@ -40,7 +37,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -69,12 +66,11 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun validateCurrencySelectorTest() {
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val popularFiatsTitle = "Popular Fiats"
|
||||
val otherCurrenciesTitle = "Other currencies"
|
||||
val australianDollar = "AUD"
|
||||
val fiatAmount = "1"
|
||||
val tokenAmount = "POL 488.24938338"
|
||||
val tokenAmount = "~488.24938338 POL"
|
||||
val scenarioName = "payment_methods"
|
||||
|
||||
step("Reset WireMock scenario '$scenarioName'") {
|
||||
|
|
@ -85,7 +81,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -102,18 +98,6 @@ class BuyTokenTest : BaseTestCase() {
|
|||
step("Write fiat amount = '$fiatAmount'") {
|
||||
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
|
||||
}
|
||||
step("Assert 'Provider loading block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerLoadingTitle.assertIsDisplayed()
|
||||
providerLoadingText.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'Provider block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerTitle.assertIsDisplayed()
|
||||
providerText.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert token amount = '$tokenAmount'") {
|
||||
onBuyTokenDetailsScreen {
|
||||
tokenAmountField.assertTextContains(tokenAmount)
|
||||
|
|
@ -159,10 +143,9 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun validateBuyTokenScreenTest() {
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val euro = "EUR"
|
||||
val fiatAmount = "1"
|
||||
val tokenAmount = "POL 488.24938338"
|
||||
val tokenAmount = "~488.24938338 POL"
|
||||
val scenarioName = "payment_methods"
|
||||
|
||||
step("Reset WireMock scenario '$scenarioName'") {
|
||||
|
|
@ -173,7 +156,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -199,27 +182,45 @@ class BuyTokenTest : BaseTestCase() {
|
|||
step("Assert fiat amount = '$fiatAmount'") {
|
||||
onBuyTokenDetailsScreen { fiatAmountTextField.assertTextContains(euro + fiatAmount) }
|
||||
}
|
||||
step("Assert 'Provider loading block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerLoadingTitle.assertIsDisplayed()
|
||||
providerLoadingText.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'Provider block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerTitle.assertIsDisplayed()
|
||||
providerText.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert token amount = '$tokenAmount'") {
|
||||
onBuyTokenDetailsScreen { tokenAmountField.assertTextContains(tokenAmount) }
|
||||
}
|
||||
step("Assert 'ToS' block is displayed") {
|
||||
onBuyTokenDetailsScreen { toSBlock.assertIsDisplayed()}
|
||||
step("Click on 'Continue' button") {
|
||||
onBuyTokenDetailsScreen { continueButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Recommended' title is displayed") {
|
||||
onBuyTokenDetailsScreen { recommendedTitle.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Best rate' icon is displayed") {
|
||||
onBuyTokenDetailsScreen { bestRateIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Best rate' title is displayed") {
|
||||
onBuyTokenDetailsScreen { bestRateTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert offer amount is displayed") {
|
||||
onBuyTokenDetailsScreen { offerTokenAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onBuyTokenDetailsScreen { buyButton.assertIsDisplayed()}
|
||||
}
|
||||
step("Assert timing icon is displayed") {
|
||||
onBuyTokenDetailsScreen { timingIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Instant' processing time text is displayed") {
|
||||
onBuyTokenDetailsScreen { instantProcessingSpeedText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert provider name is displayed") {
|
||||
onBuyTokenDetailsScreen { providerName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Pay with' is displayed") {
|
||||
onBuyTokenDetailsScreen { payWith.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method icon is displayed") {
|
||||
onBuyTokenDetailsScreen { paymentMethodIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'All offers' button is displayed") {
|
||||
onBuyTokenDetailsScreen { allOffersButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Close' button in top bar is displayed") {
|
||||
onBuyTokenDetailsScreen { topBarCloseButton.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -232,7 +233,6 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun validateResidenceSettingsScreenTest() {
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val country = "Albania"
|
||||
val unavailableCountry = "Lebanon"
|
||||
val scenarioName = "payment_methods"
|
||||
|
|
@ -245,7 +245,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -313,14 +313,10 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun validateProvidersScreenTest() {
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val paymentMethod = "Card"
|
||||
val paymentMethod = "Invoice Revolut Pay"
|
||||
val fiatAmount = "1"
|
||||
val providerNameMercuryo = "Mercuryo"
|
||||
val providerNameSimplex = "Simplex"
|
||||
val tokenAmount = "POL 488.24938338"
|
||||
val bestRate = "Best rate"
|
||||
val rate = "-0.00%"
|
||||
val tokenAmount = "~488.24938338 POL"
|
||||
val scenarioName = "payment_methods"
|
||||
|
||||
step("Reset WireMock scenario '$scenarioName'") {
|
||||
|
|
@ -331,7 +327,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -348,58 +344,53 @@ class BuyTokenTest : BaseTestCase() {
|
|||
step("Write fiat amount = '$fiatAmount'") {
|
||||
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
|
||||
}
|
||||
step("Assert token amount = '$tokenAmount'") {
|
||||
onBuyTokenDetailsScreen { tokenAmountField.assertTextContains(tokenAmount) }
|
||||
}
|
||||
step("Click on 'Continue' button") {
|
||||
onBuyTokenDetailsScreen { continueButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Provider block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerTitle.assertIsDisplayed()
|
||||
providerText.assertIsDisplayed()
|
||||
}
|
||||
onBuyTokenDetailsScreen { providerName.assertIsDisplayed() }
|
||||
}
|
||||
step("Open 'Select Provider' bottom sheet") {
|
||||
onBuyTokenDetailsScreen { providerTitle.performClick() }
|
||||
step("Click on 'All offers' button") {
|
||||
onBuyTokenDetailsScreen { allOffersButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert available provider name is displayed") {
|
||||
onSelectProviderBottomSheet {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
availableProviderItem.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Click on '$paymentMethod' payment method") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithName(paymentMethod).clickWithAssertion() }
|
||||
}
|
||||
step("Click on 'Expand payment methods' button") {
|
||||
onSelectProviderBottomSheet { paymentMethodExpandButton.clickWithAssertion() }
|
||||
}
|
||||
step("Click on payment method: '$paymentMethod'") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(paymentMethod).clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Select Provider' bottom sheet title is displayed") {
|
||||
step("Assert 'Provider' bottom sheet title is displayed") {
|
||||
onSelectProviderBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Provider' bottom sheet subtitle is displayed") {
|
||||
onSelectProviderBottomSheet { subtitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Best rate' icon is displayed") {
|
||||
onSelectProviderBottomSheet { bestRateIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Best rate' title is displayed") {
|
||||
onSelectProviderBottomSheet { bestRateTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert offer token amount is displayed") {
|
||||
onSelectProviderBottomSheet { offerTokenAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Buy' button is displayed") {
|
||||
onSelectProviderBottomSheet { buyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert timing icon is displayed") {
|
||||
onSelectProviderBottomSheet { timingIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Instant' processing time text is displayed") {
|
||||
onSelectProviderBottomSheet { instantProcessingSpeedText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Pay with' text is displayed") {
|
||||
onSelectProviderBottomSheet { payWith.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method icon is displayed") {
|
||||
onSelectProviderBottomSheet { paymentMethodIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method title is displayed") {
|
||||
onSelectProviderBottomSheet { paymentMethodTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method name is displayed") {
|
||||
onSelectProviderBottomSheet { paymentMethodName.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert provider with name: '$providerNameMercuryo' and rate: '$bestRate' is displayed") {
|
||||
onSelectProviderBottomSheet {
|
||||
availableProviderWithName(providerNameMercuryo, tokenAmount, bestRate).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert provider with name: '$providerNameSimplex' and rate: '$rate' is displayed") {
|
||||
onSelectProviderBottomSheet {
|
||||
availableProviderWithName(providerNameSimplex, tokenAmount, rate).assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Assert 'More providers' icon is displayed") {
|
||||
onSelectProviderBottomSheet { moreProvidersIcon.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'More providers' text is displayed") {
|
||||
onSelectProviderBottomSheet { moreProvidersText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Best rate' label is displayed") {
|
||||
onSelectProviderBottomSheet { bestRateLabel.assertIsDisplayed() }
|
||||
step("Assert provider name: '$providerNameMercuryo'") {
|
||||
onSelectProviderBottomSheet { providerName.assertTextContains(providerNameMercuryo) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -410,12 +401,12 @@ class BuyTokenTest : BaseTestCase() {
|
|||
fun validatePaymentMethodScreenTest() {
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val card = "Card"
|
||||
val googlePay = "Google Pay"
|
||||
val invoiceRevolutPay = "Invoice Revolut Pay"
|
||||
val sepa = "Sepa"
|
||||
val fiatAmount = "1"
|
||||
val tokenAmount = "~488.24938338 POL"
|
||||
val scenarioName = "payment_methods"
|
||||
|
||||
step("Reset WireMock scenario '$scenarioName'") {
|
||||
|
|
@ -426,7 +417,7 @@ class BuyTokenTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
|
|
@ -443,40 +434,39 @@ class BuyTokenTest : BaseTestCase() {
|
|||
step("Write fiat amount = '$fiatAmount'") {
|
||||
onBuyTokenDetailsScreen { fiatAmountTextField.performTextInput(fiatAmount) }
|
||||
}
|
||||
step("Assert token amount = '$tokenAmount'") {
|
||||
onBuyTokenDetailsScreen { tokenAmountField.assertTextContains(tokenAmount) }
|
||||
}
|
||||
step("Click on 'Continue' button") {
|
||||
onBuyTokenDetailsScreen { continueButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Provider block' is displayed") {
|
||||
onBuyTokenDetailsScreen {
|
||||
providerTitle.assertIsDisplayed()
|
||||
providerText.assertIsDisplayed()
|
||||
}
|
||||
onBuyTokenDetailsScreen { providerName.assertIsDisplayed() }
|
||||
}
|
||||
step("Open 'Select Provider' bottom sheet") {
|
||||
onBuyTokenDetailsScreen { providerTitle.performClick() }
|
||||
}
|
||||
step("Click on 'Expand payment methods' button") {
|
||||
onSelectProviderBottomSheet { paymentMethodExpandButton.clickWithAssertion() }
|
||||
step("Click on 'All offers' button") {
|
||||
onBuyTokenDetailsScreen { allOffersButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Select Payment Method' bottom sheet title is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Select Payment Method' bottom sheet subtitle is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { subtitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Select Payment Method' bottom sheet close button is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { closeButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method: '$card' is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(card).assertIsDisplayed() }
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithName(card).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method: '$googlePay' is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(googlePay).assertIsDisplayed() }
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithName(googlePay).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method: '$invoiceRevolutPay' is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(invoiceRevolutPay).assertIsDisplayed() }
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithName(invoiceRevolutPay).assertIsDisplayed() }
|
||||
}
|
||||
step("Assert payment method: '$sepa' is displayed") {
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithNameAndIcon(sepa).assertIsDisplayed() }
|
||||
}
|
||||
step("Press 'Back' button") {
|
||||
onSelectPaymentMethodBottomSheet { device.uiDevice.pressBack() }
|
||||
}
|
||||
step("Assert 'Select Provider' bottom sheet title is displayed") {
|
||||
onSelectProviderBottomSheet { title.assertIsDisplayed() }
|
||||
onSelectPaymentMethodBottomSheet { paymentMethodWithName(sepa).assertIsDisplayed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package com.tangem.tests
|
|||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.RECIPIENT_ADDRESS
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
|
|
@ -28,6 +27,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
@DisplayName("Send feedback: from details")
|
||||
@Test
|
||||
fun sendFeedbackFromDetailsTest() {
|
||||
val gmailText = "Welcome to Gmail"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
|
|
@ -42,8 +43,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Click 'Contact support' button") {
|
||||
onDetailsScreen { contactSupportButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
step("Assert 'Gmail' app is open") {
|
||||
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,10 +53,10 @@ class FeedbackTest : BaseTestCase() {
|
|||
@DisplayName("Send feedback: failed transaction")
|
||||
@Test
|
||||
fun sendFeedbackFromFailedTransactionTest() {
|
||||
val balance = TOTAL_BALANCE
|
||||
val tokenName = "Polygon"
|
||||
val recipientAddress = RECIPIENT_ADDRESS
|
||||
val sendAmount = "1"
|
||||
val gmailText = "Welcome to Gmail"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
|
|
@ -66,7 +67,7 @@ class FeedbackTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenName'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenName).clickWithAssertion() }
|
||||
|
|
@ -87,18 +88,23 @@ class FeedbackTest : BaseTestCase() {
|
|||
onSendScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Enter address") {
|
||||
onSendAddressScreen { addressTextField.performTextReplacement(recipientAddress) }
|
||||
onSendAddressScreen { addressTextField.performTextInput(recipientAddress) }
|
||||
}
|
||||
step("Click 'Next' button") {
|
||||
onSendAddressScreen { nextButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert sanding text is displayed") {
|
||||
onSendConfirmScreen { sendingText.assertIsDisplayed() }
|
||||
}
|
||||
step("Click 'Send' button") {
|
||||
waitForIdle()
|
||||
onSendConfirmScreen {
|
||||
sendButton.assertIsEnabled()
|
||||
sendButton.performClick()
|
||||
}
|
||||
}
|
||||
step("Check 'Failed transaction' dialog") {
|
||||
waitForIdle()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkFailedTransactionDialog()
|
||||
}
|
||||
|
|
@ -106,8 +112,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Click on 'Support' button") {
|
||||
onFailedTransactionDialog { supportButton.performClick() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
step("Assert 'Gmail' app is open") {
|
||||
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,6 +122,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
@DisplayName("Send feedback: from 'Warning' dialog after card scan")
|
||||
@Test
|
||||
fun sendFeedbackFromScanScreenTest() {
|
||||
val gmailText = "Welcome to Gmail"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
|
|
@ -138,13 +146,14 @@ class FeedbackTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Check 'Scan warning' dialog") {
|
||||
waitForIdle()
|
||||
checkScanWarningDialog()
|
||||
}
|
||||
step("Click on 'Request support' button") {
|
||||
ScanWarningDialogPageObject { requestSupportButton.click() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
step("Assert 'Gmail' app is open") {
|
||||
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,6 +162,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
@DisplayName("Send feedback: from scan already used wallet alert dialog")
|
||||
@Test
|
||||
fun sendFeedbackAfterScanAlreadyUsedWalletTest() {
|
||||
val gmailText = "Welcome to Gmail"
|
||||
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
device.uiDevice.pressBack()
|
||||
|
|
@ -173,8 +184,8 @@ class FeedbackTest : BaseTestCase() {
|
|||
step("Click on 'Request support' button") {
|
||||
AlreadyUsedWalletDialogPageObject { requestSupportButton.click() }
|
||||
}
|
||||
step("Check 'Contact support' intent is called") {
|
||||
checkSendEMailIntentCalled()
|
||||
step("Assert 'Gmail' app is open") {
|
||||
ThirdPartyAppPageObject { assertElementWithTextExists(gmailText) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
|
|
@ -19,13 +18,12 @@ class HideTokenTest : BaseTestCase() {
|
|||
@Test
|
||||
fun hideWalletTokenByHideButtonTest() {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.tap.domain.sdk.mocks.content.ShibaNoBackupMockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.content.ShibaNoBackupNoWalletsMockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.content.Wallet2NoBackupMockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.content.Wallet2NoBackupNoWalletsMockContent
|
||||
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 OnboardingTest : BaseTestCase() {
|
||||
|
||||
@AllureId("248")
|
||||
@DisplayName("Onboarding: 'Shiba' no wallets backup screen test")
|
||||
@Test
|
||||
fun shibaNoWalletsBackupScreenTest() {
|
||||
setupHooks().run {
|
||||
scanCard(mockContent = ShibaNoBackupNoWalletsMockContent)
|
||||
checkCreateWalletScreenForWalletNoWallets()
|
||||
openAndCheckBackupScreenForWalletNoWallets()
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3989")
|
||||
@DisplayName("Onboarding: 'Shiba' with wallets backup screen test")
|
||||
@Test
|
||||
fun shibaBackupScreenTest() {
|
||||
setupHooks().run {
|
||||
scanCard(
|
||||
mockContent = ShibaNoBackupMockContent,
|
||||
alreadyActivatedDialogIsShown = true
|
||||
)
|
||||
checkBackupScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("246")
|
||||
@DisplayName("Onboarding: 'Wallet 2' no wallets backup screen test")
|
||||
@Test
|
||||
fun wallet2NoWalletsBackupScreenTest() {
|
||||
setupHooks().run {
|
||||
scanCard(mockContent = Wallet2NoBackupNoWalletsMockContent)
|
||||
checkCreateWalletScreenForWallet2NoWallets()
|
||||
openAndCheckBackupScreenForWallet2NoWallets()
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("3990")
|
||||
@DisplayName("Onboarding: 'Wallet 2' with wallets backup screen test")
|
||||
@Test
|
||||
fun wallet2BackupScreenTest() {
|
||||
setupHooks().run {
|
||||
scanCard(
|
||||
mockContent = Wallet2NoBackupMockContent,
|
||||
alreadyActivatedDialogIsShown = true
|
||||
)
|
||||
checkBackupScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.tests
|
|||
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
|
|
@ -92,13 +91,12 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
setupHooks().run {
|
||||
val ethereumTitle = "Ethereum"
|
||||
val bitcoinTitle = "Bitcoin"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Check positions of tokens on 'Main Screen'") {
|
||||
onMainScreen {
|
||||
|
|
@ -179,13 +177,12 @@ class OrganizeTokensTest : BaseTestCase() {
|
|||
val bitcoinTitle = "Bitcoin"
|
||||
val polygonTitle = "Polygon"
|
||||
val polExMaticTitle = "POL (ex-MATIC)"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Check positions of tokens on 'Main Screen'") {
|
||||
onMainScreen {
|
||||
|
|
|
|||
204
app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt
Normal file
204
app/src/androidTest/kotlin/com/tangem/tests/ScanCardTest.kt
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.annotations.ApiEnv
|
||||
import com.tangem.common.annotations.ApiEnvConfig
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.checkMultiCurrencyMainScreen
|
||||
import com.tangem.scenarios.checkSingleCurrencyMainScreen
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.tap.domain.sdk.mocks.MockContent
|
||||
import com.tangem.tap.domain.sdk.mocks.content.*
|
||||
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 ScanCardTest : BaseTestCase() {
|
||||
|
||||
@ApiEnv(
|
||||
ApiEnvConfig(ApiConfig.ID.TangemTech, ApiEnvironment.PROD),
|
||||
ApiEnvConfig(ApiConfig.ID.Express, ApiEnvironment.PROD)
|
||||
)
|
||||
@AllureId("868")
|
||||
@DisplayName("Scan: Scanning single-currency cards")
|
||||
@Test
|
||||
fun singleTokenNoteCardScanTest() {
|
||||
val cardBlockchain = "DOGE"
|
||||
val cardType: ProductType = ProductType.Note
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '${cardType.name}' card") {
|
||||
openMainScreen(cardType)
|
||||
}
|
||||
step("Check 'Main' screen for '${cardType.name}' $cardBlockchain card") {
|
||||
checkSingleCurrencyMainScreen(
|
||||
cardBlockchain = cardBlockchain,
|
||||
cardTitle = cardType.name,
|
||||
withTransactions = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("869")
|
||||
@DisplayName("Scan: 'Twin' card")
|
||||
@Test
|
||||
fun twinsCardScanTest() {
|
||||
val cardBlockchain = "BTC"
|
||||
val cardType: MockContent = TwinsMockContent
|
||||
val cardName = "Twin"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$cardName' card") {
|
||||
openMainScreen(mockContent = cardType, isTwinsCard = true)
|
||||
}
|
||||
step("Check 'Main' screen for '$cardName' $cardBlockchain card") {
|
||||
checkSingleCurrencyMainScreen(cardBlockchain = cardBlockchain, cardTitle = cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("872")
|
||||
@DisplayName("Scan: Card with Secp256k1 curve")
|
||||
@Test
|
||||
fun secpk1CurveCardScanTest() {
|
||||
val devicesCount = "1 device"
|
||||
val cardType: MockContent = Secpk1CurveMockContent
|
||||
val cardName = "Wallet"
|
||||
val card = "card with Secp256k1 curve"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on $card") {
|
||||
openMainScreen(mockContent = cardType, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Check 'Main' screen for $card curve with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(
|
||||
devicesCount = devicesCount,
|
||||
cardTitle = cardName,
|
||||
withWalletImage = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("870")
|
||||
@DisplayName("Scan: Card with Ed25519 curve")
|
||||
@Test
|
||||
fun edCurveCardScanTest() {
|
||||
val cardBlockchain = "XLM"
|
||||
val cardType: MockContent = EdCurveMockContent
|
||||
val cardName = "Tangem card"
|
||||
val card = "card with Ed25519 curve"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on $card") {
|
||||
openMainScreen(mockContent = cardType)
|
||||
}
|
||||
step("Check 'Main' screen for $card with blockchain: '$cardBlockchain'") {
|
||||
checkSingleCurrencyMainScreen(
|
||||
cardBlockchain = cardBlockchain,
|
||||
cardTitle = cardName,
|
||||
withWalletImage = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("866")
|
||||
@DisplayName("Scan: 'Shiba' card")
|
||||
@Test
|
||||
fun shibaCardScanTest() {
|
||||
val devicesCount = "2 devices"
|
||||
val cardType: MockContent = ShibaMockContent
|
||||
val cardName = "Wallet"
|
||||
val card = "Shiba"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$card' card") {
|
||||
openMainScreen(mockContent = cardType, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Check 'Main' screen for '$card' card with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(devicesCount, cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("864")
|
||||
@DisplayName("Scan: 'Ring'")
|
||||
@Test
|
||||
fun ringScanTest() {
|
||||
val devicesCount = "3 devices"
|
||||
val cardType: ProductType = ProductType.Ring
|
||||
val cardName = "Wallet"
|
||||
val ring = "Ring"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$ring'") {
|
||||
openMainScreen(productType = cardType, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Check 'Main' screen for '$ring' with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(devicesCount, cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("867")
|
||||
@DisplayName("Scan: 'Wallet' card")
|
||||
@Test
|
||||
fun walletCardScanTest() {
|
||||
val devicesCount = "1 device"
|
||||
val cardType: ProductType = ProductType.Wallet
|
||||
val cardName = "Wallet"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$cardName' card") {
|
||||
openMainScreen(productType = cardType)
|
||||
}
|
||||
step("Check 'Main' screen for '$cardName' card with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(devicesCount, cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("865")
|
||||
@DisplayName("Scan: 'Wallet 2' card")
|
||||
@Test
|
||||
fun wallet2ScanTest() {
|
||||
val devicesCount = "2 devices"
|
||||
val cardType: MockContent = Wallet2MockContent
|
||||
val cardName = "Wallet"
|
||||
val card = "Wallet 2"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$card' card") {
|
||||
openMainScreen(mockContent = cardType, alreadyActivatedDialogIsShown = true)
|
||||
}
|
||||
step("Check 'Main' screen for '$card' card with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(devicesCount, cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("871")
|
||||
@DisplayName("Scan: Card with 4.12 firmware")
|
||||
@Test
|
||||
fun firmware412CardScanTest() {
|
||||
val devicesCount = "1 device"
|
||||
val cardType: MockContent = Firmware412MockContent
|
||||
val cardName = "Tangem card"
|
||||
val card = "card with 4.12 firmware"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on '$card'") {
|
||||
openMainScreen(mockContent = cardType)
|
||||
}
|
||||
step("Check 'Main' screen for '$card' with devices count = '$devicesCount'") {
|
||||
checkMultiCurrencyMainScreen(devicesCount, cardName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
|
|
@ -23,7 +25,6 @@ class SendTest : BaseTestCase() {
|
|||
val currencyName = "POL (ex-MATIC)"
|
||||
val feeCurrencyName = "Ethereum"
|
||||
val feeCurrencySymbol = "ETH"
|
||||
val balance = "$763.55"
|
||||
val scenarioName = "eth_network_balance"
|
||||
val scenarioState = "Empty"
|
||||
|
||||
|
|
@ -40,7 +41,10 @@ class SendTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on token with name: $currencyName") {
|
||||
onMainScreen { tokenWithTitleAndAddress(currencyName).clickWithAssertion() }
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.steps.checkSingleCurrencyMainScreen
|
||||
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 SingleCurrencyCardsScan : BaseTestCase() {
|
||||
|
||||
@AllureId("868")
|
||||
@DisplayName("Scan: Scanning single-currency cards")
|
||||
@Test
|
||||
fun singleTokenNoteScanTest() {
|
||||
val cardBlockchain = "DOGE"
|
||||
val cardType: ProductType = ProductType.Note
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen' on ${cardType.name} card") {
|
||||
openMainScreen(cardType)
|
||||
}
|
||||
step("Check 'Main' screen for ${cardType.name} $cardBlockchain card") {
|
||||
checkSingleCurrencyMainScreen(cardBlockchain = cardBlockchain, cardTitle = cardType.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.resetWireMockScenarioState
|
||||
import com.tangem.common.utils.setWireMockScenarioState
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -21,7 +21,6 @@ class StakingTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateStakingBlockTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val balance = "$3,299.37"
|
||||
val scenarioName = "staking_eth_pol_balances_android"
|
||||
val scenarioState = "Staked"
|
||||
|
||||
|
|
@ -39,11 +38,14 @@ class StakingTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
|
|
@ -76,7 +78,6 @@ class StakingTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateStakingMoreScreensTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val balance = "$3,299.37"
|
||||
val scenarioName = "staking_eth_pol_balances_android"
|
||||
val scenarioState = "Staked"
|
||||
val stakingAmount = "1"
|
||||
|
|
@ -95,11 +96,14 @@ class StakingTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
|
|
@ -109,116 +113,20 @@ class StakingTest : BaseTestCase() {
|
|||
step("Click on 'Staking block'") {
|
||||
onTokenDetailsScreen { stakingBlock.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Title' is displayed") {
|
||||
onStakingDetailsScreen { stakingTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Annual percentage rate' is displayed") {
|
||||
onStakingDetailsScreen { annualPercentageRate.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Available' block is displayed") {
|
||||
onStakingDetailsScreen { availableBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Unbonding Period' block is displayed") {
|
||||
onStakingDetailsScreen { unbondingPeriodBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward claiming' block is displayed") {
|
||||
onStakingDetailsScreen { rewardClaimingBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward schedule' block is displayed") {
|
||||
onStakingDetailsScreen { rewardScheduleBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Rewards block' is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Rewards block' title is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlockTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Rewards block' text is displayed") {
|
||||
onStakingDetailsScreen { rewardsBlockText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Active staking block' is displayed") {
|
||||
onStakingDetailsScreen { activeStakingBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Your stakes' title is displayed") {
|
||||
onStakingDetailsScreen { yourStakesTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'ToS' text is displayed") {
|
||||
onStakingDetailsScreen { toSText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake more' button is displayed") {
|
||||
onStakingDetailsScreen { stakeMoreButton.assertIsDisplayed() }
|
||||
step("Check 'Staking details' screen") {
|
||||
checkStakingDetailsScreen(withStaking = true)
|
||||
}
|
||||
step("Click 'Stake more' button") {
|
||||
onStakingDetailsScreen { stakeMoreButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send' screen is displayed") {
|
||||
onSendScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' screen title is displayed") {
|
||||
onSendScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container title is displayed") {
|
||||
onSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container text is displayed") {
|
||||
onSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert input text field is displayed") {
|
||||
onSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Type '$stakingAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(stakingAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$stakingAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Max' button is displayed") {
|
||||
onSendScreen { maxButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert previous button is displayed") {
|
||||
onSendScreen { previousButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Next' button is displayed") {
|
||||
onSendScreen { nextButton.assertIsDisplayed() }
|
||||
step("Check 'Staking' screen") {
|
||||
checkStakingScreen(stakingAmount)
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send details' screen title is displayed") {
|
||||
onStakingConfirmScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onStakingConfirmScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingConfirmScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Validator' block is displayed") {
|
||||
onStakingConfirmScreen { validatorBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Network Fee' block is displayed") {
|
||||
onStakingConfirmScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingConfirmScreen { stakeButton.assertIsDisplayed() }
|
||||
step("Check 'Staking confirm' screen") {
|
||||
checkStakingConfirmScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +136,6 @@ class StakingTest : BaseTestCase() {
|
|||
@Test
|
||||
fun validateStakingScreensTest() {
|
||||
val tokenTitle = "POL (ex-MATIC)"
|
||||
val balance = TOTAL_BALANCE
|
||||
val scenarioName = "staking_eth_pol_balances_android"
|
||||
val scenarioState = "Started"
|
||||
val stakingAmount = "1"
|
||||
|
|
@ -247,11 +154,14 @@ class StakingTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert 'Organize tokens' button is displayed") {
|
||||
onMainScreen { organizeTokensButton().assertIsDisplayed() }
|
||||
}
|
||||
step("Swipe up") {
|
||||
swipeVertical(SwipeDirection.UP)
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
}
|
||||
|
|
@ -273,107 +183,20 @@ class StakingTest : BaseTestCase() {
|
|||
step("Click on 'Stake' button") {
|
||||
onTokenDetailsScreen { stakeButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Title' is displayed") {
|
||||
onStakingDetailsScreen { stakingTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert banner image is displayed") {
|
||||
onStakingDetailsScreen { bannerImage.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert banner text is displayed") {
|
||||
onStakingDetailsScreen { bannerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Annual percentage rate' is displayed") {
|
||||
onStakingDetailsScreen { annualPercentageRate.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Available' block is displayed") {
|
||||
onStakingDetailsScreen { availableBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Unbonding Period' block is displayed") {
|
||||
onStakingDetailsScreen { unbondingPeriodBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward claiming' block is displayed") {
|
||||
onStakingDetailsScreen { rewardClaimingBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Reward schedule' block is displayed") {
|
||||
onStakingDetailsScreen { rewardScheduleBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'ToS' text is displayed") {
|
||||
onStakingDetailsScreen { toSText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingDetailsScreen { stakeButton.assertIsDisplayed() }
|
||||
step("Check 'Staking details' screen") {
|
||||
checkStakingDetailsScreen(withStaking = false)
|
||||
}
|
||||
step("Click 'Stake' button") {
|
||||
onStakingDetailsScreen { stakeButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send' screen is displayed") {
|
||||
onSendScreen { screenContainer.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Send' screen title is displayed") {
|
||||
onSendScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container title is displayed") {
|
||||
onSendScreen { amountContainerTitle.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert amount container text is displayed") {
|
||||
onSendScreen { amountContainerText.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert input text field is displayed") {
|
||||
onSendScreen { amountInputTextField.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onSendScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Type '$stakingAmount' in input text field") {
|
||||
onSendScreen {
|
||||
amountInputTextField.performClick()
|
||||
amountInputTextField.performTextReplacement(stakingAmount)
|
||||
}
|
||||
}
|
||||
step("Assert input text field has value: '$stakingAmount'") {
|
||||
onSendScreen { amountInputTextField.assertTextContains(value = stakingAmount, substring = true) }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert currency button is displayed") {
|
||||
onSendScreen { currencyButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert fiat button is displayed") {
|
||||
onSendScreen { fiatButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Max' button is displayed") {
|
||||
onSendScreen { maxButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert previous button is displayed") {
|
||||
onSendScreen { previousButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Next' button is displayed") {
|
||||
onSendScreen { nextButton.assertIsDisplayed() }
|
||||
step("Check 'Staking' screen") {
|
||||
checkStakingScreen(stakingAmount)
|
||||
}
|
||||
step("Click on 'Next' button") {
|
||||
onSendScreen { nextButton.performClick() }
|
||||
}
|
||||
step("Assert 'Send details' screen title is displayed") {
|
||||
onStakingConfirmScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert primary amount is displayed") {
|
||||
onStakingConfirmScreen { primaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert secondary amount is displayed") {
|
||||
onStakingConfirmScreen { secondaryAmount.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Validator' block is displayed") {
|
||||
onStakingConfirmScreen { validatorBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Network Fee' block is displayed") {
|
||||
onStakingConfirmScreen { networkFeeBlock.assertIsDisplayed() }
|
||||
}
|
||||
step("Assert 'Stake' button is displayed") {
|
||||
onStakingConfirmScreen { stakeButton.assertIsDisplayed() }
|
||||
step("Check 'Staking confirm' screen") {
|
||||
checkStakingConfirmScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@ import androidx.compose.ui.test.hasText
|
|||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.annotations.ApiEnv
|
||||
import com.tangem.common.annotations.ApiEnvConfig
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT_LONG
|
||||
import com.tangem.common.extensions.*
|
||||
import com.tangem.common.utils.resetWireMockScenarios
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.screens.*
|
||||
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
|
||||
|
|
@ -28,15 +29,16 @@ class SwapTokenTest : BaseTestCase() {
|
|||
@Test
|
||||
fun networkFeeTest() {
|
||||
val inputAmount = "100"
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
val tokenTitle = "Polygon"
|
||||
|
||||
setupHooks().run {
|
||||
|
||||
resetWireMockScenarios()
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -71,7 +73,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Input swap amount = '$inputAmount'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onSwapTokenScreen {
|
||||
textInput.clickWithAssertion()
|
||||
textInput.performTextReplacement(inputAmount)
|
||||
|
|
@ -89,7 +91,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Assert 'Network fee' block is displayed") {
|
||||
onSwapTokenScreen {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
networkFeeBlock.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
|
|
@ -104,15 +106,19 @@ class SwapTokenTest : BaseTestCase() {
|
|||
@DisplayName("Swap: network error test")
|
||||
@Test
|
||||
fun networkErrorSwapTest() {
|
||||
setupHooks().run {
|
||||
setupHooks(
|
||||
additionalAfterSection = {
|
||||
enableWiFi()
|
||||
enableMobileData()
|
||||
}
|
||||
).run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -120,6 +126,10 @@ class SwapTokenTest : BaseTestCase() {
|
|||
step("Click on token with name: '$tokenTitle'") {
|
||||
onTokenDetailsScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
step("Turn off Wi-Fi and Mobile Data") {
|
||||
disableWiFi()
|
||||
disableMobileData()
|
||||
}
|
||||
step("Click on 'Swap' button") {
|
||||
onTokenDetailsScreen { swapButton.performClick() }
|
||||
}
|
||||
|
|
@ -151,13 +161,12 @@ class SwapTokenTest : BaseTestCase() {
|
|||
val inputAmount = "100"
|
||||
setupHooks().run {
|
||||
val tokenTitle = "Polygon"
|
||||
val balance = TOTAL_BALANCE
|
||||
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on token with name: '$tokenTitle'") {
|
||||
onMainScreen { tokenWithTitleAndAddress(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -189,7 +198,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Input swap amount = '$inputAmount'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onSwapTokenScreen {
|
||||
textInput.clickWithAssertion()
|
||||
textInput.performTextReplacement(inputAmount)
|
||||
|
|
@ -200,7 +209,7 @@ class SwapTokenTest : BaseTestCase() {
|
|||
}
|
||||
step("Click on 'Network fee' block") {
|
||||
onSwapTokenScreen {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT_LONG) {
|
||||
networkFeeBlock.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.tangem.tests
|
|||
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.extensions.launchApp
|
||||
import com.tangem.common.extensions.stopApp
|
||||
import com.tangem.screens.onDisclaimerScreen
|
||||
import com.tangem.screens.onStoriesScreen
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
|
|
@ -49,8 +49,9 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
@Test
|
||||
fun acceptTermsOfServiceAfterAppRestart() {
|
||||
val packageName = getTargetContext().packageName
|
||||
val tosUrl = "https://tangem.com/tangem_tos.html"
|
||||
|
||||
setupHooks().run {
|
||||
val tosUrl = "https://tangem.com/tangem_tos.html"
|
||||
step("Assert title of 'Disclaimer screen' is displayed") {
|
||||
onDisclaimerScreen { title.assertIsDisplayed() }
|
||||
}
|
||||
|
|
@ -65,14 +66,11 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
step("'Accept' button is displayed") {
|
||||
onDisclaimerScreen { acceptButton.assertIsDisplayed() }
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
step("Stop app") {
|
||||
stopApp(packageName)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
launchApp(packageName)
|
||||
}
|
||||
step("Assert title of 'Disclaimer screen' is displayed") {
|
||||
onDisclaimerScreen { title.assertIsDisplayed() }
|
||||
|
|
@ -86,16 +84,22 @@ class TermsOfServiceTest : BaseTestCase() {
|
|||
}
|
||||
}
|
||||
step("Click on 'Accept' button") {
|
||||
onDisclaimerScreen { acceptButton.clickWithAssertion() }
|
||||
onDisclaimerScreen {
|
||||
waitForIdle()
|
||||
acceptButton.clickWithAssertion()
|
||||
}
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
scanButton.assertIsDisplayed()
|
||||
orderButton.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.5f)
|
||||
step("Stop app") {
|
||||
stopApp(packageName)
|
||||
}
|
||||
step("Launch app") {
|
||||
device.apps.launch(packageName)
|
||||
launchApp(packageName)
|
||||
}
|
||||
step("Assert 'Stories' screen is opened") {
|
||||
onStoriesScreen {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
package com.tangem.tests
|
||||
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.common.extensions.SwipeDirection
|
||||
import com.tangem.common.constants.TestConstants.WAIT_UNTIL_TIMEOUT
|
||||
import com.tangem.common.extensions.clickWithAssertion
|
||||
import com.tangem.common.extensions.swipeVertical
|
||||
import com.tangem.common.utils.getWcUri
|
||||
import com.tangem.common.utils.setClipboardText
|
||||
import com.tangem.scenarios.*
|
||||
import com.tangem.screens.*
|
||||
import com.tangem.screens.onWalletConnectBottomSheet
|
||||
import com.tangem.screens.onWalletConnectDetailsBottomSheet
|
||||
import com.tangem.screens.onWalletConnectScanQrScreen
|
||||
import com.tangem.screens.onWalletConnectScreen
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.hilt.android.testing.HiltAndroidTest
|
||||
import io.qameta.allure.kotlin.AllureId
|
||||
import io.qameta.allure.kotlin.junit4.DisplayName
|
||||
|
|
@ -21,8 +24,7 @@ class WalletConnectTest : BaseTestCase() {
|
|||
@DisplayName("WC (React App): open session from deeplink on main screen")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSessionOnMainScreen() {
|
||||
val balance = TOTAL_BALANCE
|
||||
fun openWalletConnectSessionOnMainScreenTest() {
|
||||
val dAppName = "React App"
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
|
|
@ -31,25 +33,34 @@ class WalletConnectTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
}
|
||||
step("Assert 'Connect' button is enabled") {
|
||||
onWalletConnectBottomSheet { connectButton.assertIsEnabled() }
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
step("Assert 'Connect' button is not displayed") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
step("Open 'Wallet Connect' screen") {
|
||||
openWalletConnectScreen()
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
step("Check 'Wallet Connect' screen with connections") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectScreen(withConnections = true)
|
||||
}
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
|
|
@ -57,11 +68,11 @@ class WalletConnectTest : BaseTestCase() {
|
|||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
step("Click on 'Disconnect' button") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
step("Check 'Wallet Connect' screen without connections") {
|
||||
checkWalletConnectScreen(withConnections = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,8 +81,7 @@ class WalletConnectTest : BaseTestCase() {
|
|||
@DisplayName("WC (React App): open session from deeplink not on main screen")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSessionNotOnMainScreen() {
|
||||
val balance = TOTAL_BALANCE
|
||||
fun openWalletConnectSessionNotOnMainScreenTest() {
|
||||
val dAppName = "React App"
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
|
|
@ -80,43 +90,46 @@ class WalletConnectTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Click on 'Buy' button") {
|
||||
onMainScreen { buyButton.clickWithAssertion() }
|
||||
step("Open 'Wallet Connect' screen") {
|
||||
openWalletConnectScreen()
|
||||
checkWalletConnectScreen(false)
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
step("Assert 'Connect' button is not displayed") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Assert 'Wallet Connect' bottom sheet is displayed") {
|
||||
onWalletConnectBottomSheet { connectButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
step("Check 'Wallet Connect' screen with connections") {
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectScreen(withConnections = true)
|
||||
}
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
step("Click on 'Disconnect' button") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
step("Check 'Wallet Connect' screen without connections") {
|
||||
checkWalletConnectScreen(withConnections = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -125,9 +138,9 @@ class WalletConnectTest : BaseTestCase() {
|
|||
@DisplayName("WC (React App): open session from deeplink ")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSession() {
|
||||
val balance = TOTAL_BALANCE
|
||||
fun openWalletConnectSessionTest() {
|
||||
val dAppName = "React App"
|
||||
val packageName = BuildConfig.APPLICATION_ID
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
setupHooks().run {
|
||||
|
|
@ -135,34 +148,30 @@ class WalletConnectTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(balance)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open recent apps") {
|
||||
device.uiDevice.pressRecentApps()
|
||||
}
|
||||
step("Stop app by swipe") {
|
||||
swipeVertical(SwipeDirection.UP, startHeightRatio = 0.8f)
|
||||
step("Kill app") {
|
||||
device.apps.kill(packageName)
|
||||
}
|
||||
step("Create WC session buy deeplink") {
|
||||
openAppByDeepLink(deepLinkUri)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
checkWalletConnectBottomSheet()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Click 'More' button on TopBar") {
|
||||
onTopBar { moreButton.clickWithAssertion() }
|
||||
step("Assert 'Connect' button is not displayed") {
|
||||
onWalletConnectBottomSheet { connectButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Click on 'Wallet Connect' button") {
|
||||
onDetailsScreen { walletConnectButton.clickWithAssertion() }
|
||||
step("Open 'Wallet Connect' screen") {
|
||||
openWalletConnectScreen()
|
||||
}
|
||||
step("Check 'Wallet Connect' screen") {
|
||||
checkWalletConnectScreen()
|
||||
step("Check 'Wallet Connect' screen with connections") {
|
||||
checkWalletConnectScreen(withConnections = true)
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
|
|
@ -170,11 +179,71 @@ class WalletConnectTest : BaseTestCase() {
|
|||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect button' is displayed") {
|
||||
step("Click on 'Disconnect' button") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Assert connection is not displayed") {
|
||||
onWalletConnectScreen { appName.assertIsNotDisplayed() }
|
||||
step("Check 'Wallet Connect' screen without connections") {
|
||||
checkWalletConnectScreen(withConnections = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AllureId("887")
|
||||
@DisplayName("WC: open session by 'Paste from clipboard' button")
|
||||
@Ignore("TODO [REDACTED_JIRA] React app deeplink doesn't work")
|
||||
@Test
|
||||
fun openWalletConnectSessionByClipboardLinkTest() {
|
||||
val dAppName = "React App"
|
||||
val context = device.context
|
||||
val deepLinkUri = getWcUri()
|
||||
|
||||
setupHooks().run {
|
||||
step("Set URI to clipboard") {
|
||||
setClipboardText(context, deepLinkUri)
|
||||
}
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Open 'Wallet Connect' screen") {
|
||||
openWalletConnectScreen()
|
||||
}
|
||||
step("Click 'New connection' button") {
|
||||
onWalletConnectScreen { newConnectionButton.performClick() }
|
||||
}
|
||||
step("CLick 'Paste from clipboard' button") {
|
||||
onWalletConnectScanQrScreen { pasteFromClipboardButton.clickWithAssertion() }
|
||||
}
|
||||
step("Check 'Wallet Connect' bottom sheet") {
|
||||
waitForIdle()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
checkWalletConnectBottomSheet()
|
||||
}
|
||||
}
|
||||
step("Click on 'Connect' button") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.performClick() }
|
||||
}
|
||||
step("Assert 'Connect' button is not displayed") {
|
||||
waitForIdle()
|
||||
onWalletConnectBottomSheet { connectButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen with connections") {
|
||||
checkWalletConnectScreen(withConnections = true)
|
||||
}
|
||||
step("Click on app icon") {
|
||||
onWalletConnectScreen { appIcon.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' details bottom sheet") {
|
||||
checkWalletConnectDetailsBottomSheet(dAppName)
|
||||
}
|
||||
step("Click on 'Disconnect' button") {
|
||||
onWalletConnectDetailsBottomSheet { disconnectButton.performClick() }
|
||||
}
|
||||
step("Check 'Wallet Connect' screen without connections") {
|
||||
checkWalletConnectScreen(withConnections = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,394 @@
|
|||
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.WAIT_UNTIL_TIMEOUT
|
||||
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 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"
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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 bitcoinAddress = BITCOIN_ADDRESS
|
||||
|
||||
setupHooks(
|
||||
additionalBeforeSection = {
|
||||
clearClipboard()
|
||||
},
|
||||
additionalAfterSection = {
|
||||
clearClipboard()
|
||||
}
|
||||
).run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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") {
|
||||
waitForIdle()
|
||||
flakySafely(WAIT_UNTIL_TIMEOUT) {
|
||||
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 url = "sell.moonpay.com"
|
||||
val useWithoutAccount = "Use without an account"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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") {
|
||||
ThirdPartyAppPageObject { assertChromeIsOpened() }
|
||||
}
|
||||
if (ThirdPartyAppPageObject.isElementWithTextExists(useWithoutAccount)) {
|
||||
step("Click on '$useWithoutAccount' button on Chrome browser") {
|
||||
ThirdPartyAppPageObject { clickOnElementWithText(useWithoutAccount) }
|
||||
}
|
||||
}
|
||||
step("Assert url contains: '$url'") {
|
||||
ThirdPartyAppPageObject { assertUrlContains(url) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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"
|
||||
|
||||
setupHooks().run {
|
||||
step("Open 'Main Screen'") {
|
||||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses()
|
||||
}
|
||||
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() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ package com.tangem.tests.balance
|
|||
|
||||
import androidx.compose.ui.test.longClick
|
||||
import com.tangem.common.BaseTestCase
|
||||
import com.tangem.common.constants.TestConstants.TOTAL_BALANCE
|
||||
import com.tangem.scenarios.openMainScreen
|
||||
import com.tangem.scenarios.synchronizeAddresses
|
||||
import com.tangem.screens.onMainScreen
|
||||
|
|
@ -23,7 +22,7 @@ class TotalBalanceLongTapTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Long tap on total balance block") {
|
||||
onMainScreen {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class TotalBalanceUnavailableTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
synchronizeAddresses(isBalanceAvailable = false)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
|
|
@ -88,7 +88,7 @@ class TotalBalanceUnavailableTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
synchronizeAddresses(isBalanceAvailable = false)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
|
|
@ -125,7 +125,7 @@ class TotalBalanceUnavailableTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(DASH_SIGN)
|
||||
synchronizeAddresses(isBalanceAvailable = false)
|
||||
}
|
||||
step("Assert 'Synchronize addresses' button does not exist") {
|
||||
onMainScreen {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
|
|
@ -67,14 +67,14 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Open 'Markets screen'") {
|
||||
swipeMarketsBlock(SwipeDirection.UP)
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
}
|
||||
step("Click on $tokenTitle token") {
|
||||
onMarketsScreen { tokenWithTitle(tokenTitle).clickWithAssertion() }
|
||||
|
|
@ -95,7 +95,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
onDialog { continueButton.assertIsNotDisplayed() }
|
||||
}
|
||||
step("Go back to 'Markets: tokens list'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onMarketsScreen { topBarBackButton.clickWithAssertion() }
|
||||
}
|
||||
step("Close 'Markets screen'") {
|
||||
|
|
@ -117,7 +117,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
|
|
@ -145,13 +145,13 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
}
|
||||
step("Long click on token with name: '$tokenTitle'") {
|
||||
composeTestRule.waitForIdle()
|
||||
waitForIdle()
|
||||
onMainScreen {
|
||||
tokenWithTitleAndAddress(tokenTitle).performTouchInput {
|
||||
longClick(
|
||||
|
|
@ -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 {
|
||||
|
|
@ -187,7 +187,7 @@ class TotalBalanceUpdateTest : BaseTestCase() {
|
|||
openMainScreen()
|
||||
}
|
||||
step("Synchronize addresses") {
|
||||
synchronizeAddresses(TOTAL_BALANCE)
|
||||
synchronizeAddresses()
|
||||
}
|
||||
step("Assert $TOTAL_BALANCE is displayed in total balance") {
|
||||
onMainScreen { totalBalanceText.assertTextContains(TOTAL_BALANCE) }
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
<application
|
||||
android:name="com.tangem.tap.TangemHiltApplication"
|
||||
android:theme="@style/AppTheme"
|
||||
android:allowBackup="false"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import com.tangem.domain.apptheme.repository.AppThemeModeRepository
|
|||
import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.onboarding.SaveTwinsOnboardingShownUseCase
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ object ForegroundActivityObserver {
|
|||
|
||||
val foregroundActivity: AppCompatActivity?
|
||||
get() = activities.entries
|
||||
.firstOrNull {
|
||||
Timber.i("foregroundActivity: ${it.key} | ${it.value.isDestroyed}")
|
||||
it.value.isDestroyed == false
|
||||
.firstOrNull { entry ->
|
||||
Timber.i("foregroundActivity: ${entry.key} | ${entry.value.isDestroyed}")
|
||||
entry.value.isDestroyed == false
|
||||
}
|
||||
?.value
|
||||
|
||||
|
|
@ -28,9 +28,9 @@ object ForegroundActivityObserver {
|
|||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
Timber.i("onActivityResumed ${activity::class}")
|
||||
(activity as? AppCompatActivity)?.let {
|
||||
if (activity is AppCompatActivity) {
|
||||
Timber.i("onActivityResumed store activity")
|
||||
activities[activity::class] = it
|
||||
activities[activity::class] = activity
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import android.content.Context
|
|||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.tap.LockTimerWorker.Companion.TAG
|
||||
|
|
@ -22,6 +22,7 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class LockUserWalletsTimer(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import com.tangem.domain.apptheme.model.AppThemeMode
|
|||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.settings.SetGooglePayAvailabilityUseCase
|
||||
import com.tangem.domain.settings.SetGoogleServicesAvailabilityUseCase
|
||||
import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase
|
||||
|
|
@ -264,7 +264,7 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
tangemSdkManager = injectedTangemSdkManager
|
||||
|
||||
backupServiceHolder.createAndSetService(cardSdkConfigRepository.sdk, this)
|
||||
backupService = backupServiceHolder.backupService.get()!! // will be deleted eventually
|
||||
backupService = requireNotNull(backupServiceHolder.backupService.get()) // will be deleted eventually
|
||||
|
||||
lockUserWalletsTimer = LockUserWalletsTimer(
|
||||
context = this,
|
||||
|
|
@ -371,17 +371,15 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
val fromPush = intent?.extras?.containsKey(OPENED_FROM_GCM_PUSH) ?: false
|
||||
if (fromPush) {
|
||||
val isFromPush = intent.extras?.containsKey(OPENED_FROM_GCM_PUSH) == true
|
||||
if (isFromPush) {
|
||||
analyticsEventsHandler.send(Push.PushNotificationOpened)
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = true)
|
||||
}
|
||||
handleDeepLink(intent = intent, isFromOnNewIntent = true)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
|
|
@ -406,8 +404,8 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
val result = WindowObscurationObserver.dispatchTouchEvent(event, analyticsEventsHandler)
|
||||
return if (result) super.dispatchTouchEvent(event) else false
|
||||
val isHandled = WindowObscurationObserver.dispatchTouchEvent(event, analyticsEventsHandler)
|
||||
return if (isHandled) super.dispatchTouchEvent(event) else false
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
|
|
@ -451,9 +449,9 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
|
|||
getPolkadotCheckHasImmortalUseCase()
|
||||
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||
.distinctUntilChanged()
|
||||
.collect {
|
||||
.collect { (_, hasImmortalTransaction) ->
|
||||
analyticsEventsHandler.send(
|
||||
WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(it.second),
|
||||
WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(hasImmortalTransaction),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ lateinit var store: Store<AppState>
|
|||
val foregroundActivityObserver = ForegroundActivityObserver
|
||||
internal lateinit var derivationsFinder: DerivationsFinder
|
||||
|
||||
abstract class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
|
||||
open class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
|
||||
|
||||
// region DI
|
||||
private val entryPoint: ApplicationEntryPoint
|
||||
|
|
@ -290,7 +290,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
|
|||
/**
|
||||
* Initialize components that need to be initialized before [super.onCreate] is called
|
||||
*/
|
||||
private fun preInit() {
|
||||
fun preInit() {
|
||||
tangemAppLoggerInitializer.initialize()
|
||||
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package com.tangem.tap.common
|
|||
object TestActions {
|
||||
|
||||
// It used only for the test actions in debug or debug_beta builds
|
||||
var testAmountInjectionForWalletManagerEnabled = false
|
||||
var isTestAmountInjectionForWalletManagerEnabled = false
|
||||
}
|
||||
|
||||
typealias TestAction = Pair<String, () -> Unit>
|
||||
|
|
@ -58,7 +58,7 @@ private class BlockchainSdkErrorConverter(
|
|||
if (value.customMessage.contains(DemoTransactionSender.ID)) return emptyMap()
|
||||
|
||||
if (value is BlockchainSdkError.WrappedTangemError) {
|
||||
return (value.tangemError as? TangemSdkError)?.let { cardSdkErrorConverter.convert(it) } ?: emptyMap()
|
||||
return (value.tangemError as? TangemSdkError)?.let { cardSdkErrorConverter.convert(it) }.orEmpty()
|
||||
}
|
||||
|
||||
return mapOf(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
|||
*/
|
||||
sealed class Chat(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent("Chat", event, params) {
|
||||
|
||||
class ScreenOpened : Chat("Chat Screen Opened")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
|||
sealed class Onboarding(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
class Started : Onboarding("Onboarding", "Onboarding Started")
|
||||
|
|
@ -16,7 +16,7 @@ sealed class Onboarding(
|
|||
|
||||
sealed class CreateWallet(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Create Wallet", event, params) {
|
||||
|
||||
class ScreenOpened : CreateWallet("Create Wallet Screen Opened")
|
||||
|
|
@ -36,7 +36,7 @@ sealed class Onboarding(
|
|||
|
||||
sealed class Backup(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Backup", event, params) {
|
||||
|
||||
class ScreenOpened : Backup("Backup Screen Opened")
|
||||
|
|
@ -64,7 +64,7 @@ sealed class Onboarding(
|
|||
|
||||
sealed class Topup(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Top Up", event, params) {
|
||||
|
||||
class ScreenOpened : Topup("Activation Screen Opened")
|
||||
|
|
@ -79,7 +79,7 @@ sealed class Onboarding(
|
|||
|
||||
sealed class Twins(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Onboarding("Onboarding / Twins", event, params) {
|
||||
|
||||
class ScreenOpened : Twins("Twinning Screen Opened")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
|||
sealed class Settings(
|
||||
category: String = "Settings",
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
class ScreenOpened : Settings(event = "Settings Screen Opened")
|
||||
|
|
@ -17,7 +17,7 @@ sealed class Settings(
|
|||
|
||||
sealed class CardSettings(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Settings("Settings / Card Settings", event, params) {
|
||||
|
||||
class ButtonFactoryReset : CardSettings("Button - Factory Reset")
|
||||
|
|
@ -54,7 +54,7 @@ sealed class Settings(
|
|||
|
||||
sealed class AppSettings(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Settings(category = "Settings / App Settings", event = event, params = params) {
|
||||
|
||||
class SaveWalletSwitcherChanged(state: AnalyticsParam.OnOffState) : AppSettings(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent
|
|||
*/
|
||||
sealed class SignIn(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent("Sign In", event, params) {
|
||||
|
||||
class ScreenOpened : SignIn(event = "Sign In Screen Opened")
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
|||
sealed class Token(
|
||||
category: String,
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : AnalyticsEvent(category, event, params) {
|
||||
|
||||
sealed class Receive(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Token("Token / Receive", event, params) {
|
||||
|
||||
class ScreenOpened(
|
||||
|
|
@ -29,7 +29,7 @@ sealed class Token(
|
|||
|
||||
sealed class Topup(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Token("Token / Topup", event, params) {
|
||||
|
||||
class ScreenOpened : Topup("Top Up Screen Opened")
|
||||
|
|
@ -38,7 +38,7 @@ sealed class Token(
|
|||
|
||||
sealed class Withdraw(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
params: Map<String, String> = emptyMap(),
|
||||
) : Token("Token / Withdraw", event, params) {
|
||||
|
||||
class ScreenOpened : Withdraw("Withdraw Screen Opened")
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ internal class DefaultClipboardManager(private val clipboardManager: AndroidClip
|
|||
clipboardManager.setPrimaryClip(clip)
|
||||
}
|
||||
|
||||
@Suppress("UseIsNullOrEmpty")
|
||||
override fun getText(default: String?): String? {
|
||||
val clip = clipboardManager.primaryClip
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,6 @@ fun Store<AppState>.dispatchNavigationAction(action: AppRouter.() -> Unit) {
|
|||
|
||||
inline fun <reified T> Store<AppState>.inject(getDependency: DaggerGraphState.() -> T?): T {
|
||||
return requireNotNull(state.daggerGraphState.getDependency()) {
|
||||
"${T::class.simpleName} isn't initialized "
|
||||
"${T::class.simpleName.orEmpty()} isn't initialized "
|
||||
}
|
||||
}
|
||||
|
|
@ -22,9 +22,9 @@ import timber.log.Timber
|
|||
)
|
||||
@Suppress("MagicNumber")
|
||||
suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try {
|
||||
if (isDemoCard || TestActions.testAmountInjectionForWalletManagerEnabled) {
|
||||
if (isDemoCard || TestActions.isTestAmountInjectionForWalletManagerEnabled) {
|
||||
delay(500)
|
||||
TestActions.testAmountInjectionForWalletManagerEnabled = false
|
||||
TestActions.isTestAmountInjectionForWalletManagerEnabled = false
|
||||
Result.Success(wallet)
|
||||
} else {
|
||||
update()
|
||||
|
|
@ -35,7 +35,7 @@ suspend fun WalletManager.safeUpdate(isDemoCard: Boolean): Result<Wallet> = try
|
|||
|
||||
val networkConnectionManager = store.inject(DaggerGraphState::networkConnectionManager)
|
||||
if (!networkConnectionManager.isOnline) {
|
||||
Result.Failure(TapError.NoInternetConnection)
|
||||
Result.Failure(TapError.NoInternetConnection())
|
||||
} else {
|
||||
val blockchain = wallet.blockchain
|
||||
val amountToCreateAccount = blockchain.amountToCreateAccount(this, wallet.getFirstToken())
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class TangemAppLoggerInitializer(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("BooleanPropertyNaming")
|
||||
private companion object {
|
||||
val IS_LOG_ENABLED: Boolean = BuildConfig.LOG_ENABLED
|
||||
val PERMITTED_PRIORITY = listOf(Log.ERROR, Log.INFO)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@ data class GlobalState(
|
|||
typealias CryptoCurrencyName = String
|
||||
|
||||
data class OnboardingState(
|
||||
val onboardingStarted: Boolean = false,
|
||||
val isOnboardingStarted: Boolean = false,
|
||||
val shouldResetOnCreate: Boolean = false,
|
||||
)
|
||||
|
|
@ -61,9 +61,9 @@ internal class AndroidEmailSender : EmailSender {
|
|||
.setSubject(email.subject)
|
||||
.setText(email.message)
|
||||
|
||||
email.attachment?.let {
|
||||
email.attachment?.let { file ->
|
||||
builder.setStream(
|
||||
FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it),
|
||||
FileProvider.getUriForFile(activity, "${activity.packageName}.provider", file),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import javax.inject.Singleton
|
|||
import kotlin.text.encodeToByteArray
|
||||
|
||||
private const val DEFAULT_KEY = "tangem_pay_default_key"
|
||||
private const val DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY = "tangem_pay_default_customer_wallet_address_key"
|
||||
private const val ORDER_ID_KEY = "tangem_pay_order_id_key"
|
||||
|
||||
@Singleton
|
||||
internal class DefaultTangemPayStorage @Inject constructor(
|
||||
|
|
@ -54,24 +54,29 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
|||
?.let(tokensAdapter::fromJson)
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the only customer wallet address, since for the f&f user can issue only one card tied to one address
|
||||
*/
|
||||
override suspend fun storeCustomerWalletAddress(customerWalletAddress: String) =
|
||||
override suspend fun storeOrderId(customerWalletAddress: String, orderId: String) {
|
||||
withContext(dispatcherProvider.io) {
|
||||
secureStorage.store(
|
||||
customerWalletAddress.encodeToByteArray(throwOnInvalidSequence = true),
|
||||
DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY,
|
||||
orderId.encodeToByteArray(throwOnInvalidSequence = true),
|
||||
createOrderIdKey(customerWalletAddress),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getCustomerWalletAddress(): String? = withContext(dispatcherProvider.io) {
|
||||
secureStorage.get(DEFAULT_CUSTOMER_WALLET_ADDRESS_KEY)?.decodeToString(throwOnInvalidSequence = true)
|
||||
}
|
||||
|
||||
override suspend fun clear(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
override suspend fun getOrderId(customerWalletAddress: String): String? = withContext(dispatcherProvider.io) {
|
||||
secureStorage.get(createOrderIdKey(customerWalletAddress))?.decodeToString(throwOnInvalidSequence = true)
|
||||
}
|
||||
|
||||
override suspend fun clearOrderId(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||
}
|
||||
|
||||
override suspend fun clearAll(customerWalletAddress: String) = withContext(dispatcherProvider.io) {
|
||||
secureStorage.delete(createKey(customerWalletAddress))
|
||||
secureStorage.delete(createOrderIdKey(customerWalletAddress))
|
||||
}
|
||||
|
||||
private fun createKey(cardId: String): String = "${DEFAULT_KEY}_$cardId"
|
||||
private fun createKey(address: String): String = "${DEFAULT_KEY}_$address"
|
||||
|
||||
private fun createOrderIdKey(address: String): String = "${ORDER_ID_KEY}_$address"
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.tangem.tap.data
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.tap.di.data
|
||||
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.tap.data.RuntimeUserWalletsStore
|
||||
import com.tangem.tap.data.UserWalletsStoreRepositoryProxy
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.fetcher.SingleAccountListFetcher
|
||||
import com.tangem.domain.account.repository.AccountsCRUDRepository
|
||||
import com.tangem.domain.account.tokens.MainAccountTokensMigration
|
||||
import com.tangem.domain.account.usecase.*
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -15,8 +17,16 @@ internal object AccountDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAddCryptoPortfolioUseCase(accountsCRUDRepository: AccountsCRUDRepository): AddCryptoPortfolioUseCase {
|
||||
return AddCryptoPortfolioUseCase(crudRepository = accountsCRUDRepository)
|
||||
fun provideAddCryptoPortfolioUseCase(
|
||||
accountsCRUDRepository: AccountsCRUDRepository,
|
||||
singleAccountListFetcher: SingleAccountListFetcher,
|
||||
mainAccountTokensMigration: MainAccountTokensMigration,
|
||||
): AddCryptoPortfolioUseCase {
|
||||
return AddCryptoPortfolioUseCase(
|
||||
crudRepository = accountsCRUDRepository,
|
||||
singleAccountListFetcher = singleAccountListFetcher,
|
||||
mainAccountTokensMigration = mainAccountTokensMigration,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -39,8 +49,12 @@ internal object AccountDomainModule {
|
|||
@Singleton
|
||||
fun provideRecoverCryptoPortfolioUseCase(
|
||||
accountsCRUDRepository: AccountsCRUDRepository,
|
||||
mainAccountTokensMigration: MainAccountTokensMigration,
|
||||
): RecoverCryptoPortfolioUseCase {
|
||||
return RecoverCryptoPortfolioUseCase(crudRepository = accountsCRUDRepository)
|
||||
return RecoverCryptoPortfolioUseCase(
|
||||
crudRepository = accountsCRUDRepository,
|
||||
mainAccountTokensMigration = mainAccountTokensMigration,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.card.*
|
||||
import com.tangem.domain.card.DeleteSavedAccessCodesUseCase
|
||||
import com.tangem.domain.card.ResetCardUseCase
|
||||
import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetExtendedPublicKeyForCurrencyUseCase
|
||||
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
import com.tangem.tap.domain.card.DefaultDeleteSavedAccessCodesUseCase
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.domain.card.ScanCardProcessor
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.managetokens.*
|
||||
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
||||
import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
||||
|
|
@ -10,11 +9,14 @@ import com.tangem.domain.staking.StakingIdFactory
|
|||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
|
@ -74,6 +76,7 @@ internal object ManageTokensDomainModule {
|
|||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SaveManagedTokensUseCase {
|
||||
return SaveManagedTokensUseCase(
|
||||
customTokensRepository = customTokensRepository,
|
||||
|
|
@ -84,6 +87,7 @@ internal object ManageTokensDomainModule {
|
|||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.markets.*
|
||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||
|
|
@ -12,13 +12,16 @@ import com.tangem.domain.settings.repositories.SettingsRepository
|
|||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.core.wallets.UserWalletsListRepository
|
||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
|
|
@ -67,6 +70,7 @@ object MarketsDomainModule {
|
|||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): SaveMarketTokensUseCase {
|
||||
return SaveMarketTokensUseCase(
|
||||
derivationsRepository = derivationsRepository,
|
||||
|
|
@ -76,6 +80,17 @@ object MarketsDomainModule {
|
|||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetTokenMarketCryptoCurrency(
|
||||
marketsTokenRepository: MarketsTokenRepository,
|
||||
): GetTokenMarketCryptoCurrency {
|
||||
return GetTokenMarketCryptoCurrency(
|
||||
marketsTokenRepository = marketsTokenRepository,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,20 @@ internal object OnrampDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampV2QuotesUseCase(
|
||||
settingsRepository: SettingsRepository,
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampV2QuotesUseCase {
|
||||
return GetOnrampV2QuotesUseCase(
|
||||
settingsRepository = settingsRepository,
|
||||
repository = onrampRepository,
|
||||
errorResolver = onrampErrorResolver,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampProviderWithQuoteUseCase(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.staking.repositories.StakingErrorResolver
|
|||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -216,4 +217,10 @@ internal object StakingDomainModule {
|
|||
fun provideStakingIdFactory(walletManagersFacade: WalletManagersFacade): StakingIdFactory {
|
||||
return StakingIdFactory(walletManagersFacade = walletManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingApyFlowUseCase(stakingRepository: StakingRepository): StakingApyFlowUseCase {
|
||||
return StakingApyFlowUseCase(stakingRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||
|
|
@ -455,4 +456,21 @@ internal object TokensDomainModule {
|
|||
): SaveViewedTokenReceiveWarningUseCase {
|
||||
return SaveViewedTokenReceiveWarningUseCase(tokenReceiveWarningsViewedRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNeedShowYieldSupplyDepositedWarningUseCase(
|
||||
yieldSupplyWarningsViewedRepository: YieldSupplyWarningsViewedRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): NeedShowYieldSupplyDepositedWarningUseCase {
|
||||
return NeedShowYieldSupplyDepositedWarningUseCase(yieldSupplyWarningsViewedRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSaveViewedYieldSupplyWarningUseCase(
|
||||
yieldSupplyWarningsViewedRepository: YieldSupplyWarningsViewedRepository,
|
||||
): SaveViewedYieldSupplyWarningUseCase {
|
||||
return SaveViewedYieldSupplyWarningUseCase(yieldSupplyWarningsViewedRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
|
|||
import com.tangem.domain.demo.models.DemoConfig
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
|
||||
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
|
|
@ -231,6 +232,18 @@ internal object TransactionDomainModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideReceiveAddressesFactory(
|
||||
getEnsNameUseCase: GetEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase: GetViewedTokenReceiveWarningUseCase,
|
||||
): ReceiveAddressesFactory {
|
||||
return ReceiveAddressesFactory(
|
||||
getEnsNameUseCase = getEnsNameUseCase,
|
||||
getViewedTokenReceiveWarningUseCase = getViewedTokenReceiveWarningUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetReverseResolvedEnsAddressUseCase(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue