diff --git a/README.md b/README.md index 9ec770bf5..7afce517b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Kaspresso is a great framework for UI testing. Based on [Espresso](https://developer.android.com/training/testing/espresso) and [UI Automator](https://developer.android.com/training/testing/ui-automator), Kaspresso provides a wide range of additional amazing features, such as: * 100% stability, no flakiness. -* *[WIP] Jetpack Compose support.* +* Jetpack Compose support [since version 1.4]. * Significantly faster execution of UI Automator commands. With Kaspresso, some UI Automator commands run **10 times faster**! * Excellent readability due to human DSL. @@ -252,7 +252,7 @@ dependencies { androidTestImplementation 'com.kaspersky.android-components:kaspresso:' # Allure support androidTestImplementation "com.kaspersky.android-components:kaspresso-allure-support:" - # Jetpack Compose support + # Jetpack Compose support (since version 1.4) androidTestImplementation "com.kaspersky.android-components:kaspresso-compose-support:" } ``` diff --git a/build-logic/android/src/main/kotlin/convention.android-app.gradle.kts b/build-logic/android/src/main/kotlin/convention.android-app.gradle.kts index ae0619917..d3333ae38 100644 --- a/build-logic/android/src/main/kotlin/convention.android-app.gradle.kts +++ b/build-logic/android/src/main/kotlin/convention.android-app.gradle.kts @@ -9,6 +9,10 @@ plugins { android { testBuildType = "debug" + defaultConfig { + multiDexEnabled = true + } + variantFilter { if (name != testBuildType) { ignore = true diff --git a/build-logic/android/src/main/kotlin/convention.android-base.gradle.kts b/build-logic/android/src/main/kotlin/convention.android-base.gradle.kts index f338db436..7a7214195 100644 --- a/build-logic/android/src/main/kotlin/convention.android-base.gradle.kts +++ b/build-logic/android/src/main/kotlin/convention.android-base.gradle.kts @@ -12,7 +12,7 @@ configure { } defaultConfig { - minSdk = 21 + minSdk = 18 targetSdk = 30 } diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt b/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt index fc3ec2536..c535ff951 100644 --- a/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt +++ b/compose-support/src/main/java/com/kaspersky/components/composesupport/config/ComposeConfig.kt @@ -3,7 +3,6 @@ package com.kaspersky.components.composesupport.config import com.kaspersky.components.composesupport.interceptors.behavior.SemanticsBehaviorInterceptor import com.kaspersky.components.composesupport.interceptors.behavior.impl.autoscroll.AutoScrollSemanticsBehaviorInterceptor import com.kaspersky.components.composesupport.interceptors.behavior.impl.elementloader.ElementLoaderSemanticsBehaviorInterceptor -import com.kaspersky.components.composesupport.interceptors.behavior.impl.failure.FailureLoggingSemanticsBehaviorInterceptor import com.kaspersky.components.composesupport.interceptors.behavior.impl.flakysafety.FlakySafeSemanticsBehaviorInterceptor import com.kaspersky.components.composesupport.interceptors.behavior.impl.systemsafety.SystemDialogSafetySemanticsBehaviorInterceptor import com.kaspersky.components.composesupport.interceptors.watcher.SemanticsWatcherInterceptor @@ -42,15 +41,13 @@ class ComposeConfig { adbServer ), ElementLoaderSemanticsBehaviorInterceptor(libLogger, elementLoaderParams), - FlakySafeSemanticsBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingSemanticsBehaviorInterceptor(libLogger) + FlakySafeSemanticsBehaviorInterceptor(flakySafetyParams, libLogger) ) } else { mutableListOf( AutoScrollSemanticsBehaviorInterceptor(libLogger, autoScrollParams), ElementLoaderSemanticsBehaviorInterceptor(libLogger, elementLoaderParams), - FlakySafeSemanticsBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingSemanticsBehaviorInterceptor(libLogger) + FlakySafeSemanticsBehaviorInterceptor(flakySafetyParams, libLogger) ) } } diff --git a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt b/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt index 7ce1c44d3..0397f762f 100644 --- a/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt +++ b/compose-support/src/main/java/com/kaspersky/components/composesupport/interceptors/behavior/impl/failure/FailureLoggingSemanticsBehaviorInterceptor.kt @@ -12,8 +12,9 @@ import io.github.kakaocup.compose.intercept.operation.ComposeAssertion * The implementation of [SemanticsBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [ComposeInteraction.perform] and [ComposeInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingSemanticsBehaviorInterceptor( logger: UiTestLogger diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 375ef715a..d0f2d3330 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,7 @@ androidXCore = "androidx.core:core:1.7.0" appcompat = "androidx.appcompat:appcompat:1.4.0" material = "com.google.android.material:material:1.4.0" constraint = "androidx.constraintlayout:constraintlayout:2.1.2" +multidex = "androidx.multidex:multidex:2.0.1" lifecycleViewModelKtx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" } lifecycleLiveDataKtx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" } diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingDataBehaviorInterceptor.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingDataBehaviorInterceptor.kt index e04816c9c..b3c1db6e4 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingDataBehaviorInterceptor.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingDataBehaviorInterceptor.kt @@ -10,8 +10,9 @@ import com.kaspersky.kaspresso.logger.UiTestLogger * The implementation of [DataBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [DataInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingDataBehaviorInterceptor( logger: UiTestLogger diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingViewBehaviorInterceptor.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingViewBehaviorInterceptor.kt index 2a3070c6f..d80ac5b32 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingViewBehaviorInterceptor.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingViewBehaviorInterceptor.kt @@ -10,8 +10,9 @@ import com.kaspersky.kaspresso.logger.UiTestLogger * The implementation of [ViewBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [ViewInteraction.perform] and [ViewInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingViewBehaviorInterceptor( logger: UiTestLogger diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingWebBehaviorInterceptor.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingWebBehaviorInterceptor.kt index 6c6263933..a3c865de7 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingWebBehaviorInterceptor.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behavior/impl/failure/FailureLoggingWebBehaviorInterceptor.kt @@ -10,8 +10,9 @@ import com.kaspersky.kaspresso.logger.UiTestLogger * The implementation of [WebBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [Web.WebInteraction.perform] and [Web.WebInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingWebBehaviorInterceptor( logger: UiTestLogger diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingDeviceBehaviorInterceptor.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingDeviceBehaviorInterceptor.kt index 69694a166..ea74d76a1 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingDeviceBehaviorInterceptor.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingDeviceBehaviorInterceptor.kt @@ -12,8 +12,9 @@ import com.kaspersky.kaspresso.logger.UiTestLogger * The implementation of [DeviceBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [UiDeviceInteraction.perform] and [UiDeviceInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingDeviceBehaviorInterceptor( logger: UiTestLogger diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingObjectBehaviorInterceptor.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingObjectBehaviorInterceptor.kt index f160cc171..4c2ca5489 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingObjectBehaviorInterceptor.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/interceptors/behaviorkautomator/impl/failure/FailureLoggingObjectBehaviorInterceptor.kt @@ -12,8 +12,9 @@ import com.kaspersky.kaspresso.logger.UiTestLogger * The implementation of [ObjectBehaviorInterceptor] and [FailureLoggingProvider] interfaces. * Provides failure logging functionality for [UiObjectInteraction.perform] and [UiObjectInteraction.check] calls. * - * By default, this interceptor is not used in Kaspresso. - * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly + * Important! + * By default, the interceptor is not used in Kaspresso because this one pollutes logs by error messages that may confuse a user. + * If you desire to change result log (especially in case of an error) we recommend to use [FailureLoggingProvider] directly. */ class FailureLoggingObjectBehaviorInterceptor( logger: UiTestLogger diff --git a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/kaspresso/Kaspresso.kt b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/kaspresso/Kaspresso.kt index 420323249..3e48532fb 100644 --- a/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/kaspresso/Kaspresso.kt +++ b/kaspresso/src/main/kotlin/com/kaspersky/kaspresso/kaspresso/Kaspresso.kt @@ -71,9 +71,6 @@ import com.kaspersky.kaspresso.interceptors.behavior.ViewBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.WebBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.impl.autoscroll.AutoScrollViewBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.impl.autoscroll.AutoScrollWebBehaviorInterceptor -import com.kaspersky.kaspresso.interceptors.behavior.impl.failure.FailureLoggingDataBehaviorInterceptor -import com.kaspersky.kaspresso.interceptors.behavior.impl.failure.FailureLoggingViewBehaviorInterceptor -import com.kaspersky.kaspresso.interceptors.behavior.impl.failure.FailureLoggingWebBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeDataBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeViewBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behavior.impl.flakysafety.FlakySafeWebBehaviorInterceptor @@ -84,8 +81,6 @@ import com.kaspersky.kaspresso.interceptors.behaviorkautomator.DeviceBehaviorInt import com.kaspersky.kaspresso.interceptors.behaviorkautomator.ObjectBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.autoscroll.AutoScrollObjectBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.elementloader.ElementLoaderObjectBehaviorInterceptor -import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.failure.FailureLoggingDeviceBehaviorInterceptor -import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.failure.FailureLoggingObjectBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.flakysafety.FlakySafeDeviceBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.flakysafety.FlakySafeObjectBehaviorInterceptor import com.kaspersky.kaspresso.interceptors.behaviorkautomator.impl.systemsafety.SystemDialogSafetyDeviceBehaviorInterceptor @@ -832,12 +827,10 @@ data class Kaspresso( instrumentalDependencyProviderFactory.getInterceptorProvider(instrumentation), adbServer ), - FlakySafeViewBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingViewBehaviorInterceptor(libLogger) + FlakySafeViewBehaviorInterceptor(flakySafetyParams, libLogger) ) else mutableListOf( AutoScrollViewBehaviorInterceptor(autoScrollParams, libLogger), - FlakySafeViewBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingViewBehaviorInterceptor(libLogger) + FlakySafeViewBehaviorInterceptor(flakySafetyParams, libLogger) ) if (!::dataBehaviorInterceptors.isInitialized) dataBehaviorInterceptors = @@ -847,11 +840,9 @@ data class Kaspresso( instrumentalDependencyProviderFactory.getInterceptorProvider(instrumentation), adbServer ), - FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingDataBehaviorInterceptor(libLogger) + FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger) ) else mutableListOf( - FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingDataBehaviorInterceptor(libLogger) + FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger) ) if (!::webBehaviorInterceptors.isInitialized) webBehaviorInterceptors = @@ -863,14 +854,12 @@ data class Kaspresso( instrumentalDependencyProviderFactory.getInterceptorProvider(instrumentation), adbServer ), - FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingWebBehaviorInterceptor(libLogger) + FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger) ) } else { mutableListOf( AutoScrollWebBehaviorInterceptor(autoScrollParams, libLogger), - FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingWebBehaviorInterceptor(libLogger) + FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger) ) } @@ -882,8 +871,7 @@ data class Kaspresso( adbServer ), ElementLoaderObjectBehaviorInterceptor(libLogger, elementLoaderParams), - FlakySafeObjectBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingObjectBehaviorInterceptor(libLogger) + FlakySafeObjectBehaviorInterceptor(flakySafetyParams, libLogger) ) if (!::deviceBehaviorInterceptors.isInitialized) deviceBehaviorInterceptors = mutableListOf( @@ -892,8 +880,7 @@ data class Kaspresso( instrumentalDependencyProviderFactory.getInterceptorProvider(instrumentation), adbServer ), - FlakySafeDeviceBehaviorInterceptor(flakySafetyParams, libLogger), - FailureLoggingDeviceBehaviorInterceptor(libLogger) + FlakySafeDeviceBehaviorInterceptor(flakySafetyParams, libLogger) ) if (!::stepWatcherInterceptors.isInitialized) stepWatcherInterceptors = mutableListOf( diff --git a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/component/common/assertions/UiBaseAssertions.kt b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/component/common/assertions/UiBaseAssertions.kt index a8e76a0e4..9d34cf361 100644 --- a/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/component/common/assertions/UiBaseAssertions.kt +++ b/kautomator/src/main/kotlin/com/kaspersky/components/kautomator/component/common/assertions/UiBaseAssertions.kt @@ -3,7 +3,6 @@ package com.kaspersky.components.kautomator.component.common.assertions import com.google.common.truth.Truth.assertThat import com.kaspersky.components.kautomator.intercept.delegate.UiObjectInteractionDelegate -import com.kaspersky.components.kautomator.intercept.exception.UnfoundedUiObjectException import com.kaspersky.components.kautomator.intercept.operation.UiOperationType /** @@ -27,18 +26,11 @@ interface UiBaseAssertions { * Checks if the view is not completely displayed */ fun isNotDisplayed() { - // the implementation is a little bit tricky because - // UiObjectInteractionDelegate throws UnfoundedUiObjectException in case of absence of a related UIObject2 - // that's why we just catch the mentioned exception and do a final check - val notDisplayed = try { - isDisplayed() - false - } catch (exception: UnfoundedUiObjectException) { - true - } catch (exception: Throwable) { - false - } - assertThat(notDisplayed).isTrue() + // the implementation is a little bit tricky skipping 'view.check' way + // the reason: nullable uiObject2 triggers the work of all behavior Interceptors + // which can lead to unexpected behavior + // that's why we check uiObject2 directly + assertThat(view.interaction.uiObject2).isNull() } /** diff --git a/samples/adbserver-sample/build.gradle.kts b/samples/adbserver-sample/build.gradle.kts index 3e4fc46d7..35a32975b 100644 --- a/samples/adbserver-sample/build.gradle.kts +++ b/samples/adbserver-sample/build.gradle.kts @@ -12,4 +12,5 @@ dependencies { implementation(libs.kotlinStdlib) implementation(libs.appcompat) implementation(projects.adbServer.adbserverDevice) + implementation(libs.multidex) } diff --git a/samples/adbserver-sample/src/main/AndroidManifest.xml b/samples/adbserver-sample/src/main/AndroidManifest.xml index e76419ae3..81bd5b777 100644 --- a/samples/adbserver-sample/src/main/AndroidManifest.xml +++ b/samples/adbserver-sample/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ - \ No newline at end of file + diff --git a/samples/kaspresso-allure-support-sample/build.gradle.kts b/samples/kaspresso-allure-support-sample/build.gradle.kts index 5f96ec8c8..d19c46191 100644 --- a/samples/kaspresso-allure-support-sample/build.gradle.kts +++ b/samples/kaspresso-allure-support-sample/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { implementation(libs.appcompat) implementation(libs.material) implementation(libs.constraint) + implementation(libs.multidex) androidTestImplementation(projects.kaspresso) androidTestImplementation(projects.allureSupport) diff --git a/samples/kaspresso-allure-support-sample/src/main/AndroidManifest.xml b/samples/kaspresso-allure-support-sample/src/main/AndroidManifest.xml index 21f11d60b..71d91183d 100644 --- a/samples/kaspresso-allure-support-sample/src/main/AndroidManifest.xml +++ b/samples/kaspresso-allure-support-sample/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ tools:ignore="ScopedStorage" /> diff --git a/samples/kaspresso-compose-support-sample/build.gradle.kts b/samples/kaspresso-compose-support-sample/build.gradle.kts index dace89f93..40d63f011 100644 --- a/samples/kaspresso-compose-support-sample/build.gradle.kts +++ b/samples/kaspresso-compose-support-sample/build.gradle.kts @@ -4,6 +4,8 @@ plugins { android { defaultConfig { + minSdk = 21 + applicationId = "com.kaspersky.kaspresso.composesupport.com.kaspersky.kaspresso.composesupport.sample" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["clearPackageData"] = "true" diff --git a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyScreen.kt b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyScreen.kt index 1508384a5..f7e1e4097 100644 --- a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyScreen.kt +++ b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyScreen.kt @@ -1,6 +1,11 @@ package com.kaspersky.kaspresso.composesupport.sample.features.flaky -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.Button diff --git a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyViewModel.kt b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyViewModel.kt index 41fbe121d..406a17c4f 100644 --- a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyViewModel.kt +++ b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/flaky/SimpleFlakyViewModel.kt @@ -4,7 +4,10 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.plus private const val TIMEOUT = 1_000L diff --git a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/main/MainScreen.kt b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/main/MainScreen.kt index 01b295894..8f43e95f4 100644 --- a/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/main/MainScreen.kt +++ b/samples/kaspresso-compose-support-sample/src/main/kotlin/com/kaspersky/kaspresso/composesupport/sample/features/main/MainScreen.kt @@ -1,6 +1,11 @@ package com.kaspersky.kaspresso.composesupport.sample.features.main -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text diff --git a/samples/kaspresso-sample/build.gradle.kts b/samples/kaspresso-sample/build.gradle.kts index 202675df6..4753800af 100644 --- a/samples/kaspresso-sample/build.gradle.kts +++ b/samples/kaspresso-sample/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { implementation(libs.appcompat) implementation(libs.material) implementation(libs.constraint) + implementation(libs.multidex) androidTestImplementation(libs.junit) androidTestImplementation(projects.kaspresso) diff --git a/samples/kaspresso-sample/src/main/AndroidManifest.xml b/samples/kaspresso-sample/src/main/AndroidManifest.xml index 918f2414f..55d1440bc 100644 --- a/samples/kaspresso-sample/src/main/AndroidManifest.xml +++ b/samples/kaspresso-sample/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ - \ No newline at end of file + diff --git a/samples/kautomator-sample/build.gradle.kts b/samples/kautomator-sample/build.gradle.kts index 3dbbf36e4..6cd11668e 100644 --- a/samples/kautomator-sample/build.gradle.kts +++ b/samples/kautomator-sample/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { implementation(libs.appcompat) implementation(libs.material) implementation(libs.constraint) + implementation(libs.multidex) androidTestImplementation(projects.kaspresso) } diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ComponentsScreen.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ComponentsScreen.kt index 0e1cecd55..bb63055f7 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ComponentsScreen.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ComponentsScreen.kt @@ -7,7 +7,7 @@ import com.kaspersky.components.kautomator.component.dialog.UiAlertDialog import com.kaspersky.components.kautomator.component.text.UiButton import com.kaspersky.components.kautomator.screen.UiScreen -object ComponentsScreen : UiScreen() { +class ComponentsScreen : UiScreen() { override val packageName: String = "com.kaspersky.kaspresso.kautomatorsample" diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/MainScreen.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/MainScreen.kt index cd1b58f29..38cd4ecc6 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/MainScreen.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/MainScreen.kt @@ -5,7 +5,7 @@ import com.kaspersky.components.kautomator.component.edit.UiEditText import com.kaspersky.components.kautomator.component.text.UiButton import com.kaspersky.components.kautomator.screen.UiScreen -object MainScreen : UiScreen() { +class MainScreen : UiScreen() { override val packageName: String = "com.kaspersky.kaspresso.kautomatorsample" diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/RecyclerScreen.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/RecyclerScreen.kt index 10fd1cb13..1b8995ef7 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/RecyclerScreen.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/RecyclerScreen.kt @@ -4,7 +4,7 @@ import com.kaspersky.components.kautomator.component.scroll.UiScrollView import com.kaspersky.components.kautomator.component.text.UiTextView import com.kaspersky.components.kautomator.screen.UiScreen -object RecyclerScreen : UiScreen() { +class RecyclerScreen : UiScreen() { override val packageName: String = "com.kaspersky.kaspresso.kautomatorsample" diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ScrollScreen.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ScrollScreen.kt index d7d5a3cd3..21e0bc776 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ScrollScreen.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/screen/ScrollScreen.kt @@ -4,16 +4,16 @@ import com.kaspersky.components.kautomator.component.scroll.UiScrollView import com.kaspersky.components.kautomator.component.text.UiTextView import com.kaspersky.components.kautomator.screen.UiScreen -object ScrollScreen : UiScreen() { +private const val TOP_TEXT = "Beginning" +private const val CENTER_TEXT = "Center" +private const val BOTTOM_TEXT = "End" - private const val TOP_TEXT = "Beginning" - private const val CENTER_TEXT = "Center" - private const val BOTTOM_TEXT = "End" +class ScrollScreen : UiScreen() { override val packageName: String = "com.kaspersky.kaspresso.kautomatorsample" val scroll = UiScrollView { withId(this@ScrollScreen.packageName, "scroll") } - val top = UiTextView { withText(this@ScrollScreen.TOP_TEXT) } - val center = UiTextView { withText(this@ScrollScreen.CENTER_TEXT) } - val bottom = UiTextView { withText(this@ScrollScreen.BOTTOM_TEXT) } + val top = UiTextView { withText(TOP_TEXT) } + val center = UiTextView { withText(CENTER_TEXT) } + val bottom = UiTextView { withText(BOTTOM_TEXT) } } diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/InterceptorTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/InterceptorTest.kt index 16231140e..d0996058d 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/InterceptorTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/InterceptorTest.kt @@ -6,7 +6,6 @@ import androidx.test.rule.GrantPermissionRule import com.kaspersky.components.kautomator.KautomatorConfigurator import com.kaspersky.components.kautomator.component.text.UiButton import com.kaspersky.components.kautomator.screen.UiScreen -import com.kaspersky.kaspresso.kaspresso.Kaspresso import com.kaspersky.kaspresso.kautomatorsample.MainActivity import com.kaspersky.kaspresso.kautomatorsample.screen.MainScreen import com.kaspersky.kaspresso.testcases.api.testcase.TestCase @@ -17,13 +16,7 @@ import org.junit.Test /** * The test demonstrating and checking work of interceptors concept in Kautomator */ -class InterceptorTest : TestCase( - kaspressoBuilder = Kaspresso.Builder.simple { - afterEachTest { - InterceptedMainScreen.resetScreenList() - } - } -) { +class InterceptorTest : TestCase() { @get:Rule val runtimePermissionRule: GrantPermissionRule = GrantPermissionRule.grant( @@ -34,6 +27,9 @@ class InterceptorTest : TestCase( @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) + private val interceptorMainScreen = InterceptedMainScreen() + private val mainScreen = MainScreen() + @Test fun testKautomatorInterceptors() { val list = mutableListOf() @@ -52,7 +48,7 @@ class InterceptorTest : TestCase( }.after { }.run { step("Simple action on default Screen") { - MainScreen { + mainScreen { simpleButton { isDisplayed() click() @@ -73,7 +69,7 @@ class InterceptorTest : TestCase( }.after { }.run { step("Simple action on Intercepted Screen") { - InterceptedMainScreen { + interceptorMainScreen { simpleButton { isDisplayed() click() @@ -82,7 +78,7 @@ class InterceptorTest : TestCase( } step("Check Intercepting correctness") { - InterceptedMainScreen { + interceptorMainScreen { assertEquals(mutableListOf("ALL", "CHECK", "ALL", "PERFORM"), screenList) } } @@ -98,7 +94,7 @@ class InterceptorTest : TestCase( }.after { }.run { step("Simple action on default Screen with intercepted View") { - MainScreen { + mainScreen { simpleButton { intercept { onAll { list.add("ALL") } @@ -136,7 +132,7 @@ class InterceptorTest : TestCase( }.after { }.run { step("Simple action on intercepted Screen with intercepted View") { - InterceptedMainScreen { + interceptorMainScreen { simpleButton { intercept { onAll { list.add("ALL_VIEW") } @@ -151,7 +147,7 @@ class InterceptorTest : TestCase( } step("Check Intercepting correctness") { - InterceptedMainScreen { + interceptorMainScreen { assert(screenList == mutableListOf("ALL", "CHECK", "ALL", "PERFORM")) } assertEquals( @@ -182,7 +178,7 @@ class InterceptorTest : TestCase( }.after { }.run { step("Simple action on intercepted Screen with intercepted View") { - InterceptedMainScreen { + interceptorMainScreen { simpleButton { intercept { onAll { list.add("ALL_VIEW") } @@ -205,7 +201,7 @@ class InterceptorTest : TestCase( } step("Check Intercepting correctness") { - InterceptedMainScreen { + interceptorMainScreen { assert(screenList.isEmpty()) } assertEquals(mutableListOf("ALL_VIEW", "CHECK_VIEW", "ALL_VIEW", "PERFORM_VIEW"), list) @@ -213,7 +209,7 @@ class InterceptorTest : TestCase( } } - object InterceptedMainScreen : UiScreen() { + class InterceptedMainScreen : UiScreen() { override val packageName: String = "com.kaspersky.kaspresso.kautomatorsample" @@ -229,9 +225,5 @@ class InterceptorTest : TestCase( } } } - - fun resetScreenList() { - screenList.clear() - } } } diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/UiSimpleTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/UiSimpleTest.kt index 46e6c8eed..99d685310 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/UiSimpleTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/UiSimpleTest.kt @@ -26,6 +26,8 @@ class UiSimpleTest : TestCase() { @get:Rule val activityTestRule = ActivityTestRule(MainActivity::class.java, true, false) + private val mainScreen = MainScreen() + @Test fun upgradeTest() { before { @@ -48,7 +50,7 @@ class UiSimpleTest : TestCase() { }.run { step("Input text in EditText and check it") { - MainScreen { + mainScreen { simpleEditText { replaceText("Kaspresso") hasText("Kaspresso") @@ -56,14 +58,14 @@ class UiSimpleTest : TestCase() { } } step("Click button") { - MainScreen { + mainScreen { simpleButton { click() } } } step("Click checkbox and check it") { - MainScreen { + mainScreen { checkBox { setChecked(true) isChecked() diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/AlertDialogTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/AlertDialogTest.kt index 7d33c258b..70bff1f4c 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/AlertDialogTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/AlertDialogTest.kt @@ -12,11 +12,13 @@ class AlertDialogTest : TestCase() { @get:Rule val activityRule = ActivityTestRule(ComponentsActivity::class.java, true, true) + private val componentsScreen = ComponentsScreen() + @Test fun test() { run { step("Open dialog") { - ComponentsScreen { + componentsScreen { showDialogBtn { click() } @@ -24,7 +26,7 @@ class AlertDialogTest : TestCase() { } step("Check title and message") { - ComponentsScreen { + componentsScreen { dialog { title { hasText("Title") @@ -42,7 +44,7 @@ class AlertDialogTest : TestCase() { } step("Negative button click") { - ComponentsScreen { + componentsScreen { showDialogBtn { click() } @@ -56,7 +58,7 @@ class AlertDialogTest : TestCase() { } step("Neutral button click") { - ComponentsScreen { + componentsScreen { showDialogBtn { click() } diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/BottomNavigationViewTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/BottomNavigationViewTest.kt index d76417ae3..7b0cbce7c 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/BottomNavigationViewTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/BottomNavigationViewTest.kt @@ -20,12 +20,14 @@ class BottomNavigationViewTest : TestCase() { @get:Rule val rule = ActivityTestRule(ComponentsActivity::class.java, true, true) + private val componentsScreen = ComponentsScreen() + @Test fun test() { run { step("Select item by id") { - ComponentsScreen { + componentsScreen { bottomNav { setSelectedItemWithId(ITEM_1_ID) hasSelectedItemWithId(ITEM_1_ID) @@ -35,7 +37,7 @@ class BottomNavigationViewTest : TestCase() { } step("Select item by index") { - ComponentsScreen { + componentsScreen { bottomNav { setSelectedItemWithIndex(0) hasSelectedItemWithIndex(0) @@ -45,7 +47,7 @@ class BottomNavigationViewTest : TestCase() { } step("Select item by label") { - ComponentsScreen { + componentsScreen { bottomNav { setSelectedItemWithTitle(ITEM_1_TEXT) hasSelectedItemWithTitle(ITEM_1_TEXT) diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/CheckboxTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/CheckboxTest.kt index 6e6fea2df..c8fa98a5e 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/CheckboxTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/CheckboxTest.kt @@ -1,6 +1,7 @@ package com.kaspersky.kaspresso.kautomatorsample.test.components import androidx.test.rule.ActivityTestRule +import com.kaspersky.components.kautomator.screen.UiScreen.Companion.onUiScreen import com.kaspersky.kaspresso.kautomatorsample.ComponentsActivity import com.kaspersky.kaspresso.kautomatorsample.screen.ComponentsScreen import com.kaspersky.kaspresso.testcases.api.testcase.TestCase @@ -16,7 +17,7 @@ class CheckboxTest : TestCase() { fun test() { run { step("Set checked") { - ComponentsScreen { + onUiScreen { checkbox { setChecked(true) isChecked() @@ -25,7 +26,7 @@ class CheckboxTest : TestCase() { } step("Set not checked") { - ComponentsScreen { + onUiScreen { checkbox { setChecked(false) isNotChecked() diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ChipGroupTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ChipGroupTest.kt index b664e5b50..1066fb18f 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ChipGroupTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ChipGroupTest.kt @@ -1,6 +1,7 @@ package com.kaspersky.kaspresso.kautomatorsample.test.components import androidx.test.rule.ActivityTestRule +import com.kaspersky.components.kautomator.screen.UiScreen.Companion.onUiScreen import com.kaspersky.kaspresso.kautomatorsample.ComponentsActivity import com.kaspersky.kaspresso.kautomatorsample.screen.ComponentsScreen import com.kaspersky.kaspresso.testcases.api.testcase.TestCase @@ -22,7 +23,7 @@ class ChipGroupTest : TestCase() { fun test() { run { step("Select chip with id") { - ComponentsScreen { + onUiScreen { chipGroup { isNotChipWithIdSelected(CHIP_ID) selectChipWithId(CHIP_ID) @@ -32,7 +33,7 @@ class ChipGroupTest : TestCase() { } step("Select chip with text") { - ComponentsScreen { + onUiScreen { chipGroup { isNotChipWithTextSelected(CHIP_TEXT) selectChipWithText(CHIP_TEXT) @@ -42,7 +43,7 @@ class ChipGroupTest : TestCase() { } step("Select chip with index") { - ComponentsScreen { + onUiScreen { chipGroup { isNotChipWithIndexSelected(CHIP_INDEX) selectChipWithIndex(CHIP_INDEX) diff --git a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ScrollViewTest.kt b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ScrollViewTest.kt index 70aec4f2c..1b11dbe87 100644 --- a/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ScrollViewTest.kt +++ b/samples/kautomator-sample/src/androidTest/java/com/kaspersky/kaspresso/kautomatorsample/test/components/ScrollViewTest.kt @@ -15,6 +15,8 @@ class ScrollViewTest : TestCase() { @get:Rule val rule = ActivityTestRule(ScrollActivity::class.java, true, true) + private val scrollScreen = ScrollScreen() + @Test fun test() { run { @@ -22,7 +24,7 @@ class ScrollViewTest : TestCase() { * An example of the use swipe gestures */ step("Swipe actions") { - ScrollScreen { + scrollScreen { /** * Swipes up for about one screen */ @@ -43,7 +45,7 @@ class ScrollViewTest : TestCase() { } step("Scroll actions") { - ScrollScreen { + scrollScreen { /** * Scrolls the view to the bottom */ @@ -55,7 +57,7 @@ class ScrollViewTest : TestCase() { /** * Scrolls the view to selected UiBaseView */ - scroll { scrollToView(this@ScrollScreen.center) } + scroll { scrollToView(scrollScreen.center) } /** * toSearch view should be displayed */ diff --git a/samples/kautomator-sample/src/main/AndroidManifest.xml b/samples/kautomator-sample/src/main/AndroidManifest.xml index 0a671ccc5..3cd3daded 100644 --- a/samples/kautomator-sample/src/main/AndroidManifest.xml +++ b/samples/kautomator-sample/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ - \ No newline at end of file + diff --git a/static-analysis/config/detekt/config.yml b/static-analysis/config/detekt/config.yml index f1d0a8d2a..98649faba 100644 --- a/static-analysis/config/detekt/config.yml +++ b/static-analysis/config/detekt/config.yml @@ -281,7 +281,7 @@ formatting: active: true autoCorrect: true NoWildcardImports: - active: false + active: true PackageName: active: false autoCorrect: true @@ -514,7 +514,7 @@ style: maxJumpCount: 1 MagicNumber: active: true - excludes: ['**/test/**', '**/androidTest/**', '**/sharedTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] + excludes: ['**/test/**', '**/androidTest/**', '**/sharedTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt', '**/*.kts'] ignoreNumbers: ['-1', '0', '1', '2'] ignoreHashCodeFunction: true ignorePropertyDeclaration: false @@ -619,4 +619,4 @@ style: VarCouldBeVal: active: false WildcardImport: - active: false + active: true diff --git a/tutorial/build.gradle.kts b/tutorial/build.gradle.kts index 322ddb038..474193de6 100644 --- a/tutorial/build.gradle.kts +++ b/tutorial/build.gradle.kts @@ -4,6 +4,9 @@ plugins { android { defaultConfig { + // remove after upgrading to 1.4 + minSdk = 21 + applicationId = "com.kaspersky.kaspresso.tutorial" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments["clearPackageData"] = "true" diff --git a/wiki/10_Jetpack-Compose.md b/wiki/10_Jetpack-Compose.md index 588195df6..38d7e92c4 100644 --- a/wiki/10_Jetpack-Compose.md +++ b/wiki/10_Jetpack-Compose.md @@ -115,6 +115,40 @@ I/KASPRESSO: ___________________________________________________________________ I/KASPRESSO: TEST STEP: "3. Click on the Second button" in ComposeSimpleFlakyTest ``` +## Caveats +Remember, that Jetpack Compose and all relative tools are developing. +It means Jetpack Compose is not learned very well and some things can be unexpected after "Old fashioned View World" experience. +Let me show the interesting case. + +For example, this code +```kotlin +composeSimpleFlakyScreen(composeTestRule) { + firstButton { + performClick() + } +} +``` +can be the source of flakiness behavior if `firstButton` is located in non visible for a user area +(you just need to scroll to see the element). + +But, this code will always work stably: +```kotlin +composeSimpleFlakyScreen(composeTestRule) { + firstButton { + assertIsDisplayed() + performClick() + } +} +``` + +The explanation is in the nature of SemanticsNode Tree and Jetpack Compose. `firstButton` is a Node and presented in the Tree. +It means that `performClick()` may work and nothing bad doesn't happen. But, `firstButton` is not visible physically and a real click doesn't occur. +Such behavior causes the crash of a test a little bit later.
+But, `assertIsDisplayed()` check doesn't pass on the first try (we don't see the element on the screen) and +launches work of all Interceptors including Autoscroll interceptor which scrolls the Screen to the desired element. + +Please, [share your experience](https://github.com/KasperskyLab/Kaspresso/issues/new) to help other developers. + ## What else ### Configuration @@ -175,6 +209,8 @@ All information about Robolectric support is available [here](./08_Kaspresso-Rob ### Compose is compatible with all sweet Kaspresso extensions Sweet Kaspresso extensions means using of the such constructions as -- `flakySafely`, -- `continuously`, -- etc. +- `flakySafely` +- `continuously` + +The support of some constructions is in progress: [issue-317](https://github.com/KasperskyLab/Kaspresso/issues/317). +