Skip to content

Commit

Permalink
Merge pull request KasperskyLab#327 from KasperskyLab/small_improvements
Browse files Browse the repository at this point in the history
Small improvements
  • Loading branch information
matzuk authored Nov 26, 2021
2 parents 121ec33 + dab4b2d commit f2ddd6a
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 48 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -252,7 +252,7 @@ dependencies {
androidTestImplementation 'com.kaspersky.android-components:kaspresso:<latest_version>'
# Allure support
androidTestImplementation "com.kaspersky.android-components:kaspresso-allure-support:<latest_version>"
# Jetpack Compose support
# Jetpack Compose support (since version 1.4)
androidTestImplementation "com.kaspersky.android-components:kaspresso-compose-support:<latest_version>"
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -832,12 +827,10 @@ data class Kaspresso(
instrumentalDependencyProviderFactory.getInterceptorProvider<SystemDialogSafetyViewBehaviorInterceptor>(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 =
Expand All @@ -847,11 +840,9 @@ data class Kaspresso(
instrumentalDependencyProviderFactory.getInterceptorProvider<SystemDialogSafetyViewBehaviorInterceptor>(instrumentation),
adbServer
),
FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingDataBehaviorInterceptor(libLogger)
FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger)
) else mutableListOf(
FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingDataBehaviorInterceptor(libLogger)
FlakySafeDataBehaviorInterceptor(flakySafetyParams, libLogger)
)

if (!::webBehaviorInterceptors.isInitialized) webBehaviorInterceptors =
Expand All @@ -863,14 +854,12 @@ data class Kaspresso(
instrumentalDependencyProviderFactory.getInterceptorProvider<SystemDialogSafetyViewBehaviorInterceptor>(instrumentation),
adbServer
),
FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingWebBehaviorInterceptor(libLogger)
FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger)
)
} else {
mutableListOf(
AutoScrollWebBehaviorInterceptor(autoScrollParams, libLogger),
FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingWebBehaviorInterceptor(libLogger)
FlakySafeWebBehaviorInterceptor(flakySafetyParams, libLogger)
)
}

Expand All @@ -882,8 +871,7 @@ data class Kaspresso(
adbServer
),
ElementLoaderObjectBehaviorInterceptor(libLogger, elementLoaderParams),
FlakySafeObjectBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingObjectBehaviorInterceptor(libLogger)
FlakySafeObjectBehaviorInterceptor(flakySafetyParams, libLogger)
)

if (!::deviceBehaviorInterceptors.isInitialized) deviceBehaviorInterceptors = mutableListOf(
Expand All @@ -892,8 +880,7 @@ data class Kaspresso(
instrumentalDependencyProviderFactory.getInterceptorProvider<SystemDialogSafetyViewBehaviorInterceptor>(instrumentation),
adbServer
),
FlakySafeDeviceBehaviorInterceptor(flakySafetyParams, libLogger),
FailureLoggingDeviceBehaviorInterceptor(libLogger)
FlakySafeDeviceBehaviorInterceptor(flakySafetyParams, libLogger)
)

if (!::stepWatcherInterceptors.isInitialized) stepWatcherInterceptors = mutableListOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions static-analysis/config/detekt/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ formatting:
active: true
autoCorrect: true
NoWildcardImports:
active: false
active: true
PackageName:
active: false
autoCorrect: true
Expand Down Expand Up @@ -619,4 +619,4 @@ style:
VarCouldBeVal:
active: false
WildcardImport:
active: false
active: true
42 changes: 39 additions & 3 deletions wiki/10_Jetpack-Compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.<br>
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
Expand Down Expand Up @@ -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).

0 comments on commit f2ddd6a

Please sign in to comment.