Hello,
I am writing tests for a mobile browser chat application using Screenplay and Appium
My tests can have multiple Actors which may use different devices
My question is: What is the recommended way to manage multiple devices in a single test?
I've tried using serenity.properties to configure properties such as:
appium.hub = http://127.0.0.1:4723/wd/hub
appium.platformName = Android
appium.platformVersion = 5.1.1
appium.deviceName = e2f5c460
appium.browserName = Chrome
However, this seems to only support a single device.
It's unclear if something similar is supported in serenity.conf
Currently, I'm considering something like this to configure my capabilities
public DesiredCapabilities capabilities(String deviceModel, String browserName) {
DesiredCapabilities capabilities;
if (deviceModel.equals("Samsung S10")) {
capabilities = DesiredCapabilities.android();
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "879e6464");
capabilities.setCapability("platformVersion","10.0");
}
if (deviceModel.equals("iPhone XS")) {
capabilities = DesiredCapabilities.iphone();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion","12");
capabilities.setCapability("deviceName", "iPhone XS");
}
if( capabilities != null) {
capa.setCapability("browserName", browserName);
}
return capabilities;
}
Any advice is appreciated :)
There isn't currently any built-in support for multiple devices in a built-in test.
Thank you for your reply.
I did some digging through the code. You are correct, there appears to be multiple difficulties with achieving this. I did come across AppiumConfiguration.from(environmentVariables).getCapabilities(options) which can at least generate my desired capabilities. or I can specify the options in the @Managed tag
That being said, I would love to see something like:
devices{
iPhoneXS {
platformName = IOS
platformVersion = 12
deviceName = "iPhone XS"
}
SamsungS10 {
platformName = "Android"
platformVersion = 10.0
deviceName = 879e6464
}
}
AppiumConfiguration.from(environmentVariables).getCapabilitiesForDevice("iPhoneXS")
You can use multiple devices, because u can specify to each actor which device to use, I have done it using something like:
class MobileActorsCast() : Cast() {
override fun actorNamed(actorName: String, vararg abilities: Ability?): Actor {
val deviceId = getCurrentAndroidDevices().last()
return super.actorNamed(actorName, UseAMobileDevice.with(theDefaultDriverFor(actorName, deviceId)))
}
private fun theDefaultDriverFor(actorName: String, deviceId: String): WebDriver {
return ThucydidesWebDriverSupport.getWebdriverManager()
.withOptions("deviceName=$deviceId;udid=$deviceId")
.getWebdriverByName(actorName)
}
private fun getCurrentAndroidDevices(): List<String> {
val process = ProcessBuilder("adb", "devices")
.redirectErrorStream(true)
.start()
val output = readOutput(process.inputStream)
process.waitFor()
return output
.mapNotNull {
it.substringBefore("\tdevice", "")
.ifEmpty { null }
}
.ifEmpty { error("There are no Android devices connected") }
}
private fun readOutput(inputStream: InputStream): List<String> {
return BufferedReader(InputStreamReader(inputStream)).use {
it.lines().toList()
}
}
}
UseAMobile is just an ability that I made.
class UseAMobileDevice(private val webDriver: WebDriver) : BrowseTheWeb(webDriver) {
override fun toString(): String {
return "Use a Mobile device"
}
fun getAndroidDriver(): AndroidDriver<*> {
return ((webDriver as WebDriverFacade).proxiedDriver as AndroidDriver<*>)
}
companion object {
fun with(webDriver: WebDriver) = UseAMobileDevice(webDriver)
}
}
I've come up with my own solution for this. See this sample project.
I would gladly submit a PR if it's useful for others. I would need to solve #2289 before it would be useful to JUnit users though.
Most helpful comment
You can use multiple devices, because u can specify to each actor which device to use, I have done it using something like:
UseAMobile is just an ability that I made.