Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add installApp command #1854

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions maestro-client/src/main/java/maestro/Driver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,6 @@ interface Driver {
fun isAirplaneModeEnabled(): Boolean

fun setAirplaneMode(enabled: Boolean)

fun installApk(apk: File)
}
5 changes: 5 additions & 0 deletions maestro-client/src/main/java/maestro/Maestro.kt
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,11 @@ class Maestro(private val driver: Driver) : AutoCloseable {
driver.setAirplaneMode(enabled)
}

fun installApk(apkPath: String?) {
val apkFile = File(apkPath.orEmpty())
driver.installApk(apkFile)
}

companion object {

private val LOGGER = LoggerFactory.getLogger(Maestro::class.java)
Expand Down
5 changes: 5 additions & 0 deletions maestro-client/src/main/java/maestro/drivers/AndroidDriver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,11 @@ class AndroidDriver(
shell("cmd connectivity airplane-mode $value")
}

override fun installApk(apk: File) {
install(apk)
}


private fun broadcastAirplaneMode(enabled: Boolean) {
val command = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state $enabled"
try {
Expand Down
4 changes: 4 additions & 0 deletions maestro-client/src/main/java/maestro/drivers/IOSDriver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ class IOSDriver(
LOGGER.warn("Airplane mode is not available on iOS simulators")
}

override fun installApk(apk: File) {
LOGGER.warn("Install app is not available on iOS simulators")
}

boranfrkn marked this conversation as resolved.
Show resolved Hide resolved
private fun addMediaToDevice(mediaFile: File) {
val namedSource = NamedSource(
mediaFile.name,
Expand Down
4 changes: 4 additions & 0 deletions maestro-client/src/main/java/maestro/drivers/WebDriver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@ class WebDriver(val isStudio: Boolean) : Driver {
TODO("Not yet implemented")
}

override fun installApk(apk: File) {
TODO("Not yet implemented")
}

companion object {
private const val SCREENSHOT_DIFF_THRESHOLD = 0.005
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,20 @@ data class ToggleAirplaneModeCommand(
}
}

data class InstallApplicationCommand(
bartekpacia marked this conversation as resolved.
Show resolved Hide resolved
val apkPath: String? = null,
val label: String? = null,
): Command {
override fun description(): String {
return label ?: "Installing $apkPath"
}

override fun evaluateScripts(jsEngine: JsEngine): Command {
return this
}

}

internal fun tapOnDescription(isLongPress: Boolean?, repeat: TapRepeat?): String {
return if (isLongPress == true) "Long press"
else if (repeat != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ data class MaestroCommand(
val addMediaCommand: AddMediaCommand? = null,
val setAirplaneModeCommand: SetAirplaneModeCommand? = null,
val toggleAirplaneModeCommand: ToggleAirplaneModeCommand? = null,
val installApplicationCommand: InstallApplicationCommand? = null,
) {

constructor(command: Command) : this(
Expand Down Expand Up @@ -105,6 +106,7 @@ data class MaestroCommand(
addMediaCommand = command as? AddMediaCommand,
setAirplaneModeCommand = command as? SetAirplaneModeCommand,
toggleAirplaneModeCommand = command as? ToggleAirplaneModeCommand,
installApplicationCommand = command as? InstallApplicationCommand,
)

fun asCommand(): Command? = when {
Expand Down Expand Up @@ -145,6 +147,7 @@ data class MaestroCommand(
addMediaCommand != null -> addMediaCommand
setAirplaneModeCommand != null -> setAirplaneModeCommand
toggleAirplaneModeCommand != null -> toggleAirplaneModeCommand
installApplicationCommand != null -> installApplicationCommand
else -> null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ class Orchestra(
is AddMediaCommand -> addMediaCommand(command.mediaPaths)
is SetAirplaneModeCommand -> setAirplaneMode(command)
is ToggleAirplaneModeCommand -> toggleAirplaneMode()
is InstallApplicationCommand -> installApk(command)
else -> true
}.also { mutating ->
if (mutating) {
Expand All @@ -289,6 +290,12 @@ class Orchestra(
}
}

private fun installApk(command: InstallApplicationCommand): Boolean {
maestro.installApk(command.apkPath)

return true
}

private fun setAirplaneMode(command: SetAirplaneModeCommand): Boolean {
when (command.value) {
AirplaneValue.Enable -> maestro.setAirplaneModeState(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ data class YamlFluentCommand(
val addMedia: YamlAddMedia? = null,
val setAirplaneMode: YamlSetAirplaneMode? = null,
val toggleAirplaneMode: YamlToggleAirplaneMode? = null,
val installApp: YamlInstallApp? = null,
) {

@SuppressWarnings("ComplexMethod")
Expand Down Expand Up @@ -224,6 +225,14 @@ data class YamlFluentCommand(
}
setAirplaneMode != null -> listOf(MaestroCommand(SetAirplaneModeCommand(setAirplaneMode.value, setAirplaneMode.label)))
toggleAirplaneMode != null -> listOf(MaestroCommand(ToggleAirplaneModeCommand(toggleAirplaneMode.label)))
installApp != null -> listOf(
MaestroCommand(
InstallApplicationCommand(
apkPath = installApp.apkPath,
label = installApp.label
)
)
)
else -> throw SyntaxError("Invalid command: No mapping provided for $this")
}
}
Expand Down Expand Up @@ -688,6 +697,10 @@ data class YamlFluentCommand(
toggleAirplaneMode = YamlToggleAirplaneMode()
)

"installApp" -> YamlFluentCommand(
installApp = YamlInstallApp()
)

else -> throw SyntaxError("Invalid command: \"$stringCommand\"")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package maestro.orchestra.yaml

import com.fasterxml.jackson.annotation.JsonCreator

data class YamlInstallApp(
val apkPath: String? = null,
val label: String? = null,
) {
companion object {
@JvmStatic
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
fun parse(apkPath: String) = YamlInstallApp(
apkPath = apkPath,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,10 @@ class FakeDriver : Driver {
this.airplaneMode = enabled
}

override fun installApk(apk: File) {
events.add(Event.InstallApp)
}

sealed class Event {

data class Tap(
Expand Down Expand Up @@ -486,6 +490,8 @@ class FakeDriver : Driver {
object StartRecording : Event()

object StopRecording : Event()

object InstallApp: Event()
}

interface UserInteraction
Expand Down
18 changes: 18 additions & 0 deletions maestro-test/src/test/kotlin/maestro/test/IntegrationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3137,6 +3137,24 @@ class IntegrationTest {
driver.assertHasEvent(Event.KillApp("another.app"))
}

@Test
fun `Case 117 - Install app`() {
// Given
val commands = readCommands("116_install_app")

val driver = driver {
}

// When
Maestro(driver).use {
orchestra(it).runFlow(commands)
}

// Then
// No test failure
driver.assertHasEvent(Event.InstallApp)
}

private fun orchestra(
maestro: Maestro,
) = Orchestra(
Expand Down
3 changes: 3 additions & 0 deletions maestro-test/src/test/resources/116_install_app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
appId: com.example.app
---
- installApp: "maestro-client/src/main/resources/maestro-app.apk"
bartekpacia marked this conversation as resolved.
Show resolved Hide resolved