Skip to content

Commit

Permalink
Merge pull request #286 from matzuk/issue/242-3
Browse files Browse the repository at this point in the history
Issue/242-3
  • Loading branch information
matzuk authored Oct 12, 2021
2 parents 4b09959 + 808dd2d commit 76940bd
Show file tree
Hide file tree
Showing 53 changed files with 1,153 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,37 @@ import com.kaspersky.components.alluresupport.interceptors.testrun.ScreenshotTes
import com.kaspersky.components.alluresupport.interceptors.testrun.VideoRecordingTestInterceptor
import com.kaspersky.kaspresso.kaspresso.Kaspresso

/**
* Kaspresso Builder that includes all appropriate interceptors to support rich Allure reports.
*
* If a test is executing on the JVM (with Robolectric) environment then mentioned above interceptors are not including to prevent crashes.
* Allure reports don't have any sense in non Instrumental environment.
*/
fun Kaspresso.Builder.Companion.withAllureSupport(
customize: Kaspresso.Builder.() -> Unit = {}
): Kaspresso.Builder = simple(customize).addAllureSupport()

/**
* Kaspresso Builder that includes all appropriate interceptors to support rich Allure reports.
*
* If a test is executing on the JVM (with Robolectric) environment then mentioned above interceptors are not including to prevent crashes.
* Allure reports don't have any sense in non Instrumental environment.
*/
fun Kaspresso.Builder.addAllureSupport(): Kaspresso.Builder = apply {
stepWatcherInterceptors.addAll(
listOf(
ScreenshotStepInterceptor(screenshots),
AllureMapperStepInterceptor()
if (isAndroidRuntime) {
stepWatcherInterceptors.addAll(
listOf(
ScreenshotStepInterceptor(screenshots),
AllureMapperStepInterceptor()
)
)
)
testRunWatcherInterceptors.addAll(
listOf(
DumpLogcatTestInterceptor(logcatDumper),
ScreenshotTestInterceptor(screenshots),
VideoRecordingTestInterceptor(videos),
DumpViewsTestInterceptor(viewHierarchyDumper)
testRunWatcherInterceptors.addAll(
listOf(
DumpLogcatTestInterceptor(logcatDumper),
ScreenshotTestInterceptor(screenshots),
VideoRecordingTestInterceptor(videos),
DumpViewsTestInterceptor(viewHierarchyDumper)
)
)
)
}
}
8 changes: 6 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ espressoCore = { module = "androidx.test.espresso:espresso-core", version.ref =
espressoWeb = { module = "androidx.test.espresso:espresso-web", version.ref = "espresso" }
testCore = "androidx.test:core:1.3.0"
uiAutomator = "androidx.test.uiautomator:uiautomator:2.2.0"
fragmentTesting = "androidx.fragment:fragment-testing:1.3.2"
robolectric = "org.robolectric:robolectric:4.5.1"

androidXCore = "androidx.core:core:1.3.1"
androidXCore = "androidx.core:core:1.3.0"
androidXRules = "androidx.test:rules:1.3.0"
androidXTest = "androidx.test.ext:junit:1.1.2"
androidXTestKtx = "androidx.test.ext:junit-ktx:1.1.2"

appcompat = "androidx.appcompat:appcompat:1.2.0"
appcompat = "androidx.appcompat:appcompat:1.3.0"
material = "com.google.android.material:material:1.2.0"
constraint = "androidx.constraintlayout:constraintlayout:2.0.0"

Expand Down
7 changes: 0 additions & 7 deletions kaspresso/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ dependencies {
api(libs.androidXCore)
api(libs.androidXRules)

api(projects.kautomator)
api(libs.kakao)
api(libs.bundles.espresso)
api(libs.uiAutomator)
api(libs.androidXCore)
api(libs.androidXRules)

implementation(libs.kotlinStdlib)
implementation(libs.gson)
implementation(projects.adbServer.adbserverDevice)
Expand Down
22 changes: 13 additions & 9 deletions kaspresso/src/main/kotlin/com/kaspersky/kaspresso/device/Device.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.kaspersky.kaspresso.device

import android.app.Instrumentation
import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.kaspersky.kaspresso.device.accessibility.Accessibility
import com.kaspersky.kaspresso.device.activities.Activities
Expand All @@ -17,6 +17,7 @@ import com.kaspersky.kaspresso.device.permissions.HackPermissions
import com.kaspersky.kaspresso.device.permissions.Permissions
import com.kaspersky.kaspresso.device.phone.Phone
import com.kaspersky.kaspresso.device.screenshots.Screenshots
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider

/**
* The provider of managers for all off-screen work.
Expand Down Expand Up @@ -119,22 +120,25 @@ data class Device(
/**
* Holds the reference to the implementation of [Logcat] interface.
*/
val logcat: Logcat
val logcat: Logcat,

private val instrumentalDependencyProvider: InstrumentalDependencyProvider,

private val instrumentation: Instrumentation
) {
/**
* A not caching property to get [Context].
* A caching property to get [Context].
*/
val context: Context
get() = InstrumentationRegistry.getInstrumentation().context
val context: Context = instrumentation.context

/**
* A not caching property to get target [Context].
* A caching property to get target [Context].
*/
val targetContext: Context
get() = InstrumentationRegistry.getInstrumentation().targetContext
val targetContext: Context = instrumentation.targetContext

/**
* A property to get the instance of [UiDevice].
*/
val uiDevice: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val uiDevice: UiDevice
get() = instrumentalDependencyProvider.uiDevice
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package com.kaspersky.kaspresso.device.accessibility
import android.annotation.TargetApi
import android.app.UiAutomation
import android.os.Build
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.Configurator
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.logger.UiTestLogger

/**
* The implementation of the [Accessibility] interface.
*/
class AccessibilityImpl(
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
private val logger: UiTestLogger
) : Accessibility {

Expand All @@ -28,7 +29,7 @@ class AccessibilityImpl(
val flags = UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES
Configurator.getInstance().uiAutomationFlags = flags

InstrumentationRegistry.getInstrumentation()
instrumentalDependencyProvider
.getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES)
.executeShellCommand(cmd)
.close()
Expand All @@ -44,7 +45,7 @@ class AccessibilityImpl(
val string = "enabled_accessibility_services"
val cmd = "settings put secure $string null"

InstrumentationRegistry.getInstrumentation()
instrumentalDependencyProvider
.getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES)
.executeShellCommand(cmd)
.close()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.kaspersky.kaspresso.device.activities

import android.app.Activity
import android.app.Instrumentation
import android.os.Looper
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
import androidx.test.runner.lifecycle.Stage
import com.kaspersky.kaspresso.logger.UiTestLogger
Expand All @@ -14,7 +14,8 @@ import org.junit.Assert
* The implementation of the [Activities] interface.
*/
class ActivitiesImpl(
private val logger: UiTestLogger
private val logger: UiTestLogger,
private val instrumentation: Instrumentation,
) : Activities {

/**
Expand Down Expand Up @@ -43,7 +44,7 @@ class ActivitiesImpl(
if (isMainThread) {
findResumedActivity()
} else {
InstrumentationRegistry.getInstrumentation().runOnMainSync(findResumedActivity)
instrumentation.runOnMainSync(findResumedActivity)
}

resumedActivity ?: logger.e("No resumed activity found")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
import com.kaspersky.kaspresso.device.server.AdbServer
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.logger.UiTestLogger
import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert
Expand All @@ -20,7 +21,7 @@ import org.junit.Assert
class AppsImpl(
private val logger: UiTestLogger,
private val context: Context,
private val uiDevice: UiDevice,
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
private val adbServer: AdbServer
) : Apps {

Expand All @@ -29,9 +30,12 @@ class AppsImpl(
const val LAUNCH_APP_TIMEOUT = 5_000L
}

private val uiDevice: UiDevice
get() = instrumentalDependencyProvider.uiDevice
private val chromePackageName: String = "com.android.chrome"

override val targetAppLauncherPackageName: String = uiDevice.launcherPackageName
override val targetAppLauncherPackageName: String
get() = uiDevice.launcherPackageName

override val targetAppPackageName: String = context.packageName

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.test.espresso.Espresso
import androidx.test.uiautomator.UiDevice
import com.kaspersky.kaspresso.device.activities.Activities
import com.kaspersky.kaspresso.device.server.AdbServer
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.logger.UiTestLogger

/**
Expand All @@ -14,10 +15,13 @@ import com.kaspersky.kaspresso.logger.UiTestLogger
class ExploitImpl(
private val logger: UiTestLogger,
private val activities: Activities,
private val uiDevice: UiDevice,
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
private val adbServer: AdbServer
) : Exploit {

private val uiDevice: UiDevice
get() = instrumentalDependencyProvider.uiDevice

/**
* Toggles the orientation of the device.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ package com.kaspersky.kaspresso.device.permissions
import android.app.UiAutomation
import android.os.Process
import android.os.UserHandle
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.logger.UiTestLogger

/**
* The implementation of the [HackPermissions] interface.
*/
class HackPermissionsImpl(
private val uiAutomation: UiAutomation,
private val logger: UiTestLogger
private val logger: UiTestLogger,
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
) : HackPermissions {

private val uiAutomation: UiAutomation
get() = instrumentalDependencyProvider.uiAutomation

/**
* @return result of operation: true is success, false is something went wrong
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject
import androidx.test.uiautomator.UiObjectNotFoundException
import androidx.test.uiautomator.UiSelector
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.internal.wait.wait
import com.kaspersky.kaspresso.logger.UiTestLogger

Expand All @@ -14,13 +15,15 @@ import com.kaspersky.kaspresso.logger.UiTestLogger
*/
class PermissionsImpl(
private val logger: UiTestLogger,
private val uiDevice: UiDevice
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
) : Permissions {

private companion object {
private const val DIALOG_TIMEOUT_MS: Long = 3_000
}

private val uiDevice: UiDevice
get() = instrumentalDependencyProvider.uiDevice
private val packageInstallerPackageName =
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P)
"com.android.permissioncontroller"
Expand Down Expand Up @@ -93,7 +96,7 @@ class PermissionsImpl(
/**
* Passes the permission-requesting permissions dialog.
*
* @param buttonResId resource name of permission dialog button
* @param button resource name of permission dialog button
*/
private fun handlePermissionRequest(button: Permissions.Button) {
val uiObjectButton = getPermissionDialogButtonAsUiObject(button)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package com.kaspersky.kaspresso.device.screenshots.screenshotmaker

import androidx.test.uiautomator.UiDevice
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.params.ScreenshotParams
import java.io.File

/**
* Captures spoon-compatible screenshots by uiautomator.
*/
class ExternalScreenshotMaker(
private val device: UiDevice,
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
private val params: ScreenshotParams = ScreenshotParams()
) : ScreenshotMaker {

private val device: UiDevice
get() = instrumentalDependencyProvider.uiDevice

// Somehow scale param is not used in UiDevice#takeScreenshot method,
// so just using default here
private val scale: Float = 1.0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,24 @@ class AdbServerImpl(
}
if (result.status == ExecutorResultStatus.TIMEOUT) {
throw AdbServerException(
"AdbServer. The command=$command was performed with timeout exception. \n" +
"The possible reason (99.9%) is absence of started 'adbserver-desktop.jar'. \n" +
"Please, follow the instruction: \n" +
"1. Find the last 'adbserver-desktop.jar' here - https://github.com/KasperskyLab/Kaspresso/tree/master/artifacts \n" +
"2. Copy 'adbserver-desktop.jar' to your machine. For example, /Users/yuri.gagarin/Desktop/adbserver-desktop.jar. \n" +
"3. Start 'adbserver-desktop.jar' with the command in Terminal - 'java -jar /Users/yuri.gagarin/Desktop/adbserver-desktop.jar"
"""
AdbServer. The command=$command was performed with timeout exception.
There are two possible reasons:
1. The test is executing on the JVM (with Robolectric) environment and the test uses AdbServer. But, Unit tests can't use this implementation of AdbServer.
Possible solutions:
a. Rewrite the test and replace/remove a peace of code where AdbServer is called.
b. Write another implementation of AdbServer.
c. Don't use this test like a JVM(Unit)-test.
2. The second reason is absence of started 'adbserver-desktop.jar'.
Please, follow the instruction to resolve this issue:
a. Find the last 'adbserver-desktop.jar' here - https://github.com/KasperskyLab/Kaspresso/tree/master/artifacts.
b. Copy 'adbserver-desktop.jar' to your machine. For example, /Users/yuri.gagarin/Desktop/adbserver-desktop.jar.
c. Start 'adbserver-desktop.jar' with the command in Terminal - 'java -jar /Users/yuri.gagarin/Desktop/adbserver-desktop.jar
""".trimIndent()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package com.kaspersky.kaspresso.device.video.recorder

import android.util.Log
import androidx.test.uiautomator.UiDevice
import com.kaspersky.kaspresso.instrumental.InstrumentalDependencyProvider
import com.kaspersky.kaspresso.internal.wait.wait
import com.kaspersky.kaspresso.logger.UiTestLogger
import com.kaspersky.kaspresso.params.VideoParams
import java.io.File

class VideoRecorderImpl(
private val device: UiDevice,
private val instrumentalDependencyProvider: InstrumentalDependencyProvider,
private val logger: UiTestLogger,
private val params: VideoParams
) : VideoRecorder {

private val device: UiDevice
get() = instrumentalDependencyProvider.uiDevice
private var videoRecordingThread: VideoRecordingThread? = null

/**
Expand Down
Loading

0 comments on commit 76940bd

Please sign in to comment.