diff --git a/src/main/java/ru/samsung/test/core/core/BaseTest.kt b/src/main/java/ru/samsung/test/core/core/BaseTest.kt old mode 100644 new mode 100755 index 5860a48..de0df93 --- a/src/main/java/ru/samsung/test/core/core/BaseTest.kt +++ b/src/main/java/ru/samsung/test/core/core/BaseTest.kt @@ -1,100 +1,85 @@ package ru.samsung.test.core.core import android.app.Activity -import android.app.Instrumentation -import android.content.Context -import android.content.Intent -import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.core.app.ActivityScenario -import androidx.test.espresso.Espresso -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.uiautomator.UiDevice import com.kaspersky.components.composesupport.config.addComposeSupport import com.kaspersky.kaspresso.idlewaiting.KautomatorWaitForIdleSettings import com.kaspersky.kaspresso.kaspresso.Kaspresso import com.kaspersky.kaspresso.testcases.api.testcase.TestCase -import com.kaspersky.kaspresso.testcases.core.sections.AfterTestSection import com.kaspersky.kaspresso.testcases.core.testcontext.BaseTestContext import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext import java.util.Locale -import org.junit.After -import org.junit.Before import org.junit.FixMethodOrder -import org.junit.Rule import org.junit.runners.MethodSorters -import ru.samsung.test.core.utils.EmptyRule import ru.samsung.test.core.utils.ResultTestsData +/** + * Базовый класс тестов, который подключается для запуска основных + * + * @param clazz класс активити, который будет запущен при старте. + * Эта активити должна иметь соответствующий флаг в манифесте и + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) open class BaseTest( - private val clazz: Class, - private val isEnabledCompose: Boolean = false -) : TestCase(kaspressoBuilder = Kaspresso.Builder.simple { - kautomatorWaitForIdleSettings = KautomatorWaitForIdleSettings.boost() -}.apply { - testRunWatcherInterceptors.add(ResultTestRunWatcherInterceptor()) - if (isEnabledCompose) addComposeSupport() -}) { - @get:Rule - val composeTestRule = if (isEnabledCompose) createComposeRule() else EmptyRule() - - protected lateinit var activityScenario: ActivityScenario - private set - protected lateinit var uiDevice: UiDevice - private set - protected lateinit var appContext: Context - private set - protected lateinit var instrumentation: Instrumentation - private set - - open fun beforeTest() {} - - @Before - fun setUp() { - instrumentation = InstrumentationRegistry.getInstrumentation() - val handler = DescriptionFailureHandler(instrumentation) - Espresso.setFailureHandler(handler) - - uiDevice = UiDevice.getInstance(instrumentation) - uiDevice.pressHome() - Thread.sleep(1_000) - - val nonLocalizedContext = instrumentation.targetContext - val configuration = nonLocalizedContext.resources.configuration - configuration.setLocale(Locale.UK) - appContext = nonLocalizedContext.createConfigurationContext(configuration) - - val intent = Intent(appContext, clazz) - - activityScenario = ActivityScenario.launch(intent) - - beforeTest() - } - - @After - fun reset() { - uiDevice.pressHome() - } + clazz: Class, + isEnabledCompose: Boolean = false, + private val skipAfterFirstFail: Boolean = true, +) : TestCase( + kaspressoBuilder = getBuilder( + clazz = clazz, + isEnabledCompose = isEnabledCompose, + ) +) { fun runWithInit(grade: Int, test: TestContext.() -> Unit) = run { + val hasFailed = ResultTestsData.hasFailed() ResultTestsData.setupTest(grade) + if (hasFailed && skipAfterFirstFail) throw Throwable("SKIPPED. Prev test failed") try { test.invoke(this) ResultTestsData.successTest(grade) - } catch (e: Exception) { - ResultTestsData.putResult(instrumentation, uiDevice) - throw AssertionError(e.message) + } catch (e: Throwable) { + DescriptionFailureHandler.throwError(e) } - ResultTestsData.putResult(instrumentation, uiDevice) } - fun runWithGrade(grade: Int, testName: String, steps: TestContext.() -> Unit) { - ResultTestsData.testGrade[testName] = grade - run(testName, steps) - } + private companion object { + fun getBuilder( + clazz: Class, + isEnabledCompose: Boolean, + ): Kaspresso.Builder { + val builder = Kaspresso.Builder.simple { + kautomatorWaitForIdleSettings = KautomatorWaitForIdleSettings.boost() + beforeEachTest(override = true) { beforeEachAction(this, clazz) } + afterEachTest(override = true) { afterEachAction(this) } + } + builder.setupHandler() + if (isEnabledCompose) builder.addComposeSupport() + return builder + } - fun beforeWithGrade(grade: Int, testName: String, actions: BaseTestContext.() -> Unit): AfterTestSection { - ResultTestsData.testGrade[testName] = grade - return before(testName, actions) + fun Kaspresso.Builder.beforeEachAction( + context: BaseTestContext, + clazz: Class, + ) { + with(context.device) { + language.switchInApp(Locale.UK) + uiDevice.pressHome() + } + Thread.sleep(1_000) + ActivityScenario.launch(clazz) + } + + fun Kaspresso.Builder.afterEachAction( + context: BaseTestContext, + ) { + ResultTestsData.putResult(instrumentation) + context.device.uiDevice.pressHome() + } + + fun Kaspresso.Builder.setupHandler() { + stepWatcherInterceptors.add(DescriptionFailureHandler) + testRunWatcherInterceptors.add(DescriptionFailureHandler) + } } } diff --git a/src/main/java/ru/samsung/test/core/core/DescriptionFailureHandler.kt b/src/main/java/ru/samsung/test/core/core/DescriptionFailureHandler.kt old mode 100644 new mode 100755 index d75f89b..3194a41 --- a/src/main/java/ru/samsung/test/core/core/DescriptionFailureHandler.kt +++ b/src/main/java/ru/samsung/test/core/core/DescriptionFailureHandler.kt @@ -1,31 +1,42 @@ package ru.samsung.test.core.core -import android.app.Instrumentation -import android.view.View -import androidx.test.espresso.FailureHandler -import androidx.test.espresso.base.DefaultFailureHandler -import org.hamcrest.Matcher -import kotlin.math.min +import com.kaspersky.kaspresso.interceptors.watcher.testcase.StepWatcherInterceptor +import com.kaspersky.kaspresso.interceptors.watcher.testcase.TestRunWatcherInterceptor +import com.kaspersky.kaspresso.testcases.models.info.StepInfo +import com.kaspersky.kaspresso.testcases.models.info.TestInfo -class DescriptionFailureHandler(instrumentation: Instrumentation) : FailureHandler { - var extraMessage = "" - private var delegate: DefaultFailureHandler = - DefaultFailureHandler(instrumentation.targetContext) +object DescriptionFailureHandler : StepWatcherInterceptor, TestRunWatcherInterceptor { + private val outputLogs = mutableListOf() - override fun handle(error: Throwable?, viewMatcher: Matcher?) { - // Log anything you want here - if (error != null) { - val newError = Throwable( - - "$extraMessage " + error.message?.substring( - 0, min( - 1_700, error.message?.length ?: 0 - ) - ) + "...", error.cause - ) - - // Then delegate the error handling to the default handler which will throw an exception - delegate.handle(newError, viewMatcher) - } + override fun onTestStarted(testInfo: TestInfo) { + outputLogs.clear() } + + override fun interceptAfterWithSuccess(stepInfo: StepInfo) { + super.interceptAfterWithSuccess(stepInfo) + outputLogs.add(stepInfo.description + ": OK") + } + + override fun interceptAfterWithError(stepInfo: StepInfo, error: Throwable) { + super.interceptAfterWithError(stepInfo, error) + outputLogs.add(stepInfo.description + ": FAIL") + } + + fun throwError(error: Throwable): Nothing { + var message = buildString { + outputLogs.forEach { str -> + append(str) + append("\n") + } + } + if (message.length >= MAX_MESSAGE_LENGTH - MIN_ERROR_LENGTH) { + message = message.takeLast(MAX_MESSAGE_LENGTH - MIN_ERROR_LENGTH) + } + message += error.message?.take(MAX_MESSAGE_LENGTH - message.length) ?: "" + + throw Throwable(message, error) + } + + private const val MAX_MESSAGE_LENGTH = 1_700 + private const val MIN_ERROR_LENGTH = 100 } diff --git a/src/main/java/ru/samsung/test/core/core/MainTestSectionExt.kt b/src/main/java/ru/samsung/test/core/core/MainTestSectionExt.kt deleted file mode 100644 index 20d6f91..0000000 --- a/src/main/java/ru/samsung/test/core/core/MainTestSectionExt.kt +++ /dev/null @@ -1,9 +0,0 @@ -package ru.samsung.test.core.core - -import com.kaspersky.kaspresso.testcases.core.sections.MainTestSection -import com.kaspersky.kaspresso.testcases.core.testcontext.TestContext - -fun MainTestSection.runWithInit(grade: Int, steps: TestContext.() -> Unit, testName: String) { - - this.run(steps) -} \ No newline at end of file diff --git a/src/main/java/ru/samsung/test/core/core/ResultTestRunWatcherInterceptor.kt b/src/main/java/ru/samsung/test/core/core/ResultTestRunWatcherInterceptor.kt deleted file mode 100644 index 88d3538..0000000 --- a/src/main/java/ru/samsung/test/core/core/ResultTestRunWatcherInterceptor.kt +++ /dev/null @@ -1,27 +0,0 @@ -package ru.samsung.test.core.core - -import android.app.Instrumentation -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.uiautomator.UiDevice -import com.kaspersky.kaspresso.interceptors.watcher.testcase.TestRunWatcherInterceptor -import com.kaspersky.kaspresso.testcases.models.info.TestInfo -import ru.samsung.test.core.utils.ResultTestsData - -class ResultTestRunWatcherInterceptor: TestRunWatcherInterceptor { - override fun onTestStarted(testInfo: TestInfo) { - val grade: Int = ResultTestsData.testGrade[testInfo.testName] ?: 0 - ResultTestsData.setupTest(grade) - super.onTestStarted(testInfo) - } - - override fun onMainSectionFinishedSuccess(testInfo: TestInfo) { - val grade: Int = ResultTestsData.testGrade[testInfo.testName] ?: 0 - ResultTestsData.successTest(grade) - super.onMainSectionFinishedSuccess(testInfo) - } - - override fun onTestFinished(testInfo: TestInfo, success: Boolean) { - ResultTestsData.putResult(InstrumentationRegistry.getInstrumentation(), UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())) - super.onTestFinished(testInfo, success) - } -} \ No newline at end of file diff --git a/src/main/java/ru/samsung/test/core/utils/EmptyRule.kt b/src/main/java/ru/samsung/test/core/utils/EmptyRule.kt old mode 100644 new mode 100755 diff --git a/src/main/java/ru/samsung/test/core/utils/ResultTestsData.kt b/src/main/java/ru/samsung/test/core/utils/ResultTestsData.kt old mode 100644 new mode 100755 index e87c482..ecf709f --- a/src/main/java/ru/samsung/test/core/utils/ResultTestsData.kt +++ b/src/main/java/ru/samsung/test/core/utils/ResultTestsData.kt @@ -12,7 +12,6 @@ object ResultTestsData { private var totalTests = 0 private var maxGrade = 0 private var passTests = 0 - val testGrade: MutableMap = mutableMapOf() fun setupTest(grade: Int) { totalTests++ @@ -24,13 +23,12 @@ object ResultTestsData { ResultTestsData.grade += grade } + fun hasFailed() = totalTests != passTests + fun putResult( - instrumentation: Instrumentation, - uiDevice: UiDevice + instrumentation: Instrumentation ) { - uiDevice.pressHome() - val results = Bundle() results.putInt("passTests", passTests) results.putInt("totalTests", totalTests) diff --git a/src/main/java/ru/samsung/test/core/utils/UiTextViewExtensions.kt b/src/main/java/ru/samsung/test/core/utils/UiTextViewExtensions.kt old mode 100644 new mode 100755 diff --git a/src/main/java/ru/samsung/test/core/utils/UiViewBuilderExtensions.kt b/src/main/java/ru/samsung/test/core/utils/UiViewBuilderExtensions.kt old mode 100644 new mode 100755 diff --git a/src/main/java/ru/samsung/test/core/utils/Utils.kt b/src/main/java/ru/samsung/test/core/utils/Utils.kt old mode 100644 new mode 100755