158 lines
No EOL
6.1 KiB
Kotlin
158 lines
No EOL
6.1 KiB
Kotlin
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.printToLog
|
||
import androidx.test.core.app.ActivityScenario
|
||
import androidx.test.espresso.intent.Intents
|
||
import androidx.test.platform.app.InstrumentationRegistry
|
||
import androidx.test.rule.GrantPermissionRule
|
||
import com.kaspersky.components.alluresupport.interceptors.step.ScreenshotStepInterceptor
|
||
import com.kaspersky.components.alluresupport.withForcedAllureSupport
|
||
import com.kaspersky.components.composesupport.config.addComposeSupport
|
||
import com.kaspersky.kaspresso.kaspresso.Kaspresso
|
||
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
|
||
import com.tangem.common.allure.FailedStepScreenshotInterceptor
|
||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_NAME
|
||
import com.tangem.common.constants.TestConstants.ALLURE_LABEL_VALUE
|
||
import com.tangem.common.rules.ApiEnvironmentRule
|
||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||
import com.tangem.datasource.utils.WireMockRedirectInterceptor
|
||
import com.tangem.domain.promo.PromoRepository
|
||
import com.tangem.domain.promo.models.PromoId
|
||
import com.tangem.tap.MainActivity
|
||
import dagger.hilt.android.testing.HiltAndroidRule
|
||
import io.qameta.allure.kotlin.Allure
|
||
import kotlinx.coroutines.runBlocking
|
||
import org.junit.Rule
|
||
import org.junit.rules.RuleChain
|
||
import org.junit.rules.TestRule
|
||
import javax.inject.Inject
|
||
|
||
abstract class BaseTestCase : TestCase(
|
||
kaspressoBuilder = Kaspresso.Builder.withForcedAllureSupport(
|
||
shouldRecordVideo = false
|
||
).apply {
|
||
stepWatcherInterceptors = stepWatcherInterceptors.filter {
|
||
it !is ScreenshotStepInterceptor
|
||
}.toMutableList()
|
||
stepWatcherInterceptors.addAll(
|
||
listOf(
|
||
FailedStepScreenshotInterceptor(screenshots)
|
||
)
|
||
)
|
||
}.addComposeSupport()
|
||
) {
|
||
|
||
@Inject
|
||
lateinit var apiConfigsManager: ApiConfigsManager
|
||
|
||
@Inject
|
||
lateinit var appPreferencesStore: AppPreferencesStore
|
||
|
||
@Inject
|
||
lateinit var promoRepository: PromoRepository
|
||
|
||
private val hiltRule = HiltAndroidRule(this)
|
||
private val apiEnvironmentRule = ApiEnvironmentRule()
|
||
private val permissionRule = GrantPermissionRule.grant(
|
||
Manifest.permission.POST_NOTIFICATIONS,
|
||
)
|
||
|
||
/**
|
||
* It is important to use `ComposeRule` without specifying an activity to ensure that the initialization order of
|
||
* all test rules is fully controlled.
|
||
*/
|
||
val composeTestRule = createEmptyComposeRule()
|
||
|
||
@Rule
|
||
@JvmField
|
||
val ruleChain: TestRule = RuleChain
|
||
.outerRule(hiltRule)
|
||
.around(applicationInjectionRule())
|
||
.around(permissionRule)
|
||
.around(apiEnvironmentRule)
|
||
.around(composeTestRule)
|
||
|
||
/**
|
||
* Initialization order is important:
|
||
* – DI dependencies must be injected first,
|
||
* – then the API environment should be set up,
|
||
* – and only after that the activity should be launched.
|
||
*/
|
||
protected fun setupHooks(
|
||
additionalBeforeSection: () -> Unit = {},
|
||
additionalAfterSection: () -> Unit = {},
|
||
) = before {
|
||
Allure.label(ALLURE_LABEL_NAME, ALLURE_LABEL_VALUE)
|
||
// Setup WireMock redirect for CI with local WireMock instances
|
||
val wiremockUrl = InstrumentationRegistry.getArguments().getString(WIREMOCK_BASE_URL_ARG)
|
||
WireMockRedirectInterceptor.overriddenBaseUrl = wiremockUrl
|
||
hiltRule.inject()
|
||
runBlocking {
|
||
appPreferencesStore.editData { mutablePreferences ->
|
||
mutablePreferences.set(
|
||
key = PreferencesKeys.NOTIFICATIONS_USER_ALLOW_SEND_ADDRESSES_KEY,
|
||
value = false
|
||
)
|
||
}
|
||
appPreferencesStore.editData { mutablePreferences ->
|
||
mutablePreferences.set(
|
||
key = PreferencesKeys.getShouldShowNotificationKey("EnablePushesReminderNotification"),
|
||
value = false
|
||
)
|
||
}
|
||
promoRepository.setNeverToShowWalletPromo(PromoId.Sepa)
|
||
}
|
||
apiEnvironmentRule.setup(apiConfigsManager)
|
||
ActivityScenario.launch(MainActivity::class.java)
|
||
Intents.init()
|
||
additionalBeforeSection()
|
||
}.after {
|
||
additionalAfterSection()
|
||
Intents.release()
|
||
}
|
||
|
||
/**
|
||
* 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).
|
||
* @param tag Log tag for filtering in logcat. Default: "SEMANTIC_TREE".
|
||
* @param maxDepth Maximum nesting level to print. Use to avoid log overflow.
|
||
* Default: Int.MAX_VALUE (unlimited depth).
|
||
*/
|
||
fun printSemanticTree(
|
||
rootIndex: Int = 0,
|
||
useUnmergedTree: Boolean = false,
|
||
tag: String = "SEMANTIC_TREE",
|
||
maxDepth: Int = Int.MAX_VALUE
|
||
) {
|
||
composeTestRule.onAllNodes(isRoot(), useUnmergedTree = useUnmergedTree)[rootIndex]
|
||
.printToLog(tag, maxDepth)
|
||
}
|
||
|
||
fun waitForIdle() = composeTestRule.waitForIdle()
|
||
|
||
private fun applicationInjectionRule(): ApplicationInjectionExecutionRule {
|
||
return ApplicationInjectionExecutionRule(
|
||
toggleStates = mapOf(
|
||
"SWAP_REDESIGN_ENABLED" to false,
|
||
"NEW_ONRAMP_MAIN_ENABLED" to true,
|
||
"HOT_WALLET_ENABLED" to true,
|
||
"YIELD_SUPPLY_FEATURE_ENABLED" to true,
|
||
"ACCOUNTS_FEATURE_ENABLED" to true
|
||
)
|
||
)
|
||
}
|
||
|
||
private companion object {
|
||
const val WIREMOCK_BASE_URL_ARG = "wiremockBaseUrl"
|
||
}
|
||
} |