The idea of “TestUI” was born from a desire of having a simpler way to automate tests for mobile. A framework that would allow you to concentrate merely on writing test cases and not coding for hours until finally discovering why your Appium server or your device did not connect to your scenarios or why the functions you wrote do not work as they should.
At first, you will probably be happy to have a faster way of creating the Appium server and driver, but the framework does much more than that! It provides a fluent API which makes your code readable, simple and efficient. This framework was inspired by a similar one for desktop browser automation ( Selenide), so for those who have worked with it will find the methods quite similar. Now let's check how it looks...
- Installation
- Start using TestUI
- Elements
- Collections
- Browser Testing
- Driver and Server
- Configuration Settings
- Quick Start
- Code Examples
- Project Contributors
Add Jitpack as a repository in your pom.xml
file:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Then add TestUI dependency
<dependencies>
<dependency>
<groupId>com.github.testdevlab</groupId>
<artifactId>TestUI</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
Add the following lines to build.gradle.kts
repositories {
maven { url = "https://jitpack.io" }
}
dependencies {
implementation("com.github.testdevlab:TestUI:2.0.0")
}
Add the following lines to build.gradle
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.testdevlab:TestUI:2.0.0'
}
Here you see an example of creating an Appium server and Appium driver connecting your device or starting an emulator present in your computer:
public class AndroidTest {
public void option1() {
Configuration.automationType = Configuration.ANDROID_PLATFORM;
Configuration.appPackage = "appPackage";
Configuration.appActivity = "appActivity";
open();
}
// or
public void option2() {
Configuration.automationType = Configuration.ANDROID_PLATFORM;
Configuration.androidAppPath = "relative or absolute path";
open();
}
}
That’s all! After your tests end, the driver will quit and the server will stop without writing any line of code. But there is a question that will rise in the minds of the most exigent testers: can it handle forks or executing different tests at the same time? Yes, it will automatically open as many Appium servers as forks you have chosen, and it will use a different device per server. In case you have devices connected to your machine, it will take those first, but if there are no enough connected devices to choose, then it will search for emulators and will start them and finally create linked drivers.
After this useful features you could just choose to work with Appium as it is documented in its official site; just call the getDriver() method and you will be able to manage all the features included by Appium java. But of course this is not yet the same as the browser counterpart Selenide. Now we want Appium elements and Appium collections that work as the Selenide ones. Here we have an example of an Appium element. With this element you will have a selection of the most useful functions to be used in your tests.
public class Test {
UIElement element = E(byId("your.Id"));
public void test() {
element.click();
element.sendKeys("some text");
element.getValue();
// you can also chain methods
element.click().and().sendKeys("some text").and().getValue();
}
}
We provide assertions as well:
public class Test {
public void test() {
element.shouldBe().visible();
element.shouldHave().exactText("some text");
// or you can chain methods like so
element.shouldBe().visible().and().shouldHave().exactText("some text");
}
}
Moreover, the framework will always wait for 5 seconds before considering that one element is not
clickable, enabled or visible (This timeout can be changed by
setting Configuration.timeout = timeInSeconds
that you wish as default). In case it has gone
through those 5 seconds and still not fitting the imposed conditions it will rise an error that
informs you about which element made your test fail. Nonetheless sometimes the app under test is not
as fast as we would want it to be, and in these cases 5 seconds is asking too much... then you can
choose to wait more without changing the global configuration, just like this:
public class Test {
public void test() {
element.waitFor(10).untilIsVisible();
element.waitFor(10).untilIsEnabled();
element.waitFor(10).untilHasText("Some text");
}
}
Even though now the framework seems to be quite appealing, it has two more features that will satisfy testers with browser versions of their apps or mobile apps that also work in computer browsers, for example responsive websites. In this case you can open a chrome browser in your device substituting the openApp method aforementioned by:
public class Test {
public void test() {
Configuration.automationType = Configuration.ANDROID_PLATFORM;
open("url");
}
}
The rest will work the same as with the app method. But wait... because there is one last thing to
mention:
it integrates with Selenide! This means that you can choose to use a laptop browser by changing one
single boolean variable (Configuration.useDevice
) to false, and you will be able to use the same
Appium elements and collections in your laptop browser tests, or just write new ones with the same
syntax as the ones we have used for Appium. This is quite useful since some elements are common in
both screen sizes, and therefore you can increase the reusable code.
The procedure for opening an iOS app is quite similar to the Android counterpart, the only difference comes with the testUI driver specifications, in this case you have to choose a device name, its version and also the path of the iOS' .app for testing:
public class Test {
public void test() {
Configuration.automationType = Configuration.IOS_PLATFORM;
Configuration.iOSVersion = "12.2";
Configuration.AppPath = "/path/to/testapp.app";
Configuration.deviceName = "iPhone 6";
open();
}
}
In case you want to test the Safari browser within the device, you can avoid writing the AppPath and instead of open app method use the following method for browser:
public class Test {
public void test() {
Configuration.automationType = Configuration.IOS_PLATFORM;
Configuration.iOSVersion = "12.2";
Configuration.deviceName = "iPhone 6";
open("http://example.com");
}
}
In certain scenarios, applications may switch contexts, which can be necessary for automation purposes. Utilize the following function to switch the application context:
switchApplicationContext(""); // Pass the application context to switch to
Same element can be defined for all the platforms, i.e. same element definition for iOS, android and computer Browser:
public class Test {
UIElement element = E(byId("your.Id"));
}
But in most cases the elements are different for each platform. For those cases you can specify elements for specific platforms this way:
public class Test {
UIElement element = E(byId("your.Id"))
.setSelenideElement(byXpath("//some"))
.setiOSElement(byCssSelector(".something"));
}
element.given().when().then().and()
element.click()
element.sendKeys()
element.getText()
element.getValue()
element.getAttribute("attribute")
element.scrollTo()
element.scrollUp()
Note: For the web version, both scrollUp() and scrollDown() use the same Selenide method.
element.scrollDown()
element.swipe(element)
element.swipeLeft()
element.swipeRight()
element.(shouldBe()/shouldHave()) (.not()) .visible() .enabled() .Exists() .exactText("someText")/containText("")/containNoCaseSensitiveText("") .value("someValue") .attribute("attributeName").equalTo("value") .theAttribute("attribute")
element.waitFor(timeInteger) .untilIs(Not)Visible() .untilIs(Not)Enabled() .until(Not)Exist() .untilHas(Not)Text("someText") .untilHas(Not)Value("someValue") .untilHas(Not)Attribute("someAttribute")
Collection definition:
UICollection collection = EE(byId(“your.Id”));
or:
UICollection collection = EE(byId(“your.Id”), byId(“your.Id2”), ...);
You can also use a definition per platform like this:
UICollection collection = EE(byId(“your.Id”)) .selenideCollection(byXpath("//some"")) .iOSCollection(byCssSelector(".something""));
collection.get(index)
collection.first()
collection.findByVisible()
collection.findByEnabled()
collection.findByExist()
collection.waitUntilAllVisible(timeSeconds) // Only makes sense for collection definitions like EE(E(...), E(...), ...)
collection.findByText("some text")
Once you specify which element form the collection you have the same methods than in the element section above
With testUI you can test browsers in mobile devices and computers just by changing the boolean value of a single variable:
public class Test {
public void test() {
Configuration.automationType = Configuration.IOS_PLATFORM;
Configuration.automationType = Configuration.ANDROID_PLATFORM;
Configuration.automationType = Configuration.DESKTOP_PLATFORM;
}
}
And then using:
open("url");
With this you will be able to open a web page in a computer device and navigate to the indicated url. By default it uses chrome but you can change that by setting:
Configuration.browser = "firefox", "safari", "edge", "ie"...
You just have to make sure your computer has these browsers installed.
In case you want to use a remote browser such as selenium grid, you just have to specify the url to this grid as follows:
Configuration.remote = "http://grid:4444/hub/wd"
testUI uses Selenide for computer browser automation, so you can check their methods in the official page Here. In case you don't need mobile automation, you should use Selenide framwork instead, since it is a less heavy framework and the methods are the native ones.
For mobile browsers, android only has chrome for automation and iOS devices only has safari. So in these cases there is no point on specifying which browser to use, they will always take one of them.
Then for Android you will call:
Configuration.automationType = Configuration.ANDROID_PLATFORM; open("url");
And for iOS:
Configuration.automationType = Configuration.IOS_PLATFORM; Configuration.iOSversion = "12.2"; Configuration.iOSDevice = "iPhone 6"; open("url");
If you want to create the Appium driver the usual way, you can do so and set it in the testUI static method:
setDriver(YourAppiumDriver);
This way you will still be able to use all the element and collection methods mentioned before.
You can also start your own Appium server and then use it like this:
Configuration.appiumUrl = "AppiumURL"; // for example Configuration.appiumUrl = "https://localhost:4723/wd/hub" open()/open("url")
There is a Configuration.remote parameter parameter that works to open browser in a remote grid ( such as selenium grid or selenoid)
You can specify your own desired capabilities and start driver as:
setDesiredCapabilities(desiredCapabilities); openApp();
It is possible to add the android device connected of your choice by setting this variables:
Configuration.androidDeviceName = "deviceName"; Configuration.androidVersion = "version";
or the emulator:
Configuration.emulatorName = "emulatorName";
As mentioned in previous sections, there are some static variables that you can modify to choose between different options for your automation. Here we will give a detailed description for all of them.
- *
Configuration.appPackage
is a string variable that defines the appPackage of the Android application you want to test, and must be defined before callingopenApp()
method. - *
Configuration.appActivity
same rules as the appPackage, in this case it's the main activity of the android application. Configuration.browser (= "chrome")
(String) you can choose the browser you want to test. However, in mobile version, android just admits chrome and iOS only safari, so it would be just optional for desktop browser testing if you want to test other than chrome (this the default browser).Configuration.baseUrl
(String) it is possible to set the base url for browser automation.Configuration.timeout (= 5)
(integer) you can set the time out (in seconds) in which an element is considered to not be present in the current screen. By default is 5 seconds.Configuration.automationType (= DESKTOP_PLATFORM)
(String) There are three different types, ANDROID_PLATFORM, IOS_PLATFORM, DESKTOP_PLATFORM(default)Configuration.startMaximized (= false)
(boolean) when set to true the computer browser will start maximized.Configuration.headless (= false)
(boolean) in computer browser testing you can set this variable to true so it will start a headless session.Configuration.remote
(String) it is possible to set this variable to a specific url where you have running an Selenium grid which will control your bowsers.Configuration.appiumUrl
(String) it is possible to set this variable to a specific url where you have running an Appium server which will control your devices. In case of computer browser testing, it will point to a selenium grid or where the browsers are running remotely.Configuration.useEmulators (= true)
(boolean) when set to false, it uses only real devices.Configuration.driver (= 1)
(integer) with this variable you can switch between the different mobile drivers created under the same test scenario, being the first one the 1 and next ones 2, 3...Configuration.useAllure (= true)
(boolean) in case you dont want to use allure reporter it is possible to disable it by setting this variable to false.- *
Configuration.iOSVersion
(String) iOS version of the device in use. must be set before calling openiOSApp/Browser(). - *
Configuration.iOSAppPath
(String) path to the iOS compiled app for testing. - *
Configuration.iOSDeviceName
(String) iOS device name in use. Configuration.androidDeviceName
(String) it is possible to specify android device before opening app or browser with this variable.Configuration.emulatorName
(String) it is possible to specify android emulator before opening app or browser with this variable.Configuration.androidAppPath
(String) android relative app path to the apk (if it's in root of project directory => "app.apk"). It will reinstall the app in case of being specified..Configuration.androidVersion
(String) you can set manually the android version of your device. However this is not necessary since the version is taken automatically by adb commands testUI executes previous to generate the driverConfiguration.chromeDriverPath
(String) relative path of your chromedriver (if it's in the root of your directory => "chromedriver"). Only specify if current is not working.Configuration.softAsserts
(Boolean) if set to True, then any TestUI error will not stop the execution, and in the end of the case (or any given part of the test) it is possible to callraiseSoftAsserts();
to raise all errors that have occurred through the test.
* this parameters are mandatory before calling open() or open("url")
Basic requirements and steps to start using TestUI
The framework is based on Java, therefore you will need to install Java 8 or above.
Then the setup depends on what platform or platforms you want to test on.
- Android - Appium setup for Android (Node.js, Android SDK, JDK, Appium)
- iOS - Appium setup for iOS (Node.js, Xcode, Carthage, Appium)
- Desktop browser - Selenide does everything for you :) No additional steps
For Appium setup check out their page and you can see if the setup was successful by using appium-doctor.
- Download this repository
- Go to repo in terminal:
cd path/to/repo/
- Execute the test:
-
- Android: connect device or start emulator and run
mvn clean -Dtest=TestAndroid test
- Android: connect device or start emulator and run
-
- iOS: connect device or start simulator and run
mvn clean -Dtest=TestIOS test
- iOS: connect device or start simulator and run
-
- Desktop Browser: have Chrome installed and run
mvn clean -Dtest=TestBrowser test
- Desktop Browser: have Chrome installed and run
Android app as a JUnit test case:
// You need to have the app 1188.apk in project root folder! @Test public void testAndroidApp() { Configuration.automationType = Configuration.ANDROID_PLATFORM; Configuration.androidAppPath = "1188.apk"; open(); Ex("//android.widget.Button[@text=\"Catering\"]").given().waitFor(10).untilIsVisible().then().click(); EE(byId("lv.lattelecombpo.yellowpages:id/label")).get(1).then().waitFor(5).untilIsVisible().and().click(); System.out.println(EE(byId("lv.lattelecombpo.yellowpages:id/label")).then().findByVisible().and().getText()); }
Android browser as JUnit test case:
@Test public void testAndroidBrowser() { Configuration.automationType = Configuration.ANDROID_PLATFORM; open("https://www.google.com"); E(byXpath("//input[@name='q']")).given().waitFor(5).untilIsVisible().then().sendKeys("TestUI"); E(byXpath("//button[@class='Tg7LZd']")).given().waitFor(10).untilIsVisible().then().click(); }
Desktop browser as JUnit test case:
@Test public void testAndroidBrowser() { Configuration.automationType = Configuration.DESKTOP_PLATFORM; open("https://www.google.com"); E(byXpath("//input[@name='q']")).given().waitFor(5).untilIsVisible().then().sendKeys("TestUI"); E(byXpath("//button[@class='Tg7LZd']")).given().waitFor(10).untilIsVisible().then().click(); }
IOS App as JUnit test case:
@Test public void testIOSApp() { Configuration.automationType = Configuration.IOS_PLATFORM; Configuration.iOSVersion = "12.2"; Configuration.iOSAppPath = "testapp.app"; Configuration.iOSDeviceName = "iPhone 6"; open(); }
IOS browser as JUnit test case:
@Test public void testIOSBrowser() { Configuration.automationType = Configuration.IOS_PLATFORM; open("https://www.facebook.com"); E(byXpath("//input[@name='email']")).getSafariFacebookEmailDiv().click(); }
We are glad to hear your feedback or review your suggestions for TestUI framework!
In case there is some bug, you can report that as an Issue or send an E-mail to testui@testdevlab.com . The format for these Issues should be as follows:
(Version)
App Android/Browser chrome Android/App iOS/ Browser Safario iOS/ Computer Browser... (Mentioning which app you are testing could help)
Given I set the configuration variables: this, this and this
And I start an testUI driver with open() method
Then I use this method
The method doesnt do what is expected
Full stacktrace
COMING SOON