Skip to main content

_ruby

A brief primer on Native App Testing In Sauce Labs

In order to test your app in Sauce Labs you will need to zip it up and serve it somehow. Here are some options on how to do that:

Once you have that you just need to set your test's desired capabilities accordingly. You can see a list of options here.

An iPhone Example

In this example we will be testing an application that has a form that takes 2 numbers, adds them together, and displays the result.

NOTE: Contrary to the Appium philosophy of not needing to recompile your app, there is one SMALL tweak you'll need to make before your app is ready for Sauce (if you care about testing against an iPhone). It's to make sure that the correct simulator gets loaded. Instructions available here.

We kick off our iPhone example by requiring our dependent libraries (selenium-webdriver to drive the browser, and rspec-expectations for handling assertions). After that, we wire up our setup, teardown, and run methods.

require 'selenium-webdriver'
require 'rspec-expectations'

def setup
caps = {
'platform' => 'Mac 10.8',
'version' => '6.1',
'device' => 'iPhone Simulator',
'app' => 'https://appium.s3.amazonaws.com/TestApp6.0.app.zip',
'name' => 'Ruby/iPhone Example for Appium'
}

@driver = Selenium::WebDriver.for(
:remote,
:url => "https://SAUCE_USERNAME:SAUCE_API_KEY@ondemand.saucelabs.com/wd/hub",
:desired_capabilities => caps)
end

def teardown
@driver.quit
end

def run
setup
yield
teardown
end

Note that in setup we configure our capabilities by setting them to a hash and storing them in a variable called caps. In it, we are specifying the platform we would like (Mac 10.8), the iOS version (6.1), the device (iPhone Simulator), and the app we would like to load (zipped up and served from AWS).

We then instantiate Selenium Remote in a @driver object; pointing it at Sauce Labs, and passing in our desired capabilities.

And in our test we wire up interaction with the app using familiar Selenium WebDriver API actions and an assertion.

run do
values = [rand(10), rand(10)]
expected_sum = values.reduce(&:+)

elements = @driver.find_elements(:tag_name, 'textField')
elements.each_with_index do |element, index|
element.send_keys values[index]
end

@driver.find_element(:tag_name, 'button').click
@driver.find_element(:tag_name, 'staticText').text.should == expected_sum.to_s
end

Expected Behavior

  • Open a job with Sauce Labs
  • Load an iPhone simulator on a Mac
  • Load the test app
  • Input two random numbers
  • Sum them together
  • Assert that they are correctly added together

NOTE: You can see the test result complete with video here.

An Android Example

In this example we will be testing a simple note-taking app.

We kick off our Android example by requiring our dependent libraries (selenium-webdriver to drive the browser, and rspec-expectations for handling assertions). After that, we wire up our setup, teardown, and run methods.

==!! Code snippet needs validation !!==

require 'selenium-webdriver'
require 'rspec-expectations'

def setup
caps = {
'platform' => 'Linux',
'version' => '4.2',
'device' => 'Android',
'app' => 'https://appium.s3.amazonaws.com/NotesList.apk',
'app-package' => 'com.example.android.notepad',
'app-activity' => '.NotesList',
'name' => 'Ruby/Android Example for Appium'
}

@driver = Selenium::WebDriver.for(
:remote,
:url => "http://SAUCE_USERNAME:SAUCE_API_KEY@ondemand.saucelabs.com:80/wd/hub",
:desired_capabilities => caps)
end

def teardown
@driver.quit
end

def run
setup
yield
teardown
end

In setup, we configure our capabilities by setting them to a hash and storing them in a variable called caps. In it we are specifying the platform (Linux), the Android version (4.2), the device (Android), and where to find the app (zipped and served from AWS). We then instantiate Selenium Remote in a @driver object; pointing it at Sauce Labs, and passing in our desired capabilities.

The additional bits of info we need to provide in caps (versus in our iPhone example) are app-package and app-activity. app-package being the package name of your app, and app-activity being the name of the activity you would like to start. app-activity gets appended to app-package and is used at Sauce run time to launch your app (e.g. com.example.android.notepad.NotesList).

And in our test we wire up interaction with the app using familiar Selenium WebDriver API actions and an assertion.

run do
@driver.find_element(:name, 'New note').click
@driver.find_element(:tag_name, 'textfield').send_keys 'This is a new note, from Ruby'
@driver.find_element(:name, 'Save').click

notes = @driver.find_elements(:tag_name, 'text')
notes[2].text.should == 'This is a new note, from Ruby'
end

Expected Behavior

  • Open a job with Sauce Labs
  • Load an Android simulator on a Linux machine
  • Load the test app
  • Create a new note
  • Fill in the new note
  • Grab the note text and assert that it's what we inputted

NOTE: You can see the test result complete with video here.

Other Helpful Tidbits

Inspecting Elements

In order to easily inspect and identify the elements in your app, you can use Appium's Inspector which comes in appium-dot-app and requires you to set up Appium locally.

NOTE: You can see a demo of it in action with an iOS app here.

Mobile Web Apps

If instead you have a mobile web app, you can launch mobile Safari by switching out the URL in app with safari, like so:

  caps = {
'platform' => 'Mac 10.8',
'version' => '6.1',
'device' => 'iPhone Simulator',
'app' => 'safari',
'name' => 'Ruby/iPhone Example for Appium',
}

But it's worth noting that Sauce Labs does not currently support the ability launch a mobile browser on Android (e.g. chrome). This functionality is, however, available when running Appium locally (as documented here).

Hybrid Apps

If you have a hybrid mobile app (e.g. an app with a native container that leverages the built in browser engine), then you should be good to go both locally and in Sauce. For details, go here.

Location Services

If you have an iOS app that deals with geolocation, then working with the Location Services dialog can be a little tricky.

You can either do a blanket dismiss (which requires some elbow grease -- see this Appium Google Groups thread for details), or capture and dismiss the dialog as it appears (using functionality found in a library like ruby_lib).

And in Sauce Labs, Location Services is disabled by default on iOS 6.1, but enabled by default on iOS 7.1. This is not configurable, but may be in the future through desired capabilities (there's [an active thread about this on Sauce's support site](http://support.saucelabs.com/entries/25117411-Location-services-enabled-by-default-on-iOS-devices, feel free to chime in!).

NOTE: Sauce Labs now supports Location Services (as noted in this recent support thread comment). You can set it in your desired capabilities with locationServicesEnabled and a true or false value.

Summary

Hopefully this tip has helped give you enough to get started with mobile testing. In order to take full advantage of what Appium has to offer, getting it set up locally is key. I encourage you to check out the installation docs (available for OS X, Linux, and Windows).

And if you're curious about other mobile automation frameworks, Alister Scott has a good breakdown of them.

Happy Testing!