The Sauce Labs Cookbook

Sauce Headless

Front End Performance Testing

Insights

External Resources

More Info


Page tree
Skip to end of metadata
Go to start of metadata

With Sauce Labs, you can run automated Appium tests against many virtual OS and platform combinations with Android emulators and iOS simulators.

See the following sections for more information:

What You'll Need

  • A Sauce Labs Account.
  • The mobile app you want to test. If you don't have one, you can use our Sauce Labs demo mobile app.
  • Ensure that your system fulfills the project support and requirements prior to uploading your apps or leveraging device emulators and simulators. Review the Automated Mobile App Testing Admin Guide for further details.

Uploading Your App to Emulators and Simulators

Before running your automated test, you will need to upload your app – an Android package file (.apk) for emulators or an iOS package file (.zip) for simulators – to a publicly available source. There are three ways you can upload your app for automated testing:

  • Sauce App Storage
  • Install from a Remote Location
  • Legacy Sauce Storage

For detailed instructions, see Application Storage.

Setting Your Test Credentials

After you've uploaded your app, you must set your Sauce Labs credentials in your test script and configure your app. How you configure your app depends on your testing use case. Authentication of the Sauce Labs platform, as well as advanced Test Configuration Options, requires the use of the W3C WebDriver-compliant sauce:options capability.

We also recommend exporting your Sauce Labs credentials to environment variables.

Configuring Appium for Emulator and Simulator Tests

Here are some tips for configuring Appium for your tests:

Setting appiumVersion

If you omit the appiumVersion in your test configuration, your test will be running with our default Appium version. We recommend that you specify one of the newer Appium versions that provides a more extended API and fixes to known bugs. 

Checking the Appium Version for Your Test

  1. Log in to Sauce Labs.
  2. Find and select the test that you ran using Appium to view the Test Details page.
  3. Click the Metadata tab.
  4. Look for the Logs row and select Appium Log.
    The first line should indicate the Appium version. For example, 2014-05-05T17:45:07.541Z - info: Welcome to Appium v1.3.6.

Setting Browser Name

When testing a native mobile app, the value for browserName is an empty string, as in caps.setCapability("browserName"""); 

Setting the Location of Your Mobile App

If the app you want to test has been uploaded to a location other than Sauce Storage, you need to specify this location for app, and make sure that this location is accessible to Sauce Labs browsers. For example, caps.setCapability("app","sauce-storage:mapp.zip");

Setting automationName for Android Apps

If you're testing a native mobile app against Android versions 4.0 - 4.1, or a hybrid mobile against Android versions 4.0 - 4.2, you need to set the capability "automationName","selendroid". These Android versions are only supported via Appium’s bundled version of Selendroid, which utilizes Instrumentation. Later versions of Android are supported via Appium’s own UIAutomator library.

Setting Appium Capabilities for Emulators and Simulators

Before you run your native/hybrid mobile app tests, you will need to configure the Appium capabilities in order to communicate with Sauce Labs virtual devices (emulators and simulators). Described below are required and optional Appium test capabilities and example scripts.

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.

Below are examples of an iPhone 8 project using iOS version 12.2:

DesiredCapabilities caps = DesiredCapabilities.iphone();
	caps.setCapability("appiumVersion", "1.13.0");
	caps.setCapability("deviceName","iPhone 8 Simulator");
	caps.setCapability("deviceOrientation", "portrait");
	caps.setCapability("platformVersion","12.2");
	caps.setCapability("platformName", "iOS");
	caps.setCapability("browserName", "");
	caps.setCapability("app", "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.zip");
caps['browserName'] = ""
caps['appiumVersion'] = "1.13.0"
caps['deviceName'] = "iPhone 8 Simulator"
caps['deviceOrientation'] = "portrait"
caps['platformVersion'] = "12.2"
caps['platformName'] = "iOS"
caps['app'] = "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.zip"
caps['browserName'] = '';
caps['appiumVersion'] = '1.13.0';
caps['deviceName'] = 'iPhone 8 Simulator';
caps['deviceOrientation'] = 'portrait';
caps['platformVersion'] = '12.2';
caps['platformName'] = 'iOS';
caps['app'] = 'https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.zip';
caps = Selenium::WebDriver::Remote::Capabilities.iphone()
caps['appiumVersion'] = '1.13.0'
caps['deviceName'] = 'iPhone 8 Simulator'
caps['deviceOrientation'] = 'portrait'
caps['platformVersion'] = '12.2'
caps['platformName'] = 'iOS'
caps['browserName'] = ''
caps['app'] = 'https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.zip'
DesiredCapabilities caps = new DesiredCapabilities();
	caps.SetCapability("appiumVersion", "1.13.0");
	caps.SetCapability("deviceName", "iPhone 8 Simulator");
	caps.SetCapability("deviceOrientation", "portrait");
	caps.SetCapability("platformVersion", "12.2");
	caps.SetCapability("platformName", "iOS");
	caps.SetCapability("browserName", "");
	caps.SetCapability("app", "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/iOS.Simulator.SauceLabs.Mobile.Sample.app.2.1.0.zip");

Below are examples of an Samsung Galaxy S9 Plus project using Android version 8.1:

DesiredCapabilities caps = DesiredCapabilities.android();
	caps.setCapability("appiumVersion", "1.9.1");
	caps.setCapability("deviceName","Samsung Galaxy S9 Plus FHD GoogleAPI Emulator");
	caps.setCapability("deviceOrientation", "portrait");
	caps.setCapability("browserName", "");
	caps.setCapability("platformVersion","8.1");
	caps.setCapability("platformName","Android");
	caps.setCapability("app", "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/Android.SauceLabs.Mobile.Sample.app.2.2.0.apk");
caps = {}
caps['appiumVersion'] = "1.9.1"
caps['deviceName'] = "Samsung Galaxy S9 Plus FHD GoogleAPI Emulator"
caps['deviceOrientation'] = "portrait"
caps['platformVersion'] = "8.1"
caps['platformName'] = "Android"
caps['app'] = "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/Android.SauceLabs.Mobile.Sample.app.2.2.0.apk"
caps = {};
caps['appiumVersion'] = '1.9.1';
caps['deviceName'] = 'Samsung Galaxy S9 Plus FHD GoogleAPI Emulator';
caps['deviceOrientation'] = 'portrait';
caps['browserName'] = '';
caps['platformVersion'] = '8.1';
caps['platformName'] = 'Android';
caps['app'] = 'https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/Android.SauceLabs.Mobile.Sample.app.2.2.0.apk';
caps = Selenium::WebDriver::Remote::Capabilities.android()
caps['appiumVersion'] = '1.9.1'
caps['deviceName'] = 'Samsung Galaxy S9 Plus FHD GoogleAPI Emulator'
caps['deviceOrientation'] = 'portrait'
caps['browserName'] = ''
caps['platformVersion'] = '8.1'
caps['platformName'] = 'Android'
caps['app'] = 'https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/Android.SauceLabs.Mobile.Sample.app.2.2.0.apk'
DesiredCapabilities caps = new DesiredCapabilities();
	caps.SetCapability("appiumVersion", "1.9.1");
	caps.SetCapability("deviceName", "Samsung Galaxy S9 Plus FHD GoogleAPI Emulator");
	caps.SetCapability("deviceOrientation", "portrait");
	caps.SetCapability("browserName", "");
	caps.SetCapability("platformVersion", "8.1");
	caps.SetCapability("platformName", "Android");
	caps.SetCapability("app", "https://github.com/saucelabs/sample-app-mobile/releases/download/2.2.0/Android.SauceLabs.Mobile.Sample.app.2.2.0.apk");

Configuring Native Mobile Apps vs. Hybrid Mobile Apps

iPhone Native App

DesiredCapabilities caps = DesiredCapabilities.iphone();
caps.setCapability("appiumVersion", "1.4.16");
caps.setCapability("deviceName","iPhone 5");
caps.setCapability("deviceOrientation", "portrait");
caps.setCapability("platformVersion","10.3");
caps.setCapability("platformName", "iOS");
caps.setCapability("browserName", "");
caps.setCapability("app","sauce-storage:mapp.zip");

iPad Native App

DesiredCapabilities caps = DesiredCapabilities.iphone();
caps.setCapability("appiumVersion", "1.4.16");
caps.setCapability("deviceName","iPad Retina");
caps.setCapability("deviceOrientation", "portrait");
caps.setCapability("platformVersion","9.2");
caps.setCapability("platformName", "iOS");
caps.setCapability("browserName", "");
caps.setCapability("app","sauce-storage:myapp.zip");

iPhone Hybrid App

DesiredCapabilities caps = DesiredCapabilities.iphone();
caps.setCapability("appiumVersion", "1.4.16");
caps.setCapability("deviceName","iPhone Retina (4-inch 64-bit)");
caps.setCapability("deviceOrientation", "portrait");
caps.setCapability("platformVersion","7.1");
caps.setCapability("platformName", "iOS");
caps.setCapability("browserName", "");
caps.setCapability("app","sauce-storage:myapp.zip");

Android Native App, Android v. 4.3

DesiredCapabilities caps = DesiredCapabilities.android();
caps.setCapability("appiumVersion", "1.4.16");
caps.setCapability("deviceName","Samsung Galaxy S4 Emulator");
caps.setCapability("deviceOrientation", "portrait");
caps.setCapability("browserName", "");
caps.setCapability("platformVersion","4.3");
caps.setCapability("platformName","Android");
caps.setCapability("app","sauce-storage:myapp.zip");

Android Hybrid App, Android v. 4.1

DesiredCapabilities caps = DesiredCapabilities.android();
caps.setCapability("appiumVersion", "1.4.16");
caps.setCapability("deviceName","Android Emulator");
caps.setCapability("deviceType","tablet");
caps.setCapability("deviceOrientation", "portrait");
caps.setCapability("browserName", "");
caps.setCapability("platformVersion","4.1");
caps.setCapability("platformName","Android");
caps.setCapability("app","sauce-storage:myapp.zip");
caps.setCapability("automationName","Selendroid");


Example Appium Test Scripts for Emulators and Simulators

These Appium scripts for iOS and Android mobile app tests on emulators and simulators can help streamline your testing process. See Sauce Labs Training on GitHub for a full repository of demo scripts and additional resources.

iOS Simulators

These Java examples employ the page object model to run tests on emulators and simulators. Feel free to clone these scripts directly from GitHub.

Page Objects

This object represents a single view/page in the sample app. Click below to see the script:

 GuineaPigPage.java

Not found

Could not read the file appium-example/src/test/java/example/ios/Pages/GuineaPigPage.java


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:

 TestBase.java

Not found

Could not read the file appium-example/src/test/java/example/ios/Tests/TestBase.java

 FollowLinkTest.java

Not found

Could not read the file appium-example/src/test/java/example/ios/Tests/FollowLinkTest.java

 TextInputTest.java

Not found

Could not read the file appium-example/src/test/java/example/ios/Tests/TextInputTest.java

These examples use the pytest test framework to run tests on emulators and simulators. Feel free to clone these scripts directly from GitHub.

Python Config

This script initializes the test fixtures, as well as the prerequisite and post-requisite test tasks.

 conftest.py

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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    driver.quit()

@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
    # this sets the result as a test attribute for Sauce Labs reporting.
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    # set an report attribute for each phase of a call, which can
    # be "setup", "call", "teardown"
    setattr(item, "rep_" + rep.when, rep)

Test Objects

These scripts represents the individual test. Click below to see the script(s):

 test_add_to_cart.py

import pytest


def test_add_to_cart(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1/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/v1/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/v1/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/v1/cart.html')
    expected = emusim_driver.find_elements_by_class_name('inventory_item_name')
    assert len(expected) == 2

 test_login_fail.py

import pytest


def test_valid_crentials_login(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1')

    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()

 test_login_success.py

import pytest


def test_valid_crentials_login(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1')

    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

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.

 Click here for the RSpec example...

Rakefile

This file initializes the test capabilities, as well as the prerequisite and post-requisite test tasks:

 Rakefile

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 app:

 app_object.rb

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:

 comment_test_spec.rb

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_helper.rb

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

 Click here for the Cucumber example...

Rakefile

This file initializes the prerequisite and postrequisite test tasks:

 Rakefile

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:

 env.rb

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:

 comment.feature

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

 email.feature

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:

 comment_steps.rb

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

 email_steps.rb

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


Android Emulators

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 app. Click below to see the script:

 GuineaPigPage.java

Not found

Could not read the file appium-example/src/test/java/example/android/Pages/GuineaPigPage.java


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:

 TestBase.java

Not found

Could not read the file appium-example/src/test/java/example/android/Tests/TestBase.java

 FollowLinkTest.java

Not found

Could not read the file appium-example/src/test/java/example/android/Tests/FollowLinkTest.java

 TextInputTest.java

Not found

Could not read the file appium-example/src/test/java/example/android/Tests/TextInputTest.java

Python Config

This script initializes the test fixtures, as well as the prerequisite and post-requisite test tasks.

 conftest.py

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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    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
    sauce_result = "failed" if request.node.rep_call.failed else "passed"
    driver.execute_script("sauce:job-result={}".format(sauce_result))
    driver.quit()

@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
    # this sets the result as a test attribute for Sauce Labs reporting.
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    # set an report attribute for each phase of a call, which can
    # be "setup", "call", "teardown"
    setattr(item, "rep_" + rep.when, rep)

Test Objects

These scripts represents the individual test. Click below to see the script(s):

 test_add_to_cart.py

import pytest


def test_add_to_cart(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1/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/v1/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/v1/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/v1/cart.html')
    expected = emusim_driver.find_elements_by_class_name('inventory_item_name')
    assert len(expected) == 2

 test_login_fail.py

import pytest


def test_valid_crentials_login(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1')

    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()

 test_login_success.py

import pytest


def test_valid_crentials_login(emusim_driver):
    emusim_driver.get('https://www.saucedemo.com/v1')

    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

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.

 Click here for the RSpec example...

Rakefile

This file initializes the test capabilities, as well as the prerequisite and postrequisite test tasks:

 Rakefile

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 app:

 app_object.rb

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:

 comment_test_spec.rb

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_helper.rb

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

 Click here for the Cucumber example...

Rakefile

This file initializes the prerequisite and postrequisite test tasks:

 Rakefile

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:

 env.rb

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:

 comment.feature

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

 email.feature

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:

 comment_steps.rb

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

 email_steps.rb

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

Best Practices and Reporting Test Results

Now that you've been able to get a test running on Sauce, check out Best Practices for Running Tests and available modifications you can make to your tests:

Additional Resources

See Sauce Labs sample test script GitHub repo for detailed, language-specific examples to get you started with automated testing on Sauce Labs.

Visit the following repositories for Appium iOS app example scripts:

Visit the following repositories for Appium Android example scripts: