Skip to main content

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 a TutorialFirstPage object. On this object, we call titleShouldBe 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.

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 connections
  • browserstack.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

ParameterTypeDescription
screenObjectAn 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.).