- Created by Phil Gochenour, last modified by Rachel Andre on Jun 25, 2020
These Appium scripts for Android mobile application tests can help streamline your testing process.
For Example Purposes Only
The code in these scripts is provided on an "AS-IS” basis without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, merchantability, fitness for a particular purpose, or non-infringement. Your tests and testing environments may require you to modify these scripts. Issues regarding these scripts should be submitted through GitHub. These scripts are not maintained by Sauce Labs Support.
These examples employ the page object model to run tests on emulators and simulators. Feel free to clone these scripts directly from GitHub, and follow the instructions in the README file.
Page Objects
This object represents a single view/page in the sample application. Click below to see the script:
package example.android.Pages; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class GuineaPigPage { @FindBy(id = "Heading1_1") private WebElement h1Text; @FindBy(id = "i_am_a_link") private WebElement theActiveLink; @FindBy(id = "your_comments") private WebElement yourComments; @FindBy(id = "comments") private WebElement commentsTextInput; @FindBy(id = "submit") private WebElement submitButton; public WebDriver driver; public GuineaPigPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } public void submitComment(String text) { this.commentsTextInput.click(); this.commentsTextInput.sendKeys(text); hideKeyboard(); this.submitButton.click(); } public String getSubmittedCommentText() { return this.yourComments.getText(); } public void followLink() { this.theActiveLink.click(); } public boolean isOnPage() { try { getSubmittedCommentText(); return true; } catch (NoSuchElementException ex) { return false; } } /** * This method only work for this page and assumes the app supports keyboard hide on click-away. */ public void hideKeyboard() { this.h1Text.click(); } }
Test Objects
These object represent the individual tests, as well as the prerequisite and postrequisite test tasks (TestBase.java). Click on any of the text below to see the scripts:
package example.android.Tests; // import Sauce TestNG helper libraries import com.saucelabs.common.SauceOnDemandAuthentication; import com.saucelabs.common.SauceOnDemandSessionIdProvider; import com.saucelabs.testng.SauceOnDemandAuthenticationProvider; import com.saucelabs.testng.SauceOnDemandTestListener; import io.appium.java_client.android.AndroidDriver; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.rmi.UnexpectedException; // import testng annotations // import java libraries /** * Simple TestNG test which demonstrates being instantiated via a DataProvider in order to supply multiple browser combinations. * * @author Neil Manvar */ @Listeners({SauceOnDemandTestListener.class}) public class TestBase implements SauceOnDemandSessionIdProvider, SauceOnDemandAuthenticationProvider { public String seleniumURI = "@ondemand.saucelabs.com:443"; public String buildTag = System.getenv("BUILD_TAG"); public String username = System.getenv("SAUCE_USERNAME"); public String accesskey = System.getenv("SAUCE_ACCESS_KEY"); public String app = "https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/android/GuineaPigApp-debug.apk?raw=true"; //public String app = "../../../../../../resources/android/GuineaPigApp-debug.apk"; /** * Constructs a {@link SauceOnDemandAuthentication} instance using the supplied user name/access key. To use the authentication * supplied by environment variables or from an external file, use the no-arg {@link SauceOnDemandAuthentication} constructor. */ public SauceOnDemandAuthentication authentication = new SauceOnDemandAuthentication(username, accesskey); /** * ThreadLocal variable which contains the {@link AndroidDriver} instance which is used to perform browser interactions with. */ private ThreadLocal<AndroidDriver> androidDriver = new ThreadLocal<AndroidDriver>(); /** * ThreadLocal variable which contains the Sauce Job Id. */ private ThreadLocal<String> sessionId = new ThreadLocal<String>(); /** * DataProvider that explicitly sets the browser combinations to be used. * * @param testMethod * @return Two dimensional array of objects with browser, version, and platform information */ @DataProvider(name = "hardCodedBrowsers", parallel = true) public static Object[][] sauceBrowserDataProvider(Method testMethod) { return new Object[][]{ new Object[]{"Android", "Samsung Galaxy Tab S3 GoogleAPI Emulator", "8.1", "1.9.1", "portrait"}, new Object[]{"Android", "Samsung Galaxy S9 Plus FHD GoogleAPI Emulator", "8.1", "1.9.1", "portrait"} }; } /** * @return the {@link AndroidDriver} for the current thread */ public AndroidDriver getAndroidDriver() { return androidDriver.get(); } /** * @return the Sauce Job id for the current thread */ public String getSessionId() { return sessionId.get(); } /** * @return the {@link SauceOnDemandAuthentication} instance containing the Sauce username/access key */ @Override public SauceOnDemandAuthentication getAuthentication() { return authentication; } /** * Constructs a new {@link AndroidDriver} instance which is configured to use the capabilities defined by the browser, * version and os parameters, and which is configured to run against ondemand.saucelabs.com, using * the username and access key populated by the {@link #authentication} instance. * * @param platformName name of the platformName. (Android, iOS, etc.) * @param deviceName name of the device * @param platformVersion Os version of the device * @param appiumVersion appium version * @param deviceOrientation device orientation * @return * @throws MalformedURLException if an error occurs parsing the url */ protected void createDriver( String platformName, String deviceName, String platformVersion, String appiumVersion, String deviceOrientation, String methodName) throws MalformedURLException, UnexpectedException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("platformName", platformName); capabilities.setCapability("platformVersion", platformVersion); capabilities.setCapability("deviceName", deviceName); capabilities.setCapability("browserName", ""); capabilities.setCapability("deviceOrientation", deviceOrientation); capabilities.setCapability("appiumVersion", appiumVersion); capabilities.setCapability("name", methodName); capabilities.setCapability("app", app); capabilities.setCapability("build", "Java-TestNG-Appium-Android"); if (buildTag != null) { capabilities.setCapability("build", buildTag); } // Launch remote browser and set it as the current thread androidDriver.set(new AndroidDriver( new URL("https://" + authentication.getUsername() + ":" + authentication.getAccessKey() + seleniumURI + "/wd/hub"), capabilities)); String id = ((RemoteWebDriver) getAndroidDriver()).getSessionId().toString(); sessionId.set(id); } /** * Method that gets invoked after test. * Dumps browser log and * Closes the browser */ @AfterMethod public void tearDown() throws Exception { //Gets browser logs if available. androidDriver.get().quit(); } }
package example.android.Tests; import example.android.Pages.GuineaPigPage; import org.openqa.selenium.InvalidElementStateException; import org.openqa.selenium.WebDriver; import org.testng.Assert; import org.testng.annotations.Test; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.rmi.UnexpectedException; /** * Created by mehmetgerceker on 12/7/15. * Updated by spider@saucelabs.com on 10/8/19. */ public class FollowLinkTest extends TestBase { /** * Runs a simple test verifying link can be followed. * * @throws InvalidElementStateException */ @Test(dataProvider = "hardCodedBrowsers") public void verifyLinkTest(String platformName, String deviceName, String platformVersion, String appiumVersion, String deviceOrientation, Method method) throws MalformedURLException, InvalidElementStateException, UnexpectedException { //create webdriver session this.createDriver(platformName, deviceName, platformVersion, appiumVersion, deviceOrientation, method.getName()); WebDriver driver = this.getAndroidDriver(); GuineaPigPage page = new GuineaPigPage(driver); page.followLink(); Assert.assertFalse(page.isOnPage()); } }
package example.android.Tests; import example.android.Pages.GuineaPigPage; import org.openqa.selenium.InvalidElementStateException; import org.openqa.selenium.WebDriver; import org.testng.Assert; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.rmi.UnexpectedException; import java.util.UUID; /** * Created by mehmetgerceker on 12/7/15. */ public class TextInputTest extends TestBase { /** * Runs a simple test verifying if the comment input is functional. * @throws InvalidElementStateException */ @org.testng.annotations.Test(dataProvider = "hardCodedBrowsers") public void verifyCommentInputTest(String platformName, String deviceName, String platformVersion, String appiumVersion, String deviceOrientation, Method method) throws MalformedURLException, InvalidElementStateException, UnexpectedException { this.createDriver(platformName, deviceName, platformVersion, appiumVersion, deviceOrientation, method.getName()); WebDriver driver = this.getAndroidDriver(); String commentInputText = UUID.randomUUID().toString(); GuineaPigPage page = new GuineaPigPage(driver); page.submitComment(commentInputText); Assert.assertTrue(page.getSubmittedCommentText().contains(commentInputText)); } }
The example below employs the page object model using WebDriverIO test automation framework to run tests on emulators and simulators. For more Webdriver examples, see Sauce Labs Training on GitHub: Node.js examples repository (be sure to read the follow the README file first).
WebDriverIO Config
This script represents the prerequisite and postrequisite test tasks. Click below to see the script:
const {config} = require('./wdio.shared.local.appium.conf'); // ================== // Specify Test Files // ================== config.specs= [ './test/specs/emu-sim/*.js' ]; // ============ // Capabilities // ============ // For all capabilities please check // http://appium.io/docs/en/writing-running-appium/caps/#general-capabilities config.capabilities = [ { // The defaults you need to have in your config automationName: 'UiAutomator2', deviceName: 'Pixel_3_10.0', platformName: 'Android', platformVersion: '10.0', orientation: 'PORTRAIT', // Provide the Google Photos package here but don't start it appPackage: 'com.google.android.apps.photos', appActivity: '.home.HomeActivity', autoLaunch: false, // Read the reset strategies very well, they differ per platform, see // http://appium.io/docs/en/writing-running-appium/other/reset-strategies/ noReset: true, newCommandTimeout: 240, maxInstances: 1, // Always default the language to a language you prefer so you know the app language is always as expected language: 'en', locale: 'en', }, ]; exports.config = config;
These examples use the pytest test framework to run tests on real devices. Feel free to clone these scripts directly from GitHub, and follow the instructions in the README file.
Python Config
This script initializes the test fixtures, as well as the prerequisite and post-requisite test tasks.
import pytest import os import json import re from appium import webdriver def pytest_addoption(parser): parser.addoption("--dc", action="store", default='us', help="Set Sauce Labs Data Center (US or EU)") @pytest.fixture def data_center(request): return request.config.getoption('--dc') @pytest.fixture def ios_up_driver(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'iPhone.*', 'platformName': 'iOS', 'name': request.node.name, 'app': 'storage:filename=iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.2.1.ipa' } if data_center and data_center.lower() == 'eu': sauce_url = "http://ondemand.eu-central-1.saucelabs.com/wd/hub" else: sauce_url = "http://ondemand.us-west-1.saucelabs.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def ios_simulator(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'iPhone XS Simulator', 'appiumVersion': '1.17.1', 'platformName': 'iOS', 'platformVersion': "13.4", 'deviceOrientation': "portrait", 'name': request.node.name, 'app': 'storage:filename=iOS.Simulator.SauceLabs.Mobile.Sample.app.2.7.0.zip' } if data_center and data_center.lower() == 'eu': sauce_url = "http://ondemand.eu-central-1.saucelabs.com/wd/hub" else: sauce_url = "http://ondemand.us-west-1.saucelabs.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def ios_to_driver(request, data_center): caps = { 'platformName': 'iOS', 'deviceOrientation':'portrait', 'privateDevicesOnly': False, 'phoneOnly': True } rdc_key = os.environ['TESTOBJECT_SAMPLE_IOS'] caps['testobject_api_key'] = rdc_key test_name = request.node.name caps['name'] = test_name if data_center and data_center.lower() == 'eu': sauce_url = "http://appium.testobject.com/wd/hub" else: sauce_url = "http://us1.appium.testobject.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) # This is specifically for SauceLabs plugin. # In case test fails after selenium session creation having this here will help track it down. # creates one file per test non ideal but xdist is awful if driver: print("SauceOnDemandSessionID={} job-name={}\n".format(driver.session_id, test_name)) else: raise WebDriverException("Never created!") yield driver driver.quit() @pytest.fixture def android_to_driver(request, data_center): caps = { 'deviceName': 'Google.*', 'platformName': 'Android', 'deviceOrientation':'portrait', 'privateDevicesOnly': False } rdc_key = os.environ['TESTOBJECT_SAMPLE_ANDROID'] caps['testobject_api_key'] = rdc_key test_name = request.node.name caps['name'] = test_name if data_center and data_center().lower() == 'eu': sauce_url = "http://appium.testobject.com/wd/hub" else: sauce_url = "http://us1.appium.testobject.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) # This is specifically for SauceLabs plugin. # In case test fails after selenium session creation having this here will help track it down. # creates one file per test non ideal but xdist is awful if driver: print("SauceOnDemandSessionID={} job-name={}\n".format(driver.session_id, test_name)) else: raise WebDriverException("Never created!") yield driver driver.quit() @pytest.fixture def android_up_driver(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'Google.*', 'platformName': 'Android', 'name': request.node.name, 'app': 'storage:filename=Android.SauceLabs.Mobile.Sample.app.2.3.0.apk' } if data_center and data_center.lower() == 'eu': sauce_url = 'http://ondemand.eu-central-1.saucelabs.com/wd/hub' else: sauce_url = 'http://ondemand.us-west-1.saucelabs.com/wd/hub' driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def android_emulator(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'Android GoogleAPI Emulator', 'platformName': 'Android', 'platformVersion': '10.0', 'deviceOrientation': 'portrait', 'name': request.node.name, 'appiumVersion': '1.17.1', 'appWaitActivity': 'com.swaglabsmobileapp.MainActivity', 'app': 'storage:filename=Android.SauceLabs.Mobile.Sample.app.2.3.0.apk' } if data_center and data_center.lower() == 'eu': sauce_url = 'http://ondemand.eu-central-1.saucelabs.com/wd/hub' else: sauce_url = 'http://ondemand.us-west-1.saucelabs.com/wd/hub' driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit()
Test Objects
These scripts represents the individual test. Click below to see the script(s):
import pytest def test_add_to_cart(emusim_driver): emusim_driver.get('https://www.saucedemo.com/inventory.html') emusim_driver.find_element_by_class_name('btn_primary').click() assert emusim_driver.find_element_by_class_name('shopping_cart_badge').text == '1' emusim_driver.get('https://www.saucedemo.com/cart.html') expected = emusim_driver.find_elements_by_class_name('inventory_item_name') assert len(expected) == 1 def test_add_two_to_cart(emusim_driver): emusim_driver.get('https://www.saucedemo.com/inventory.html') emusim_driver.find_element_by_class_name('btn_primary').click() emusim_driver.find_element_by_class_name('btn_primary').click() assert emusim_driver.find_element_by_class_name('shopping_cart_badge').text == '2' emusim_driver.get('https://www.saucedemo.com/cart.html') expected = emusim_driver.find_elements_by_class_name('inventory_item_name') assert len(expected) == 2
import pytest def test_valid_crentials_login(emusim_driver): emusim_driver.get('https://www.saucedemo.com') emusim_driver.find_element_by_id('user-name').send_keys('locked_out_user') emusim_driver.find_element_by_id('password').send_keys('secret_sauce') emusim_driver.find_element_by_css_selector('.btn_action').click() assert emusim_driver.find_element_by_css_selector('.error-button').is_displayed()
import pytest def test_valid_crentials_login(emusim_driver): emusim_driver.get('https://www.saucedemo.com') emusim_driver.find_element_by_id('user-name').send_keys('standard_user') emusim_driver.find_element_by_id('password').send_keys('secret_sauce') emusim_driver.find_element_by_css_selector('.btn_action').click() assert "/inventory.html" in emusim_driver.current_url
Python Config
This script initializes the test fixtures, as well as the prerequisite and post-requisite test tasks.
import pytest import os import json import re from appium import webdriver def pytest_addoption(parser): parser.addoption("--dc", action="store", default='us', help="Set Sauce Labs Data Center (US or EU)") @pytest.fixture def data_center(request): return request.config.getoption('--dc') @pytest.fixture def ios_up_driver(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'iPhone.*', 'platformName': 'iOS', 'name': request.node.name, 'app': 'storage:filename=iOS.RealDevice.SauceLabs.Mobile.Sample.app.2.2.1.ipa' } if data_center and data_center.lower() == 'eu': sauce_url = "http://ondemand.eu-central-1.saucelabs.com/wd/hub" else: sauce_url = "http://ondemand.us-west-1.saucelabs.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def ios_simulator(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'iPhone XS Simulator', 'appiumVersion': '1.17.1', 'platformName': 'iOS', 'platformVersion': "13.4", 'deviceOrientation': "portrait", 'name': request.node.name, 'app': 'storage:filename=iOS.Simulator.SauceLabs.Mobile.Sample.app.2.7.0.zip' } if data_center and data_center.lower() == 'eu': sauce_url = "http://ondemand.eu-central-1.saucelabs.com/wd/hub" else: sauce_url = "http://ondemand.us-west-1.saucelabs.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def ios_to_driver(request, data_center): caps = { 'platformName': 'iOS', 'deviceOrientation':'portrait', 'privateDevicesOnly': False, 'phoneOnly': True } rdc_key = os.environ['TESTOBJECT_SAMPLE_IOS'] caps['testobject_api_key'] = rdc_key test_name = request.node.name caps['name'] = test_name if data_center and data_center.lower() == 'eu': sauce_url = "http://appium.testobject.com/wd/hub" else: sauce_url = "http://us1.appium.testobject.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) # This is specifically for SauceLabs plugin. # In case test fails after selenium session creation having this here will help track it down. # creates one file per test non ideal but xdist is awful if driver: print("SauceOnDemandSessionID={} job-name={}\n".format(driver.session_id, test_name)) else: raise WebDriverException("Never created!") yield driver driver.quit() @pytest.fixture def android_to_driver(request, data_center): caps = { 'deviceName': 'Google.*', 'platformName': 'Android', 'deviceOrientation':'portrait', 'privateDevicesOnly': False } rdc_key = os.environ['TESTOBJECT_SAMPLE_ANDROID'] caps['testobject_api_key'] = rdc_key test_name = request.node.name caps['name'] = test_name if data_center and data_center().lower() == 'eu': sauce_url = "http://appium.testobject.com/wd/hub" else: sauce_url = "http://us1.appium.testobject.com/wd/hub" driver = webdriver.Remote(sauce_url, desired_capabilities=caps) # This is specifically for SauceLabs plugin. # In case test fails after selenium session creation having this here will help track it down. # creates one file per test non ideal but xdist is awful if driver: print("SauceOnDemandSessionID={} job-name={}\n".format(driver.session_id, test_name)) else: raise WebDriverException("Never created!") yield driver driver.quit() @pytest.fixture def android_up_driver(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'Google.*', 'platformName': 'Android', 'name': request.node.name, 'app': 'storage:filename=Android.SauceLabs.Mobile.Sample.app.2.3.0.apk' } if data_center and data_center.lower() == 'eu': sauce_url = 'http://ondemand.eu-central-1.saucelabs.com/wd/hub' else: sauce_url = 'http://ondemand.us-west-1.saucelabs.com/wd/hub' driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit() @pytest.fixture def android_emulator(request, data_center): caps = { 'username': os.environ['SAUCE_USERNAME'], 'accessKey': os.environ['SAUCE_ACCESS_KEY'], 'deviceName': 'Android GoogleAPI Emulator', 'platformName': 'Android', 'platformVersion': '10.0', 'deviceOrientation': 'portrait', 'name': request.node.name, 'appiumVersion': '1.17.1', 'appWaitActivity': 'com.swaglabsmobileapp.MainActivity', 'app': 'storage:filename=Android.SauceLabs.Mobile.Sample.app.2.3.0.apk' } if data_center and data_center.lower() == 'eu': sauce_url = 'http://ondemand.eu-central-1.saucelabs.com/wd/hub' else: sauce_url = 'http://ondemand.us-west-1.saucelabs.com/wd/hub' driver = webdriver.Remote(sauce_url, desired_capabilities=caps) yield driver driver.quit()
Test Objects
These scripts represents the individual tests. Click below to see the script:
def test_blank_credentials(android_up_driver): android_up_driver.find_element_by_accessibility_id("test-Username").send_keys("") android_up_driver.find_element_by_accessibility_id("test-Password").send_keys("") android_up_driver.find_element_by_accessibility_id("test-LOGIN").click() assert android_up_driver.find_element_by_accessibility_id("test-Error message").is_displayed()
def test_standard_user(android_up_driver): android_up_driver.find_element_by_accessibility_id("test-Username").send_keys("standard_user") android_up_driver.find_element_by_accessibility_id("test-Password").send_keys("secret_sauce") android_up_driver.find_element_by_accessibility_id("test-LOGIN").click() assert android_up_driver.find_element_by_accessibility_id("test-PRODUCTS").is_displayed()
These examples employ the page object model and use either the RSpec or Cucumber test frameworks to run tests on emulators and simulators. Feel free to clone these scripts directly from GitHub, and follow the instructions in the README file.
Rakefile
This file initializes the test capabilities, as well as the prerequisite and postrequisite test tasks:
def run_tests(deviceName, platformName, platformVersion, app) system("deviceName=\"#{deviceName}\" platformName=\"#{platformName}\" platformVersion=\"#{platformVersion}\" app=\"#{app}\" parallel_split_test spec") end task :Andoid_Emulator_Phone_5_1 do run_tests('Android Emulator', 'Android', '5.1', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true') end task :Andoid_Emulator_Tablet_5_1 do run_tests('Android Emulator', 'Android', '5.1', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true') end task :Galaxy_S8_Emulator do run_tests('Samsung Galaxy S8 HD GoogleAPI Emulator', 'Android', '7.0', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true') end task :Galaxy_S6_Emulator do run_tests('Samsung Galaxy S6 GoogleAPI Emulator', 'Android', '7.0', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true') end task :iPhone_6_Simulator do run_tests('iPhone 6 Simulator', 'iOS', '10.3', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true') end task :iPhone_7_Simulator do run_tests('iPhone 7 Simulator', 'iOS', '12.0', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true') end task :iPad_Air_Simulator do run_tests('iPad Air Simulator', 'iOS', '11.2', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true') end task :iPad_Simulator do run_tests('iPad (6th generation) Simulator', 'iOS', '12.0', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true') end multitask :test_sauce => [ :Andoid_Emulator_Phone_5_1, :Galaxy_S8_Emulator, :Andoid_Emulator_Tablet_5_1, :Galaxy_S6_Emulator, :iPhone_6_Simulator, :iPhone_7_Simulator, :iPad_Air_Simulator, :iPad_Simulator, ] do puts 'Running automation' end
Page Objects
These scripts represent the individual views/pages of the sample application:
require_relative "../spec/spec_helper" class GuineaPigAppPage attr_accessor :driver def initialize(driver) @driver = driver end # Elements def textInput @driver.find_element(:id, "i_am_a_textbox") end def emailTextInput @driver.find_element(:id, "fbemail") end end
Spec Objects
These scripts represents the individual tests, as well as a Sauce Labs utility helper:
require_relative "../spec/spec_helper" class GuineaPigAppPage attr_accessor :driver def initialize(driver) @driver = driver end # Elements def textInput @driver.find_element(:id, "i_am_a_textbox") end def emailTextInput @driver.find_element(:id, "fbemail") end end
require_relative "../spec/spec_helper" class GuineaPigAppPage attr_accessor :driver def initialize(driver) @driver = driver end # Elements def textInput @driver.find_element(:id, "i_am_a_textbox") end def emailTextInput @driver.find_element(:id, "fbemail") end end
Rakefile
This file initializes the prerequisite and postrequisite test tasks:
def run_tests(deviceName, platformName, platformVersion, app, junit) system("deviceName=\"#{deviceName}\" platformName=\"#{platformName}\" platformVersion=\"#{platformVersion}\" app=\"#{app}\" parallel_cucumber features -n 20") end task :Andoid_Emulator_Phone_5_1 do run_tests('Android Emulator', 'Android', '5.1', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true', 'junit_reports/Andoid_Emulator_Phone_5_1') end task :Andoid_Emulator_Tablet_5_1 do run_tests('Android Emulator', 'Android', '5.1', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true', 'junit_reports/Andoid_Emulator_Tablet_5_1') end task :Galaxy_S8_Emulator do run_tests('Samsung Galaxy S8 HD GoogleAPI Emulator', 'Android', '7.0', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true', 'junit_reports/Galaxy_S8_Emulator') end task :Galaxy_S6_Emulator do run_tests('Samsung Galaxy S6 GoogleAPI Emulator', 'Android', '7.0', 'https://github.com/saucelabs-sample-test-frameworks/Java-Junit-Appium-Android/blob/master/resources/GuineaPigApp-debug.apk?raw=true', 'junit_reports/Galaxy_S6_Emulator') end task :iPhone_6_Simulator do run_tests('iPhone 6 Simulator', 'iOS', '10.3', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true', 'junit_reports/iPhone_6_Simulator') end task :iPhone_7_Simulator do run_tests('iPhone 7 Simulator', 'iOS', '12.0', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true', 'junit_reports/iPhone_5s_Simulator') end task :iPad_Air_Simulator do run_tests('iPad Air Simulator', 'iOS', '11.2', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true', 'junit_reports/iPad_Air_Simulator') end task :iPad_Simulator do run_tests('iPad (6th generation) Simulator', 'iOS', '12.0', 'https://github.com/saucelabs-training/demo-java/blob/master/appium-example/resources/ios/SauceGuineaPig-sim-debug.app.zip?raw=true', 'junit_reports/iPad_Simulator') end multitask :test_sauce => [ :Andoid_Emulator_Phone_5_1, :Galaxy_S8_Emulator, :Andoid_Emulator_Tablet_5_1, :Galaxy_S6_Emulator, :iPhone_6_Simulator, :iPhone_7_Simulator, :iPad_Air_Simulator, :iPad_Simulator, ] do puts 'Running automation' end
Environment Object
This script pulls the test capabilities for each device combo from the rake tasks; it also initializes the remote web driver object:
require 'appium_lib' require 'sauce_whisk' require 'rspec' Before do | scenario | # need to configure env variables for browser caps = { caps: { platformVersion: "#{ENV['platformVersion']}", deviceName: "#{ENV['deviceName']}", platformName: "#{ENV['platformName']}", app: "#{ENV['app']}", deviceOrientation: 'portrait', name: "#{scenario.feature.name} - #{scenario.name}", appiumVersion: '1.9.1', browserName: '', build: 'Appium-Ruby-Cucumber EmuSim Examples' } } @driver = Appium::Driver.new(caps, true) @driver.start_driver end # "after all" After do | scenario | sessionid = @driver.session_id jobname = "#{scenario.feature.name} - #{scenario.name}" puts "SauceOnDemandSessionID=#{sessionid} job-name=#{jobname}" @driver.driver_quit if scenario.passed? SauceWhisk::Jobs.pass_job sessionid else SauceWhisk::Jobs.fail_job sessionid end end
Test Features
These scripts represents the individual behavior scenarios that we define tests for in our step definitions:
Feature: Sample Ruby Cucumber Comment Test Scenario: Add a Comment Given I click on the comment box When I enter a comment Then I click the send button
Feature: Sample Ruby Cucumber Email Test Scenario: Enter an Email Address Given I click on the email box When I enter my email address Then I click the submit button
Test Step Definitions
These scripts define the specific steps our tests run in order to achieve the desired results from the test features:
Given /^I click on the comment box$/ do comment_input = @driver.find_element(:id, "comments") comment_input.click() end When /^I enter a comment$/ do comment_text = @driver.find_element(:id, "comments") comment_text.send_keys("My Exceptionally Eloquent Comment") end Then /^I click the send button$/ do submit_button = @driver.find_element(:id, "submit") submit_button.click() end
Given /^I click on the email box$/ do email_input = @driver.find_element(:id, "fbemail") email_input.click() end When /^I enter my email address$/ do email_text = @driver.find_element(:id, "fbemail") email_text.send_keys("example@email.com") end Then /^I click the submit button$/ do submit_button = @driver.find_element(:id, "submit") submit_button.click() end