Mobile DSL
Architecture
Most of the architecture used in the Mobile DSL is very similar to the architecture for the Web DSL.
The Mobile DSL is mainly based on annotation helpers that allow to define screen objects using a declarative style.
Given the following test flow:
app
.openHomeScreen()
.openTutorial()
.titleShouldBe("MyAppTitle");
we need to define screen objects representing each a screen in the app flow, and actions possible on each screen. In traditional testing frameworks that would require writing code for all of these 3 methods plus the condition that verifies that the landing page is enough loaded to proceed. In Pumpo#5, annotations can be used to define what each method does as follows:
@Wait("cz.myApp.app:id/tutLogo")
public interface HomeScreen {
@Click("cz.myApp.app:id/tutStart")
TutorialFirstPage openTutorial();
}
@Wait("cz.myApp.app:id/tutTitle")
public interface TutorialFirstPage {
@AssertElementContent("cz.myApp.app:id/tutTitle")
TutorialFirstPage titleShouldBe(String expectedTitle);
}
The annotation @Wait
define what the methods openHomeScreen
and openTutorial
will do:
- As soon as the screen opens, wait for a specific element to appear before proceeding with further actions.
In those cases, the specific elements are a tutorial logo, and a tutorial title.
openTutorial
will@Click
on the button to start the tutorial and return aTutorialFirstPage
object. On this object, we calltitleShouldBe
method to assert that the title is equal to an expected string, through the@AssertElementContent
annotation.
Everything else is similar to the Web DSL. You can chain annotations, use dynamic lookup values and more. Please refer to the Web DSL architecture documentation here for more details.
Page Object Annotations reference
The Page Object annotations used in the Mobile DSL are exactly the same as the ones used in the Web DSL.
Please, check the documentation for Web DSL annotations here.
Configuring Android mobile application object
The first thing you will need to create a mobile test is to test pumpo#5 framework what application you want to test and how you want to test it.
Basic setup
You should start by selecting your platform:
import static dev.pumpo5.config.ConfigKeys.CAPABILITY_MOBILE_PLATFORM;
import static dev.pumpo5.config.ConfigKeys.CAPABILITY_MOBILE_PLATFORM_ANDROID;
@WebDriverUrl("appium.farm.url")
@Capability(key = CAPABILITY_MOBILE_PLATFORM, value = CAPABILITY_MOBILE_PLATFORM_ANDROID)
public interface MyAppAndroid extends MobileApplication {
}
In the example above we configured a mobile application on android platform (for application that run on both android and iOS platforms you will have to use conditional capabilities, see bellow).
The @WebDriverUrl("appium.farm.url")
is used to specify appium farm (your local appium server, Browserstack, etc). Most of the time it will not be a part of shared farm and this way we can provide appium specific connection string. In your config you will have something like appium.farm.url="http://localhost:4723/wd/hub"
if case you are running local Appium server.
Next, we need to add a set of required capabilities for the Appium driver:
...
import io.appium.java_client.remote.MobileCapabilityType;
...
@Capability(key = MobileCapabilityType.DEVICE_NAME, value = "Samsung Galaxy S20")
@Capability(key = MobileCapabilityType.PLATFORM_VERSION, value = "10.0")
@Capability(key = MobileCapabilityType.UDID, value = "deviceId", type = ValueType.STRING_PROPERTY)
@Capability(key = MobileCapabilityType.NEW_COMMAND_TIMEOUT, value = "mobile.session.timeout", type = ValueType.STRING_PROPERTY)
public interface MyAppAndroid extends MobileApplication {
}
The full set of mobile capabilities (both general, i.e. used by both Android and iOS and platform specific capabilities) and their meaning can be found on Appium help page.
Video recording option
Prerequisite: On server side you need to have ffmpeg installed and available in your path.
For mobile tests we can enable option that record video and save them to allure report
if test fail.Work only for IOS and Android.To do that we need to add following configuration:
pn5.video.enabled = true
pn5.video.time.limit = 5 // in minutes this is optional, default is 3 minutes
pn5.video.resolution = "720x1280" // this is optional, default is 720x1280
Installing application
It is possible to install application every time you run a test. Capability MobileCapabilityType.APP
is used for that. We refer you to Appium help page for details.
Starting application (recommended)
In most cases you will have app already installed on your device and would want to start it at when the test starts. Following additional capabilities allow you to do it:
...
import io.appium.java_client.remote.AndroidMobileCapabilityType;
...
@Capability(key = AndroidMobileCapabilityType.APP_PACKAGE, value = "appPackage", type = ValueType.STRING_PROPERTY)
@Capability(key = AndroidMobileCapabilityType.APP_ACTIVITY, value = "appActivity", type = ValueType.STRING_PROPERTY)
@Capability(key = AndroidMobileCapabilityType.SKIP_UNLOCK, value = "true", type = ValueType.BOOLEAN)
public interface MyAppAndroid extends MobileApplication {
}
Note: In my example I used both ways to specify values for capabilities: literal (value = "Samsung Galaxy S20") and driven by configuration (value = "mobile.session.timeout", type = ValueType.STRING_PROPERTY). Both are fine, pick the approach that works for you.
Using Browserstack
You can test application on Browserstack or any other mobile devices test farm provider. To do that you need to add additional (you guessed it by now I am sure) capabilities:
...
@Capability(key = MobileCapabilityType.APP, value = "app.url", type = ValueType.STRING_PROPERTY)
public interface MyAppAndroid extends MobileApplication {
}
In case of Browserstack MobileCapabilityType.APP
will not install the app, but rather tell browser stack which app upload to use. Details about application upload can be found in Browserstack documenation.
Note: Do not forget to change URL of your test farm. If you used @WebDriverUrl("appium.farm.url")
from example above, then change your config to something like this appium.farm.url="https://<username>:<api key>@hub-cloud.browserstack.com/wd/hub"
Local testing with Browserstack
Browserstack supports local testing mode. This is a way to connect Browserstack device to your local private network (to access non-public back API services for example). All you need to do is to add following capability:
@Capability(key = "browserstack.local", value = "true")
Local testing comes with additional features like proxy which you can configure in your config file. Here is an example:
browserstack.local.create=true
browserstack.local.force=true
browserstack.proxy.host="10.100.0.19"
browserstack.proxy.port=3128
browserstack.proxy.force=true
browserstack.local.create
will create a BrowserstackLocal process for you so you don't need to download and run the binary yourself.browserstack.local.force
will force use of local connection (MITM proxy) for all connectionsbrowserstack.proxy.*
allow you to specify proxy configuraton for your private network
Conditional capabilities
Sometimes, you may need to work with a complex scenario in your tests. You are developing mobile tests for both Android and iOS at the same time. Each platform needs its own set of capabilities.
At the moment, you can set up a specific lookup prefix ID for when testing Android applications. More conditional capabilities can be added in the future.
Example scenario:
import static dev.pumpo5.config.ConfigKeys.CAPABILITY_MOBILE_PLATFORM;
import static dev.pumpo5.config.ConfigKeys.CAPABILITY_MOBILE_PLATFORM_ANDROID;
// Common
@Capability(key = CAPABILITY_MOBILE_PLATFORM, value = "mobile.platform", type = ValueType.STRING_PROPERTY)
@Capability(key = "pn5:lookup:default", value = "id")
// Android
@Capability(key = "pn5:idPrefix", value = "myOwnLookupPrefix/", whenParameter = CAPABILITY_MOBILE_PLATFORM, hasValue = CAPABILITY_MOBILE_PLATFORM_ANDROID)
@Capability(group = "bstack:options", key = "acceptInsecureCerts", value = "true", whenParameter = CAPABILITY_MOBILE_PLATFORM, hasValue = CAPABILITY_MOBILE_PLATFORM_ANDROID)
public interface MyApp extends MobileApplication {
...
}
Here we assume that MyApp
is used to test both Android and iOS applications. We have to provide three types of capabilities:
- Used for both Android and iOS applications. In example above
@Capability(key = "pn5:lookup:default", value = "id")
will be used in both cases - Used for Android only. In example above
@Capability(key = "pn5:idPrefix", value = "myOwnLookupPrefix/", whenParameter = CAPABILITY_MOBILE_PLATFORM, hasValue = CAPABILITY_MOBILE_PLATFORM_ANDROID)
will be only used for Android - Used for iOS only. There is no example above, but it would be something like
@Capability(key = "pn5:idPrefix", value = "myOwnLookupPrefix/", whenParameter = CAPABILITY_MOBILE_PLATFORM, hasValue = CAPABILITY_MOBILE_PLATFORM_IOS)
Once you have MyApp configured this way and a test that uses it, you will need to run that test twice (once for Android and once for iOS). The @Capability(key = CAPABILITY_MOBILE_PLATFORM, value = "mobile.platform", type = ValueType.STRING_PROPERTY)
instructs pn5 to resolve the value of platform against config key mobile.platform
, so make sure to set it to pn5:mobile:android
or pn5:mobile:ios
depending on your goals.
Method Reference
MobileApplication::open
Parameter | Type | Description |
---|---|---|
screen | Object | An interface representing a screen to be opened from a mobile application |
The only method available from the mobile proxy client, it is used to open a screen from a mobile application. Any other methods you want to chain call should be added and called from response object. Those methods must be annotated with the typical actions listed above (@Click, @Wait, etc.).