Skip to content

Commit

Permalink
Add installApp command (mobile-dev-inc#1665)
Browse files Browse the repository at this point in the history
  • Loading branch information
Muhammed Furkan Boran committed Jul 30, 2024
1 parent 0cd8bc1 commit 6ed69d8
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 0 deletions.
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")
}

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(
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"

0 comments on commit 6ed69d8

Please sign in to comment.