Introduction to Appium

Appium is an open-source tool you can use to automate mobile native, mobile web, and mobile hybrid applications on iOS and Android platforms. “Mobile native apps” are those written using the iOS or Android SDKs. “Mobile web apps” are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome on Android). “Mobile hybrid apps” have a native wrapper around a “webview” – a native control that enables interaction with web content. Projects like Phonegap, for example, make it easy to build apps using web technologies that are then bundled into a native wrapper – these are hybrid apps.

Importantly, Appium is “cross-platform”: it allows you to write tests against multiple platforms (iOS, Android), using the same API. This enables a large or total amount of code reuse between iOS and Android testsuites.

For specific information about what it means for Appium to “support” its platforms, version, and automation modalities, please see the platform support doc.

Appium Philosophy

Appium was designed to meet mobile automation needs according to a certain philosophy. The key points of this philosophy can be stated as 4 requirements:

  1. You shouldn’t have to recompile your app or modify it in any way in order to automate it.
  2. You shouldn’t be locked into a specific language or framework to write and run your tests.
  3. A mobile automation framework shouldn’t reinvent the wheel when it comes to automation APIs.
  4. A mobile automation framework should be open source, in spirit and practice as well as in name!

Appium Design

So how does the structure of the Appium project live out this philosophy? We meet requirement #1 by using vendor-provided automation frameworks under the hood. That way, we don’t need to compile in any Appium-specific or third-party code or frameworks to your app. This means you’re testing the same app you’re shipping. The vendor-provided frameworks we use are:

We meet requirement #2 by wrapping the vendor-provided frameworks in one API, the WebDriver API. WebDriver (aka “Selenium WebDriver”) specifies a client-server protocol (known as the JSON Wire Protocol). Given this client-server architecture, a client written in any language can be used to send the appropriate HTTP requests to the server. There are already clients written in every popular programming language. This also means that you’re free to use whatever test runner and test framework you want; the client libraries are simply HTTP clients and can be mixed into your code any way you please. In other words, Appium & WebDriver clients are not technically “test frameworks” – they are “automation libraries”. You can manage your test environment any way you like!

We meet requirement #3 in the same way: WebDriver has become the de facto standard for automating web browsers, and is a W3C Working Draft. Why do something totally different for mobile? Instead we have extended the protocol with extra API methods useful for mobile automation.

It should be obvious that requirement #4 is a given – you’re reading this because Appium is open source.

Appium Concepts

Client/Server Architecture
Appium is at its heart a webserver that exposes a REST API. It receives connections from a client, listens for commands, executes those commands on a mobile device, and responds with an HTTP response representing the result of the command execution. The fact that we have a client/server architecture opens up a lot of possibilities: we can write our test code in any language that has a http client API, but it is easier to use one of the Appium client library. We can put the server on a different machine than our tests are running on. We can write test code and rely on a cloud service like Sauce Labs to receive and interpret the commands.

Session
Automation is always performed in the context of a session. Clients initiate a session with a server in ways specific to each library, but they all end up sending a POST /session request to the server, with a JSON object called the ‘desired capabilities’ object. At this point the server will start up the automation session and respond with a session ID which can be used in sending further commands.

Desired Capabilities
Desired capabilities are sets of keys and values (i.e., a map or hash) sent to the Appium server to tell the server what kind of automation session we’re interested in starting up. There are also various capabilities which can modify the behavior of the server during automation. For example, we might set the platformName capability to iOS to tell Appium that we want an iOS session, rather than an Android one. Or we might set the safariAllowPopups capability to true in order to ensure that, during a Safari automation session, we’re allowed to use JavaScript to open up new windows. See the capabilities doc for the complete list of capabilities available for Appium.

Appium Server
Appium is a server written in Node.js. It can be built and installed from source or directly from NPM.

Appium Clients
There are client libraries (in Java, Ruby, Python, PHP, JavaScript, and C#) which support Appium’s extensions to the WebDriver protocol. When using Appium, you want to use these client libraries instead of your regular WebDriver client. You can view the full list of libraries here.

Appium.app, Appium.exe
There exist GUI wrappers around the Appium server that can be downloaded. These come bundled with everything required to run the Appium server, so you don’t need to worry about Node. They also come with an Inspector, which enables you to check out the hierarchy of your app. This can come in very handy when writing tests!

Getting Started

Congratulations! You are now armed with enough knowledge to begin using Appium. Why not head back to the getting started doc for more detailed requirements and instructions?

Appium

Appium is an open source, cross-platform test automation tool for native, hybrid and mobile web apps, tested on simulators (iOS, FirefoxOS), emulators (Android), and real devices (iOS, Android, FirefoxOS).

Note: we have just recently released Appium 1.0. If you already have a bunch of Appium tests, you might want to check out the Migrating to 1.0 doc!

Supported Platforms

See the platform support doc for more detailed information.

Why Appium?

  1. You don’t have to recompile your app or modify it in any way, due to use of standard automation APIs on all platforms.
  2. You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript with Node.js (in promise, callback or generator flavors), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries.
  3. You can use any testing framework.

Investing in the WebDriver protocol means you are betting on a single, free and open protocol for testing that has become a defacto standard. Don’t lock yourself into a proprietary stack.

If you use Apple’s UIAutomation library without Appium you can only write tests using JavaScript and you can only run tests through the Instruments application. Similarly, with Google’s UiAutomator you can only write tests in Java. Appium opens up the possibility of true cross-platform native mobile automation. Finally!

I don’t get it yet…

If you’re new to Appium, or want a fuller description of what this is all about, please read our Introduction to Appium Concepts.

Requirements

Your environment needs to be setup for the particular mobile platforms that you want to run tests on. See below for particular platform requirements.

If you want to run Appium via an npm install, hack with or contribute to Appium, you will need node.js and npm 0.10 or greater (use n or brew install node to install Node.js. Make sure you have not installed Node or Appium with sudo, otherwise you’ll run into problems). We recommend the latest stable version.

To verify that all of Appium’s dependencies are met you can use appium-doctor. Run appium-doctor and supply the --ios or --android flags to verify that all of the dependencies are set up correctly. If running from source, you may have to use ./bin/appium-doctor.js or node bin/appium-doctor.js.

You also need to download the Appium client for your language so you can write tests. The Appium clients are simple extensions to the WebDriver clients. You can see the list of clients and links to download instructions at the Appium clients list.

iOS Requirements

Android Requirements

FirefoxOS Requirements

Quick Start

Kick up an Appium server, and then run a test written in your favorite WebDriver-compatible language! You can run an Appium server using node.js or using the application, see below.

Using Node.js

$ npm install -g appium $ appium &

Using the App

Writing Tests for Appium

The main guide for getting started writing and running tests is the running tests doc, which includes explanations for iOS, Android, and Android older devices. If you’re interested in testing on physical hardware, you might be interested in our real devices guide.

Essentially, we support a subset of the Selenium WebDriver JSON Wire Protocol, and extend it so that you can specify mobile-targeted desired capabilities to run your test through Appium.

You find elements by using a subset of WebDriver’s element-finding strategies. See finding elements for detailed information. We also have several extensions to the JSON Wire Protocol for automating mobile gestures like tap, flick, and swipe.

You can also automate web views in hybrid apps! See the hybrid app guide

This repository contains many examples of tests in a variety of different languages!

For the full list of Appium doc pages, visit this directory.

How It Works

Appium drives various native automation frameworks and provides an API based on Selenium’s WebDriver JSON wire protocol.

Appium drives Apple’s UIAutomation library for iOS support, which is based on Dan Cuellar’s work on iOS Auto.

Android support uses the UiAutomator framework for newer platforms and Selendroid for older Android platforms.

FirefoxOS support leverages Marionette, an automation driver that is compatible with WebDriver and is used to automate Gecko-based platforms.

Contributing

Please take a look at our contribution documentation for instructions on how to build, test and run Appium from source.

Project Credits & Inspiration

Credits

Mailing List

Announcements and debates often take place on the Discussion Group, be sure to sign up!

Troubleshooting

We put together a troubleshooting guide. Please have a look here first if you run into any problems. It contains instructions for checking a lot of common errors and how to get in touch with the community if you’re stumped.

Using Robots

Using Appium with Tapster and other robots is possible, check out the Appium Robots project!

Appium Platform Support

Appium supports a variety of platforms and testing modalities (native, hybrid, web, real devices, simulators, etc…). This document is designed to make explicit the level of support and requirements for each of these.

iOS Support

See Running on OS X: iOS for iOS requirements and setup instructions.

Android Support

See Running on OS X: Android, Running on Windows, or Running on Linux for Android requirements and setup instructions.

Appium on real iOS devices

Appium has support for real device testing.

To get started on a real device, you will need the following:

Provisioning Profile

A valid iOS Development Distribution Certificate and Provisioning Profile are necessary to test on a real device. Your app will also need to be signed. You can find information about this in the Apple documentation.

Appium will attempt to install your app using Fruitstrap, but it is often easier to pre-install your app using Xcode to ensure there are no problems.

Running your tests with Appium

Once your device and app are configured, you can run tests on that device by passing the -U or --udid flag to the server or the udid desired capability, and the bundle ID (if the app is installed on the device) or the path to the .ipa or .apk file via the --app flag or the app desired capability.

Server Arguments

For example, if you are prelaunching your app and wish for Appium to force use a specific UDID, then you may use the below command:

appium -U <udid> --app <path or bundle>

This will start Appium and have Appium use the device to test the app.

Refer to the Appium server arguments page for more detail on the arguments that you can use.

Desired Capabilities

You can launch the app on a device by including the following desired capabilities in your tests:

Refer to the Appium server capabilities page for more detail on the capabilities that you can use.

Troubleshooting ideas

  1. Make sure UDID is correct by checking it in Xcode Organizer or iTunes. It is a long string (20+ chars).
  2. Make sure that you can run your tests against the Simulator.
  3. Double check that you can invoke your automation from Instruments.
  4. Make sure Instruments in closed already.

Appium on real Android devices

Hooray! There’s nothing extra to know about testing real Android devices: it works exactly the same as testing on emulators. Make sure that your device can connect to ADB and has Developer Mode enabled.

Running Appium on Mac OS X

Appium on OS X supports iOS and Android testing.

System setup (iOS)

Testing against multiple iOS SDKs

Apple’s instruments binary, which Appium uses to launch the iOS simulator, by default uses the currently-selected Xcode, and the highest iOS SDK installed with that version of Xcode. This means that if you want to test iOS 6.1, but have iOS 7.1 installed, Appium will be forced to use the 7.1 Simulator regardless. The only way around this is to have multiple copies of Xcode installed with different sets of SDKs. You can then switch to the particular copy of Xcode that has the versions you want to test with before starting Appium.

In addition, it’s been discovered that testing against iOS 6.1 with Xcode 5 causes increased slowness and instability, so it’s recommended that for testing against iOS 6.1 and below we use Xcode 4.6.3, and for testing against iOS 7.0 we use Xcode 5.We can do this by, say, having Xcode 5 at /Applications/Xcode.app, and Xcode 4.6 and /Applications/Xcode-4.6.app. Then we use the following command:

sudo xcode-select -switch /Applications/Xcode-4.6.app/Contents/Developer/

To prepare for iOS 6.1 testing. We run it again with a different Xcode:

sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer/

To go back to iOS 7.1 testing.

System setup (Android)

Running Appium on Windows

Limitations

If you are running Appium on Windows, you can use the Appium.exe client, which will allow you to quickly launch an Appium server and use the Inspector. You will not be able to test iOS apps on a locally hosted server, because Appium relies on OS X-only libraries to support iOS testing. You can however use the Remote Server option to connect to an Appium server running on a Mac.

Setup

To get started:

  1. Install node.js (v.0.10 or greater). Use the installer from nodejs.org.
  2. Install the Android SDK. You will need to run the 'android’ tool (included in the SDK) and make sure you have an API Level 17 or greater API installed. Set ANDROID_HOME to be your Android SDK path and add the tools and platform-tools folders to your PATH variable.
  3. Install the Java JDK and set JAVA_HOME to your JDK folder.
  4. Install Apache Ant or use the one that comes with the Android Windows SDK in the eclipse\plugins folder. Be sure to add the folder containing ant to your PATH variable.
  5. Install Apache Maven and set the M2HOME and M2 environment variables. Set M2HOME to the directory maven is installed in, and set M2 to %M2HOME\bin. Add the path you used for M2 to your PATH.
  6. Install Git Be sure to install Git for windows to run in the regular command prompt.
  7. Install cURL.

Now that you’ve downloaded everything, run:

reset.bat

Running Appium

To run tests on Windows, you will need to have the Android Emulator booted or an Android Device connected that is running an AVD with API Level 17 or greater. Then run Appium on the command line using node.js:

node .

See the server documentation for all the command line arguments.

Notes

Running Appium on Linux

Limitations

If you are running Appium on Linux, you cannot use the prebuilt ’.app’, which is built for OS X only. Additionally, you will not be able to test iOS apps because Appium relies on OS X-only libraries to support iOS testing.

Setup

To get started, you’ll need to install node.js (v.0.10 or greater). Just follow the instructions for your flavor of linux.

Once you’ve got node.js installed, install the Android SDK. You will need to run the 'android’ tool (included in the SDK) and make sure you have an API Level 17 or greater API installed. You will also need Ant to build the bootstrap jar that Appium uses for testing Android.

Finally, set $ANDROID_HOME to be your Android SDK path. If you unzipped the Android SDK to /usr/local/adt/, for example, you should add this to your shell startup:

export ANDROID_HOME=“/usr/local/adt/sdk”

Now that you’re setup to run Appium, run ./reset.sh --android from your Appium checkout to install all the dependencies.

Running Appium

To run tests on Linux, you will need to have the Android Emulator booted and running an AVD with API Level 17 or greater. Then run Appium on the command line using node.js:

node .

See the server documentation for all the command line arguments.

Notes

Running Tests

Preparing your app for test (iOS)

Test apps run on the simulator have to be compiled specifically for the simulator, for example by executing the following command in the Xcode project:

> xcodebuild -sdk iphonesimulator6.0

This creates a build/Release-iphonesimulator directory in your Xcode project that contains the .app package that you’ll need to communicate with the Appium server.

If you want, you can zip up the .app directory into a .zip file! Appium will unpack it for you. Nice if you’re not using Appium locally.

Preparing your app for test (Android)

Nothing in particular needs to be done to run your .apk using Appium. If you want to zip it up, you can.

Running your test app with Appium (iOS)

The best way to see what to do currently is to look at the example tests:

Node.js | Python | PHP | Ruby | Java

Basically, first make sure Appium is running:

node .

Then script your WebDriver test, sending in the following desired capabilities:

{
    platformName: 'iOS',
    platformVersion: '7.1',
    deviceName: 'iPhone Simulator',
    app: myApp
}
{
    'platformName': 'iOS',
    'platformVersion': '7.1',
    'deviceName': 'iPhone Simulator',
    'app': myApp
}
public static $browsers = array(
    array(
        'desiredCapabilities' => array(
            'platformName' => 'iOS',
            'platformVersion' => '7.1',
            'deviceName' => 'iPhone Simulator',
            'app' => $myApp
        )
    )
);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "7.1");
capabilities.setCapability("deviceName", "iPhone Simulator");
capabilities.setCapability("app", myApp);

In this set of capabilities, myApp must be either:

Using your WebDriver library of choice, set the remote session to use these capabilities and connect to the server running at port 4723 of localhost (or whatever host and port you specified when you started Appium). You should be all set now!

Running your test app with Appium (Android)

First, make sure you have one and only one Android emulator or device connected. If you run adb devices, for example, you should see one device connected. This is the device Appium will use for tests. Of course, to have a device connected, you’ll need to have made an Android AVD (see system setup (Windows, Mac, or Linux) for more information). If the Android SDK tools are on your path, you can simply run:

emulator -avd

And wait for the android emulator to finish launching. Sometimes, for various reasons, adb gets stuck. If it’s not showing any connected devices or otherwise failing, you can restart it by running:

adb kill-server && adb devices

Now, make sure Appium is running:

node .

Then script your WebDriver test, sending in the following desired capabilities:

{
    platformName: 'Android',
    platformVersion: '4.4',
    deviceName: 'Android Emulator',
    app: myApp
}
{
    'platformName': 'Android',
    'platformVersion': '4.4',
    'deviceName': 'Android Emulator',
    'app': myApp
}
public static $browsers = array(
    array(
        'desiredCapabilities' => array(
            'platformName' => 'Android',
            'platformVersion' => '4.4',
            'deviceName' => 'Android Emulator',
            'app' => $myApp
        )
    )
);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("platformVersion", "4.4");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("app", myApp);

In this set of capabilities, myApp must be either:

Using your WebDriver library of choice, set the remote session to use these capabilities and connect to the server running at port 4723 of localhost (or whatever host and port you specified when you started Appium). You should be all set now!

Running your test app with Appium (Android devices < 4.2, and hybrid tests)

Android devices before version 4.2 (API Level 17) do not have Google’s UiAutomator framework installed. This is what Appium uses to perform the automation behaviors on the device. For earlier devices or tests of hybrid (webview-based) apps, Appium comes bundled with another automation backend called Selendroid.

To use Selendroid, all that is required is to slightly change the set of desired capabilities mentioned above, by adding the automationName capability and specifying the Selendroid automation backend.

{
    automationName: 'Selendroid',
    platformName: 'Android',
    platformVersion: '2.3',
    deviceName: 'Android Emulator',
    app: myApp
}
{
    'automationName': 'Selendroid',
    'platformName': 'Android',
    'platformVersion': '2.3',
    'deviceName': 'Android Emulator',
    'app': myApp
}
public static $browsers = array(
    array(
        'desiredCapabilities' => array(
            'automationName' => 'Selendroid',
            'platformName' => 'Android',
            'platformVersion' => '2.3',
            'deviceName' => 'Android Emulator',
            'app' => $myApp
        )
    )
);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("automationName", "Selendroid");
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("platformVersion", "2.3");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("app", myApp);

Now Appium will start up a Selendroid test session instead of the default test session. One of the downsides to using Selendroid is that its API differs sometimes significantly with Appium’s. Therefore we recommend you thoroughly read Selendroid’s documentation before writing your scripts for older devices or hybrid apps.

Intel® Hardware Accelerated Execution Manager

If you find the android emulator a slow and your system runs on an Intel® cpu, you can check out HAXM. HAXM let’s you leverage your hardware for virtualization accelerating the emulator.

Appium server arguments

Usage: node . [flags]

Server flags

All flags are optional, but some are required in conjunction with certain others.

Flag Default Description Example
--shell null Enter REPL mode
--localizable-strings-dir en.lproj IOS only: the relative path of the dir where Localizable.strings file resides --localizable-strings-dir en.lproj
--app null IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file --app /abs/path/to/my.app
--ipa null (IOS-only) abs path to compiled .ipa file --ipa /abs/path/to/my.ipa
-q, --quiet false Don’t use verbose logging output (deprecated, use –log-level instead)
-U, --udid null Unique device identifier of the connected physical device --udid 1adsf-sdfas-asdf-123sdf
-a, --address 0.0.0.0 IP Address to listen on --address 0.0.0.0
-p, --port 4723 port to listen on --port 4723
-bp, --bootstrap-port 4724 (Android-only) port to use on device to talk to Appium --bootstrap-port 4724
-k, --keep-artifacts false (IOS-only) Keep Instruments trace directories
-r, --backend-retries 3 (iOS-only) How many times to retry launching Instruments before saying it crashed or timed out --backend-retries 3
--session-override false Enables session override (clobbering)
--full-reset false (iOS) Delete the entire simulator folder. (Android) Reset app state by uninstalling app instead of clearing app data. On Android, this will also remove the app after the session is complete.
--no-reset false Don’t reset app state between sessions (IOS: don’t delete app plist files; Android: don’t uninstall app before new session)
-l, --pre-launch false Pre-launch the application before allowing the first session (Requires –app and, for Android, –app-pkg and –app-activity)
-lt, --launch-timeout 90000 (iOS-only) how long in ms to wait for Instruments to launch
-g, --log null Also send log output to this file --log /path/to/appium.log
--log-level debug log level (default: debug) --log-level debug
--log-timestamp false Show timestamps in console output
--log-no-colors false Don’t use colors in console output
-G, --webhook null Also send log output to this HTTP listener --webhook localhost:9876
--native-instruments-lib false (IOS-only) IOS has a weird built-in unavoidable delay. We patch this in appium. If you do not want it patched, pass in this flag.
--app-pkg null (Android-only) Java package of the Android app you want to run (e.g., com.example.android.myApp) --app-pkg com.example.android.myApp
--app-activity null (Android-only) Activity name for the Android activity you want to launch from your package (e.g., MainActivity) --app-activity MainActivity
--app-wait-package false (Android-only) Package name for the Android activity you want to wait for (e.g., com.example.android.myApp) --app-wait-package com.example.android.myApp
--app-wait-activity false (Android-only) Activity name for the Android activity you want to wait for (e.g., SplashActivity) --app-wait-activity SplashActivity
--android-coverage false (Android-only) Fully qualified instrumentation class. Passed to -w in adb shell am instrument -e coverage true -w --android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
--avd null (Android-only) Name of the avd to launch --avd @default
--avd-args null (Android-only) Additional emulator arguments to launch the avd --avd-args -no-snapshot-load
--device-ready-timeout 5 (Android-only) Timeout in seconds while waiting for device to become ready --device-ready-timeout 5
--intent-action android.intent.action.MAIN (Android-only) Intent action which will be used to start activity android.intent.action.VIEW
--intent-category android.intent.category.LAUNCHER (Android-only) Intent category which will be used to start activity android.intent.category.APP_CONTACTS
--intent-flags 0x10200000 (Android-only) Flags that will be used to start activity 0x10200000
--intent-args null (Android-only) Additional intent arguments that will be used to start activity. See Intent arguments --esn <EXTRA_KEY>, --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>
--safari false (IOS-Only) Use the safari app
--device-name null Name of the mobile device to use --device-name iPhone Retina (4-inch), Android Emulator
--platform-name null Name of the mobile platform: iOS, Android, or FirefoxOS --platform-name iOS
--platform-version null Version of the mobile platform --platform-version 7.1
--automation-name null Name of the automation tool: Appium or Selendroid --automation-name Appium
--browser-name null Name of the mobile browser: Safari or Chrome --browser-name Safari
--default-device, -dd false (IOS-Simulator-only) use the default simulator that instruments launches on its own
--force-iphone false (IOS-only) Use the iPhone Simulator no matter what the app wants
--force-ipad false (IOS-only) Use the iPad Simulator no matter what the app wants
--language null Language for the iOS simulator / Android Emulator --language en
--locale null Locale for the iOS simulator / Android Emulator --locale en_US
--calendar-format null (IOS-only) calendar format for the iOS simulator --calendar-format gregorian
--orientation null (IOS-only) use LANDSCAPE or PORTRAIT to initialize all requests to this orientation --orientation LANDSCAPE
--tracetemplate null (IOS-only) .tracetemplate file to use with Instruments --tracetemplate /Users/me/Automation.tracetemplate
--show-sim-log false (IOS-only) if set, the iOS simulator log will be written to the console
--nodeconfig null Configuration JSON file to register appium with selenium grid --nodeconfig /abs/path/to/nodeconfig.json
-ra, --robot-address 0.0.0.0 IP Address of robot --robot-address 0.0.0.0
-rp, --robot-port -1 port for robot --robot-port 4242
--selendroid-port 8080 Local port used for communication with Selendroid --selendroid-port 8080
--chromedriver-port 9515 Port upon which ChromeDriver will run --chromedriver-port 9515
--chromedriver-executable null ChromeDriver executable full path
--use-keystore false (Android-only) When set the keystore will be used to sign apks.
--keystore-path /Users/user/.android/debug.keystore (Android-only) Path to keystore
--keystore-password android (Android-only) Password to keystore
--key-alias androiddebugkey (Android-only) Key alias
--key-password android (Android-only) Key password
--show-config false Show info about the appium server configuration and exit
--no-perms-check false Bypass Appium’s checks to ensure we can read/write necessary files
--command-timeout 60 The default command timeout for the server to use for all sessions. Will still be overridden by newCommandTimeout cap
--keep-keychains false (iOS) Whether to keep keychains (Library/Keychains) when reset app between sessions
--strict-caps false Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device
--tmp null Absolute path to directory Appium can use to manage temporary files, like built-in iOS apps it needs to move around. On *nix/Mac defaults to /tmp, on Windows defaults to C:\Windows\Temp

Appium server capabilities

Capability Description Values
automationName Which automation engine to use Appium (default) or Selendroid
platformName Which mobile OS platform to use iOS, Android, or FirefoxOS
platformVersion Mobile OS version e.g., 7.1, 4.4
deviceName The kind of mobile device or emulator to use iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, etc…
app The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. Note that this capability is not required for Android if you specify appPackage and appActivity capabilities (see below). Incompatible with browserName. /abs/path/to/my.apk or http://myapp.com/app.ipa
browserName Name of mobile web browser to automate. Should be an empty string if automating an app instead. 'Safari’ for iOS and 'Chrome’, 'Chromium’, or 'Browser’ for Android
newCommandTimeout How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session e.g. 60
autoLaunch Whether to have Appium install and launch the app automatically. Default true true, false
language (Sim/Emu-only) Language to set for the iOS Simulator e.g. fr
locale (Sim/Emu-only) Locale to set for the iOS Simulator e.g. fr_CA
udid Unique device identifier of the connected physical device e.g. 1ae203187fc012g
orientation (Sim/Emu-only) start in a certain orientation LANDSCAPE or PORTRAIT
autoWebview Move directly into Webview context. Default false true, false

Android Only

Capability Description Values
appActivity Activity name for the Android activity you want to launch from your package MainActivity, .Settings
appPackage Java package of the Android app you want to run com.example.android.myApp, com.android.settings
appWaitActivity Activity name for the Android activity you want to wait for SplashActivity
appWaitPackage Java package of the Android app you want to wait for com.example.android.myApp, com.android.settings
deviceReadyTimeout Timeout in seconds while waiting for device to become ready 5
androidCoverage Fully qualified instrumentation class. Passed to -w in adb shell am instrument -e coverage true -w com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
enablePerformanceLogging (Chrome and webview only) Enable Chromedriver’s performance logging (default false) true, false
androidDeviceReadyTimeout Timeout in seconds used to wait for a device to become ready after booting e.g., 30
androidDeviceSocket Devtools socket name. Needed only when tested app is a Chromium embedding browser. The socket is open by the browser and Chromedriver connects to it as a devtools client. e.g., chrome_devtools_remote
avd Name of avd to launch e.g., api19
avdLaunchTimeout How long to wait in milliseconds for an avd to launch and connect to ADB (default 120000) 300000
avdReadyTimeout How long to wait in milliseconds for an avd to finish its boot animations (default 120000) 300000
avdArgs Additional emulator arguments used when launching an avd e.g., -netfast
useKeystore Use a custom keystore to sign apks, default false true or false
keystorePath Path to custom keystore, default ~/.android/debug.keystore e.g., /path/to.keystore
keystorePassword Password for custom keystore e.g., foo
keyAlias Alias for key e.g., androiddebugkey
keyPassword Password for key e.g., foo
chromedriverExecutable The absolute local path to webdriver executable (if Chromium embedder provides its own webdriver, it should be used instead of original chromedriver bundled with Appium) /abs/path/to/webdriver
specialChromedriverSessionArgs Custom arguments passed directly to chromedriver in chromeOptions capability. Passed as object which properties depend on a specific webdriver. e.g., {'androidDeviceSocket': 'opera_beta_devtools_remote',}
autoWebviewTimeout Amount of time to wait for Webview context to become active, in ms. Defaults to 2000 e.g. 4
intentAction Intent action which will be used to start activity (default android.intent.action.MAIN) e.g.android.intent.action.MAIN, android.intent.action.VIEW
intentCategory Intent category which will be used to start activity (default android.intent.category.LAUNCHER) e.g. android.intent.category.LAUNCHER, android.intent.category.APP_CONTACTS
intentFlags Flags that will be used to start activity (default 0x10200000) e.g. 0x10200000
optionalIntentArguments Additional intent arguments that will be used to start activity. See Intent arguments e.g. --esn <EXTRA_KEY>, --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>, etc.
unicodeKeyboard Enable Unicode input, default false true or false
resetKeyboard Reset keyboard to its original state, after running Unicode tests with unicodeKeyboard capability. Ignored if used alone. Default false true or false

iOS Only

Capability Description Values
calendarFormat (Sim-only) Calendar format to set for the iOS Simulator e.g. gregorian
bundleId Bundle ID of the app under test. Useful for starting an app on a real device or for using other caps which require the bundle ID during test startup e.g. io.appium.TestApp
launchTimeout Amount of time in ms to wait for instruments before assuming it hung and failing the session e.g. 20000
locationServicesEnabled (Sim-only) Force location services to be either on or off. Default is to keep current sim setting. true or false
locationServicesAuthorized (Sim-only) Set location services to be authorized or not authorized for app via plist, so that location services alert doesn’t pop up. Default is to keep current sim setting. Note that if you use this setting you MUST also use the bundleId capability to send in your app’s bundle ID. true or false
autoAcceptAlerts Accept iOS privacy access permission alerts (e.g., location, contacts, photos) automatically if they pop up. Default is false. true or false
nativeInstrumentsLib Use native intruments lib (ie disable instruments-without-delay). true or false
nativeWebTap (Sim-only) Enable “real”, non-javascript-based web taps in Safari. Default: false. Warning: depending on viewport size/ratio this might not accurately tap an element true or false
safariAllowPopups (Sim-only) Allow javascript to open new windows in Safari. Default keeps current sim setting true or false
safariIgnoreFraudWarning (Sim-only) Prevent Safari from showing a fraudulent website warning. Default keeps current sim setting. true or false
safariOpenLinksInBackground (Sim-only) Whether Safari should allow links to open in new windows. Default keeps current sim setting. true or false
keepKeyChains (Sim-only) Whether to keep keychains (Library/Keychains) when appium session is started/finished true or false
localizableStringsDir Where to look for localizable strings. Default en.lproj en.lproj
processArguments Arguments to pass to the AUT using instruments e.g., -myflag

Finding and interacting with elements

Appium supports a subset of the WebDriver locator strategies:

Appium additionally supports some of the Mobile JSON Wire Protocol locator strategies

Issues

There’s a known issue with table cell elements becoming invalidated before there’s time to interact with them. We’re working on a fix

Using The Appium Inspector To Locate Elements

Appium provides you with a neat tool that allows you to find the the elements you’re looking for without leaving the Appium app. With the Appium Inspector (the i symbol next to the start test button) you can find any element and it’s name by either clicking the element on the preview page provided, or locating it in the UI navigator.

Overview

The Appium inspector has a simple layout, complete with a UI navigator, a preview, and record and refresh buttons, and interaction tools.

Step 1

Example

After launching the Appium Inspector (you can do this by clicking the small “i” button in the top right of the app) you can locate any element in the preview. In this test, I’m looking for the id of the “show alert” button.

Step 1

To find the id of this button, I click the “show alert” button in the inspector preview. The Appium inspector then highlights the element in the UI navigator, showing me both the id and element type of the button I clicked.

Step 1

Selenium Grid

You are able to register your appium server with a local grid by using the “–nodeconfig” server parameter.

> node . -V --nodeconfig /path/to/nodeconfig.json

In the node config file you have to define the “browserName”, “version” and “platform” and based on these parameters the grid will re-direct your test to the right device. You will also need to configure you host details and the selenium grid details. For a full list of all parameters and descriptions look here

Once you start the appium server and it registers with the grid, you will see your device on the grid console page:

“http://<grid-ip-adress>:<grid-port>/grid/console”

Grid Node Configuration Example json file

{
  "capabilities":
      [
        {
          "browserName": "<e.g._iPhone5_or_iPad4>",
          "version":"<version_of_iOS_e.g._7.1>",
          "maxInstances": 1,
          "platform":"<platform_e.g._MAC_or_ANDROID>"
        }
      ],
  "configuration":
  {
    "cleanUpCycle":2000,
    "timeout":30000,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "url":"http://<host_name_appium_server_or_ip-address_appium_server>:<appium_port>/wd/hub",
    "host": <host_name_appium_server_or_ip-address_appium_server>,
    "port": <appium_port>,
    "maxSession": 1,
    "register": true,
    "registerCycle": 5000,
    "hubPort": <grid_port>,
    "hubHost": "<Grid_host_name_or_grid_ip-address>"
  }
}

Valid platforms are listed here

If url, host, and port are not given, the config will be auto updated to point to localhost:whatever-port-Appium-started-on.

Automating hybrid apps

One of the core principles of Appium is that you shouldn’t have to change your app to test it. In line with that methodology, it is possible to test hybrid web apps (e.g., the “UIWebView” elements in an iOS app) the same* way you can with Selenium for web apps. There is a bit of technical complexity required so that Appium knows whether you want to automate the native aspects of the app or the web views, but thankfully, we can stay within the WebDriver protocol for everything.

Automating hybrid iOS apps

Here are the steps required to talk to a web view in your Appium test:

  1. Navigate to a portion of your app where a web view is active
  2. Call GET session/:sessionId/contexts
  3. This returns a list of contexts we can access, like 'NATIVE_APP’ or 'WEBVIEW_1’
  4. Call POST session/:sessionId/context with the id of the context you want to access
  5. (This puts your Appium session into a mode where all commands are interpreted as being intended for automating the web view, rather than the native portion of the app. For example, if you run getElementByTagName, it will operate on the DOM of the web view, rather than return UIAElements. Of course, certain WebDriver methods only make sense in one context or another, so in the wrong context you will receive an error message).
  6. To stop automating in the web view context and go back to automating the native portion of the app, simply call context again with the native context id to leave the web frame.

Execution against a real iOS device

To interact with a web view appium establishes a connection using a remote debugger. When executing the examples below against a simulator this connection can be established directly as the simulator and the appium server are on the same machine. When executing against a real device appium is unable to access the web view directly. Therefore the connection has to be established through the USB lead. To establish this connection we use the ios-webkit-debugger-proxy.

To install the latest tagged version of the ios-webkit-debug-proxy using brew, run the following commands in the terminal:

# The first command is only required if you don't have brew installed.
> ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go/install)"
> brew update
> brew install ios-webkit-debug-proxy

You can also install the latest proxy by cloning it from git and installing it yourself:

# Please be aware that this will install the proxy with the latest code (and not a tagged version).
> git clone https://github.com/google/ios-webkit-debug-proxy.git
> cd ios-webkit-debug-proxy
> ./autogen.sh
> ./configure
> make
> sudo make install

Once installed you can start the proxy with the following command:

# Change the udid to be the udid of the attached device and make sure to set the port to 27753
# as that is the port the remote-debugger uses.
> ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d

NOTE: the proxy requires the “web inspector” to be turned on to allow a connection to be established. Turn it on by going to settings > safari > advanced. Please be aware that the web inspector was added as part of iOS 6 and was not available previously.

// assuming we have an initialized `driver` object working on the UICatalog app
return driver
  .elementByName('Web, Use of UIWebView') // find button to nav to view
    .click() // nav to UIWebView
  .contexts().then(function (contexts) { // get list of available views
    return driver.context(contexts[1]); // choose what is probably the webview context
  }).elementsByCss('.some-class').then(function (els) { // get webpage elements by css
    els.length.should.be.above(0); // there should be some!
    return els[0];
  }).text() // get text of the first element
    .should.become("My very own text") // it should be extremely personal and awesome
  .context('NATIVE_APP') // leave webview context
  // do more native stuff here if we want
  .quit() // stop webdrivage
  .done(); // end promise chain (may not be needed)
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability("platformVersion", "7.1");
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("deviceName", "iPhone Simulator");
capabilities.SetCapability("app", app);

driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

WebElement button = driver.findElement(By.id("buttonStartWebview"));
button.click();
Thread.sleep(6000);
Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
  System.out.println(contextName);
  if (contextName.contains("WEBVIEW")){
    driver.context(contextName);
  }
}
WebElement inputField = driver.findElement(By.id("name_input"));
inputField.sendKeys("Some name");
TEST_NAME = "Example Ruby Test"
SERVER_URL = "http://127.0.0.1:4723/wd/hub"
APP_PATH = "https://dl.dropboxusercontent.com/s/123456789101112/ts_ios.zip"
capabilities =
    {
      'browserName' => 'iOS 6.0',
      'platform' => 'Mac 10.8',
      'device' => 'iPhone Simulator',
      'app' => APP_PATH,
      'name' => TEST_NAME
    }
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)

# I switch to the last window because its always the webview in our case, in other cases you may need to specify a window number
# View the appium logs while running @driver.window_handles to figure out which window is the one you want and find the associated number
# Then switch to it using @driver.switch_to_window("6")

Given(/^I switch to webview$/) do
  webview = @driver.contexts.last
  @driver.switch_to.context(webview)
end

Given(/^I switch out of webview$/) do
  @driver.switch_to(@driver.contexts.first)
end

# Now you can use CSS to select an element inside your webview

And(/^I click a webview button $/) do
  @driver.find_element(:css, ".green_button").click
end
APP_PATH = "https://dl.dropboxusercontent.com/s/123456789101112/ts_ios.zip"
capabilities = {
    'browserName': 'iOS 6.0',
    'platform': 'Mac 10.8',
    'device': 'iPhone Simulator',
    'app': APP_PATH,
    'name': "Example Python Test"
}
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)

# switch to webview
webview = driver.contexts.last
driver.switch_to.context(webview)

# do some webby stuff
driver.find_element(:css, ".green_button").click

# switch back to native view
driver.switch_to(driver.contexts.first)

# Now you can use CSS to select an element inside your webview
APP_PATH = 'https://dl.dropboxusercontent.com/s/123456789101112/ts_ios.zip'
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
{
    public static $browsers = array(
        array(
            'desiredCapabilities' => array(
                'platformName' => 'iOS',
                'platformVersion' => '7.1',
                'deviceName' => 'iPhone Simulator',
                'app' => $myApp,
                'name' => 'Example Hybrid PHP Test'
            )
        )
    );

    public function testThings()
    {
        $expected_contexts = array(
            0 => 'NATIVE_APP',
            1 => 'WEBVIEW_1'
        );

        $contexts = $this->contexts();
        $this->assertEquals($expected_contexts, $contexts);

        $this->context('WEBVIEW_1');
        $context = $this->context();
        $this->assertEquals('WEBVIEW_1', $context);

        // do webby stuff

        $this->context('NATIVE_APP');

        // do mobile stuff
    }
}

Automating hybrid Android apps

Appium comes with built-in hybrid support via Chromedriver. Appium also uses Selendroid under the hood for webview support on devices older than 4.4. (In that case, you’ll want to specify "automationName": "selendroid" as a desired capability). Then follow all the same steps as above for iOS, i.e., switching contexts, etc…

Make sure setWebContentsDebuggingEnabled is set to true as described in the remote debugging docs.

// assuming we have an initialized `driver` object working on a hybrid app
return driver
  .context("WEBVIEW") // choose the only available view
  .elementsByCss('.some-class').then(function (els) { // get webpage elements by css
    els.length.should.be.above(0); // there should be some!
    return els[0];
  }).text() // get text of the first element
    .should.become("My very own text") // it should be extremely personal and awesome
  .context("NATIVE_APP") // leave webview context
  // do more native stuff here if we want
  .quit() // stop webdrivage
  .done(); // end promise chain (may not be needed)
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability("automationName","Selendroid");
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("app", myApp);
driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

WebElement button = driver.findElement(By.id("buttonStartWebview"));
button.click();
Thread.sleep(6000);
Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
  System.out.println(contextName);
  if (contextName.contains("WEBVIEW")){
    driver.context(contextName);
  }
}
WebElement inputField = driver.findElement(By.id("name_input"));
inputField.sendKeys("Some name");
# assuming we have an initialized `driver` object working on a hybrid app
driver.switch_to.context("WEBVIEW")
elements = driver.find_elements_by_css_selector('.some-class')
assertLess(0, len(elements))
assertEqual('My very own text', elements[0].text)

driver.switch_to.context("NATIVE_APP")
driver.quit()

Deploying your iOS app to your device

To prepare for your Appium tests to run on a real device, you will need to:

  1. Build your app with specific device-targeted parameters
  2. Use fruitstrap, a 3rd-party tool, to deploy this build to your device

Xcodebuild with parameters:

A newer xcodebuild now allows settings to be specified. Taken from developer.apple.com:

xcodebuild [-project projectname] [-target targetname ...]
             [-configuration configurationname] [-sdk [sdkfullpath | sdkname]]
             [buildaction ...] [setting=value ...] [-userdefault=value ...]

This is a resource to explore the available settings

CODE_SIGN_IDENTITY (Code Signing Identity)
    Description: Identifier. Specifies the name of a code signing identity.
    Example value: iPhone Developer

PROVISIONING_PROFILE is missing from the index of available commands, but may be necessary.

Specify “CODE_SIGN_IDENTITY” & “PROVISIONING_PROFILE” settings in the xcodebuild command:

xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"

On success, the app will be built to your <app_dir>/build/<configuration>-iphoneos/<app_name>.app

Deploy using Fruitstrap

Go clone a forked version of fruitstrap as the ghughes version is no longer maintained. Success has been confirmed with the unprompted fork, but others are reportedly functional.

Once cloned, run make fruitstrap Now, copy the resulting fruitstrap executable to your app’s project or a parent directory.

Execute fruitstrap after a clean build by running (commands available depend on your fork of fruitstrap):

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID>

If you are aiming to use continuous integration in this setup, you may find it useful to want to log the output of fruitstrap to both command line and log, like so:

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID> 2>&1 | tee fruit.out

Since fruitstrap will need to be killed before the node server can be launched, an option is to scan the output of the fruitstrap launch for some telling sign that the app has completed launching. This may prove useful if you are doing this via a Rakefile and a go_device.sh script:

bundle exec rake ci:fruit_deploy_app | while read line ; do 
   echo "$line" | grep "text to identify successful launch" 
   if [ $? = 0 ] 
   then 
   # Actions 
       echo "App finished launching: $line" 
       sleep 5 
       kill -9 `ps -aef | grep fruitstrap | grep -v grep | awk '{print $2}'` 
   fi
 done

Once fruitstrap is killed, node server can be launched and Appium tests can run!

Next: Running Appium on Real Devices

Automating mobile web apps

If you’re interested in automating your web app in Mobile Safari on iOS or Chrome on Android, Appium can help you. Basically, you write a normal WebDriver test, and use Appium as the Selenium server with a special set of desired capabilities.

Mobile Safari on Simulator

First of all, make sure developer mode is turned on in your Safari preferences so that the remote debugger port is open.

If you are using the simulator or a real device, you MUST run Safari before attempting to use Appium.

Then, use desired capabilities like these to run your test in mobile Safari:

{
  platformName: 'iOS'
  , platformVersion: '7.1'
  , browserName: 'Safari'
  , deviceName: 'iPhone Simulator'
}
{
  'platformName': 'iOS',
  'platformVersion': '7.1',
  'browserName': 'Safari',
  'deviceName': 'iPhone Simulator'
}
public static $browsers = array(
    array(
        'desiredCapabilities' => array(
            'platformName' => 'iOS',
            'platformVersion' => '7.1',
            'browserName' => 'Safari',
            'deviceName' => 'iPhone Simulator'
        )
    )
);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "7.1");
capabilities.setCapability("browserName", "Safari");
capabilities.setCapability("deviceName", "iPhone Simulator");

Mobile Safari on a Real iOS Device

To be able to run your tests against mobile Safari we use the SafariLauncher App to launch Safari. Once Safari has been launched the Remote Debugger automatically connects using the ios-webkit-webkit-proxy.

NOTE: There is currently a bug in the ios-webkit-debug-proxy. You have to trust the machine before you can run the ios-webkit-debug-proxy against your iOS device.

Setup

Before you can run your tests against Safari on a real device you will need to: * Have the ios-webkit-debug-proxy installed, running and listening on port 27753 (see the hybrid docs for instructions) * Turn on web inspector on iOS device (settings > safari > advanced, only for iOS 6.0 and up) * Create a provisioning profile that can be used to deploy the SafariLauncherApp.

To create a profile for the launcher go into the Apple Developers Member Center and: * Step 1: Create a new App Id and select the WildCard App ID option and set it to “” * **Step 2:* Create a new Development Profile and for App Id select the one created in step 1. * Step 3: Select your certificate(s) and device(s) and click next. * Step 4: Set the profile name and generate the profile. * Step 5: Download the profile and open it with a text editor. * Step 6: Search for the UUID and the string for it is your identity code.

Now that you have a profile open a terminal and run the following commands:

$ git clone https://github.com/appium/appium.git
$ cd appium

# Option 1: You dont define any parameters and it will set the code signing identity to 'iPhone Developer'
$ ./reset.sh --ios --real-safari

# Option 2: You define the code signing identity and allow xcode to select the profile identity code (if it can).
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>'

# Option 3: You define both the code signing identity and profile identity code.
$ ./reset.sh --ios --real-safari --code-sign '<code signing idendity>' --profile '<retrieved profile identity code>'

# Once successfully configured and with the safari launcher built, start the server as per usual
$ node /lib/server/main.js -U <UDID>

Running your test

To configure you test to run against safari simply set the “browserName” to be “Safari”.

Java Example

//setup the web driver and launch the webview app.
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability("browserName", "Safari");
URL url = new URL("http://127.0.0.1:4723/wd/hub");
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(url, desiredCapabilities);

// Navigate to the page and interact with the elements on the guinea-pig page using id.
remoteWebDriver.get("http://saucelabs.com/test/guinea-pig");
WebElement div = remoteWebDriver.findElement(By.id("i_am_an_id"));
Assert.assertEquals("I am a div", div.getText()); //check the text retrieved matches expected value
remoteWebDriver.findElement(By.id("comments")).sendKeys("My comment"); //populate the comments field by id.

//close the app.
remoteWebDriver.quit();

Python Example

# setup the web driver and launch the webview app.
capabilities = { 'browserName': 'Safari' }
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)

# Navigate to the page and interact with the elements on the guinea-pig page using id.
driver.get('http://saucelabs.com/test/guinea-pig');
div = driver.find_element_by_id('i_am_an_id')
# check the text retrieved matches expected value
assertEqual('I am a div', div.text)

# populate the comments field by id
driver.find_element_by_id('comments').send_keys('My comment')

# close the driver
driver.quit()
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
{
    public static $browsers = array(
        array(
            'desiredCapabilities' => array(
                'platformName' => 'iOS',
                'platformVersion' => '7.1',
                'browserName' => 'Safari',
                'deviceName' => 'iPhone Simulator'
            )
        )
    );

    public function testThings()
    {
        $this->get('http://saucelabs.com/test/guinea-pig');

        $div = $this->byId('i_am_an_id');
        $this->assertEquals('I am a div', $div->text());

        $this->byId('comments')->sendKeys('My comment');
    }
}

Mobile Chrome on Emulator or Real Device

Pre-requisites:

Then, use desired capabilities like these to run your test in Chrome:

{
  platformName: 'Android'
  , platformVersion: '4.4'
  , deviceName: 'Android Emulator'
  , browserName: 'Chrome'
};
{
  'platformName': 'Android',
  'platformVersion': '4.4',
  'deviceName': 'Android Emulator',
  'browserName': 'Chrome'
}
public static $browsers = array(
    array(
        'desiredCapabilities' => array(
            'platformName' => 'Android',
            'platformVersion' => '4.4',
            'browserName' => 'Chrome',
            'deviceName' => 'Android Emulator'
        )
    )
);
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("platformVersion", "4.4");
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("browserName", "Chrome");

Note that on 4.4+ devices, you can also use the 'Browser’ browserName cap to automate the built-in browser. On all devices you can use the 'Chromium’ browserName cap to automate a build of Chromium.

Automating mobile gestures

While the Selenium WebDriver spec has support for certain kinds of mobile interaction, its parameters are not always easily mappable to the functionality that the underlying device automation (like UIAutomation in the case of iOS) provides. To that end, Appium implements the new TouchAction / MultiAction API defined in the newest version of the spec (https://w3c.github.io/webdriver/webdriver-spec.html#multiactions-1). Note that this is different from the earlier version of the TouchAction API in the original JSON Wire Protocol.

These APIs allow you to build up arbitrary gestures with multiple actuators. Please see the Appium client docs for your language in order to find examples of using this API.

An Overview of the TouchAction / MultiAction API

TouchAction

TouchAction objects contain a chain of events.

In all the appium client libraries, touch objects are created and are given a chain of events.

The available events from the spec are: * press * release * moveTo * tap * wait * longPress * cancel * perform

Here’s an example of creating an action in pseudocode:

TouchAction().press(el0).moveTo(el1).release()

The above simulates a user pressing down on an element, sliding their finger to another position, and removing their finger from the screen.

Appium performs the events in sequence. You can add a wait event to control the timing of the gesture.

The appium client libraries have different ways of implementing this, for example: you can pass in coordinates or an element to a moveTo event. Passing both coordinates and an element will treat the coordinates as relative to the elements position, rather than absolute.

Calling the perform event sends the entire sequence of events to appium, and the touch gesture is run on your device.

Appium clients also allow one to directly execute a TouchAction through the driver object, rather than calling the perform event on the TouchAction object.

In pseudocode, both of the following are equivalent:

TouchAction().tap(el).perform()

driver.perform(TouchAction().tap(el))

MultiTouch

MultiTouch objects are collections of TouchActions.

MultiTouch gestures only have two methods, add, and perform.

add is used to add another TouchAction to this MultiTouch.

When perform is called, all the TouchActions which were added to the MultiTouch are sent to appium and performed as if they happened at the same time. Appium first performs the first event of all TouchActions together, then the second, etc.

Pseudocode example of tapping with two fingers:

action0 = TouchAction().tap(el)
action1 = TouchAction().tap(el)
MultiAction().add(action0).add(action1).perform()

Bugs and Workarounds

An unfortunate bug exists in the iOS 7.x Simulator where ScrollViews don’t recognize gestures initiated by UIAutomation (which Appium uses under the hood for iOS). To work around this, we have provided access to a different function, scroll, which in many cases allows you to do what you wanted to do with a ScrollView, namely, scroll it!

Scrolling

To allow access to this special feature, we override the execute or executeScript methods in the driver, and prefix the command with mobile:. See examples below:

// scroll the view down
driver.execute("mobile: scroll", [{direction: 'down'}])
// continue testing
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", "down");
scrollObject.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: scroll", scrollObject);

Automating Sliders

iOS

// slider values can be string representations of numbers between 0 and 1
// e.g., "0.1" is 10%, "1.0" is 100%
WebElement slider =  wd.findElement(By.xpath("//window[1]/slider[1]"));
slider.sendKeys("0.1");

Android

The best way to interact with the slider on Android is with TouchActions.

Troubleshooting Appium

Here’s what to do if you’re experiencing problems, before you submit a ticket to github or write to the appium-discuss mailing list.

General

If you’re running Appium.app

If you’re running Appium from source

Android

IOS

Webview/Hybrid/Safari app support

FirefoxOS

Let the community know

Once you’ve tried the above steps and your issue still isn’t resolved, here’s what you can do:

If you’ve found what you believe is a bug, go straight to the issue tracker and submit an issue describing the bug and a repro case.

If you’re having trouble getting Appium working and the error messages Appium provides are not clear, join the mailing list and send a message. Please include the following:

Known Issues

Specific Errors

Action Error Resolution
Running reset.sh xcodebuild: error: SDK "iphonesimulator6.1” cannot be located Install the iPhone 6.1 SDK or build the test apps with a separate SDK, e.g., grunt buildApp:UICatalog:iphonesimulator5.1
Running reset.sh Warning: Task “setGitRev” not found. Use –force to continue. Update the submodules with git submodule update --init and run reset.sh again

Migrating your tests from Appium 0.18.x to Appium 1.x

Appium 1.0 has removed a number of deprecated features from the previous versions. This guide will help you know what needs to change in your test suite to take advantage of Appium 1.0.

New client libraries

The biggest thing you need to worry about is using the new Appium client libraries instead of the vanilla WebDriver clients you are currently using. Visit the Appium client list to find the client for your language. Downloads and instructions for integrating into your code are available on the individual client websites.

Ultimately, you’ll be doing something like (to use Python as an example):

from appium import webdriver

Instead of:

from selenium import webdriver

New desired capabilities

The following capabilities are no longer used:

Instead, use these capabilities:

The app capability remains the same, but now refers exclusively to non-browser apps. To use browsers like Safari or Chrome, use the standard browserName cap. This means that app and browserName are exclusive.

We have also standardized on camelCase for Appium server caps. That means caps like app-package or app-wait-activity are now appPackage and appWaitActivity respectively. Of course, since Android app package and activity are now auto-detected, you should be able to omit them entirely in most cases.

New locator strategies

We’ve removed the following locator strategies:

We have now added the accessibility_id strategy to do what name used to do. The specifics will be relative to your Appium client.

tag name has been replaced by class name. So to find an element by its UI type, use the class name locator strategy for your client.

Note about class name and xpath strategies: these now require the fully-qualified class name for your element. This means that if you had an xpath selector that looked like this:

//table/cell/button

It would now need to be:

//UIATableView/UIATableCell/UIAButton

(And likewise for Android: button now needs to be android.widget.Button)

We’ve also added the following locator strategies:

Refer to your client for ways to use these new locator strategies.

XML, not JSON

App source methods, which previously returned JSON, now return XML, so if you have code that relies on parsing the app source, it will need to be updated.

Hybrid support through context, not window

Hybrid apps were previously supported by switching between “windows” using

Now Appium supports the more conceptually consistent concept of “context”. To get all of the available contexts, or the particular context the application is is, you use

driver.contexts
current = driver.context
driver.contexts().then(function (contexts) { /*...*/ })

And to switch between them, you use

driver.switch_to.context("WEBVIEW")
driver.currentContext().then(function (context) { /*...*/ })

No more execute_script("mobile: xxx")

All the mobile: methods have been removed, and have been replaced by native methods in the Appium client libraries. This means that a method call like driver.execute("mobile: lock", [5]) will now look something more like driver.lock(5) (where lock has been turned into a native client method). Of course, the details on calling these methods will differ by client.

Of particular note, the gesture methods have been replaced by the new TouchAction / MultiAction API which allows for a much more powerful and general way of putting gestural automation together. Refer to your Appium client for usage notes on TouchAction / MultiAction.

And that’s it! Happy migrating!

Appium Client Libraries

Appium has libraries for:

Language Source
Ruby GitHub
Python GitHub
Java GitHub
JavaScript GitHub
PHP GitHub
C# GitHub

Note that some methods such as endTestCoverage() and complexFind() are not generally useful. Proper coverage support will be added once this issue is resolved. complexFind() will be removed once this issue is resolved. If you want to use them anyway, consult the documentation for the bindings on GitHub.

Lock

Lock the screen.

lock 5
driver.lock(5)
driver.lockScreen(3);
driver.lock(3)
$this->lock(3);
driver.LockDevice(3);

Background app

Send the currently active app to the background.

background_app 5
driver.background_app(5)
driver.runAppInBackground(5);
driver.backgroundApp(5)
$this->backgroundApp(5);
driver.BackgroundApp(5);

Hide Keyboard

Hide the keyboard.

hide_keyboard
driver.hide_keyboard()
driver.hideKeyboard();
driver.hideKeyboard()
$this->hideKeyboard();
$this->hideKeyboard(array('strategy' => 'pressKey', 'key' => 'Done'));
driver.HideKeyboard("Done");

Is installed

Check if an app is installed

is_installed? "com.example.android.apis"
driver.is_app_installed('com.example.android.apis')
driver.isAppInstalled("com.example.android.apis")
driver.isAppInstalled("com.example.android.apis")
  .then(function (isAppInstalled) { /*...*/ })
$this->isAppInstalled('com.example.android.apis');
driver.IsAppInstalled("com.example.android.apis-");

Install App

Install an app to the device.

install 'path/to/my.apk'
driver.install_app('path/to/my.apk')
driver.installApp("path/to/my.apk")
driver.installApp("path/to/my.apk")
$this->installApp('path/to/my.apk');
driver.InstallApp("path/to/my.apk");

Remove App

Remove an app from the device.

remove 'com.example.android.apis'
driver.remove_app('com.example.android.apis')
driver.removeApp("com.example.android.apis")
driver.removeApp("com.example.android.apis")
$this->removeApp('com.example.android.apis');
driver.RemoveApp("com.example.android.apis");

Shake

Simulate the device shaking.

shake
driver.shake()
driver.shake()
driver.shake()
$this->shake();
driver.ShakeDevice();

Close app

Close the app

close_app
driver.close_app();
driver.closeApp()
driver.closeApp()
$this->closeApp();
driver.CloseApp();

Launch

Launch the app

launch
driver.launch_app()
driver.launchApp()
driver.launchApp()
$this->launchApp();
driver.LaunchApp();

Reset

Reset the app.

reset
driver.reset()
driver.resetApp()
driver.resetApp()
$this->reset();
driver.ResetApp();

Available Contexts

List all available contexts

context_array = available_contexts
driver.contexts
driver.getContextHandles()
driver.contexts().then(function (contexts) { /*...*/ })
$this->contexts();
driver.GetContexts()

Current context

List the current context

context = current_context
driver.current_context
driver.getContext()
driver.currentContext().then(function (context) { /*...*/ })
$this->context();
driver.GetContext()

Switch to default context

Change the context to the default.

switch_to_default_context
driver.switch_to.context(None)
driver.context();
driver.context()
$this->context(NULL);
driver.SetContext();

App Strings

Get the app’s strings.

strings = app_strings
driver.app_strings
driver.getAppString();
driver.getAppStrings().then(function (appStrings) { /*...*/ })
$this->appStrings();
$this->appStrings('ru');
driver.GetAppStrings();

Key Event

Send a key event to the device.

key_event 176
driver.keyevent(176)
driver.sendKeyEvent(AndroidKeyCode.HOME);
driver.deviceKeyEvent(wd.SPECIAL_KEYS.Home)
$this->keyEvent('176');
driver.KeyEvent("176");

Current Activity

Android only. Get the current activity.

current_activity
driver.current_activity
driver.currentActivity();
driver.getCurrentActivity().then(function (activity) { /*...*/ })
$this->currentActivity();
driver.GetCurrentActivity();

TouchAction / MultiTouchAction

An API for generating touch actions. This section of the documentation will be expanded upon soon.

touch_action = Appium::TouchAction.new
element  = find_element :name, 'Buttons, Various uses of UIButton'
touch_action.press(element: element, x: 10, y: 10).perform
action = TouchAction(driver)
action.press(element=el, x=10, y=10).release().perform()
TouchAction action = new TouchAction(driver)
.press(mapview, 10, 10)
.release().
perform();
var action = new wd.TouchAction(driver);
action
  .tap({el: el, x: 10, y: 10})
  .release();
return action.perform(); // returns a promise
$action = $this->initiateTouchAction();
               ->press(array('element' => $el))
               ->release()
               ->perform();

$action1 = $this->initiateTouchAction();
$action1->press(array('element' => $els[0]))
        ->moveTo(array('x' => 10, 'y' => 0))
        ->moveTo(array('x' => 10, 'y' => -75))
        ->moveTo(array('x' => 10, 'y' => -600))
        ->release();

$action2 = $this->initiateTouchAction();
$action2->press(array('element' => $els[1]))
        ->moveTo(array('x' => 10, 'y' => 10))
        ->moveTo(array('x' => 10, 'y' => -300))
        ->moveTo(array('x' => 10, 'y' => -600))
        ->release();

$multiAction = $this->initiateMultiAction();
$multiAction->add($action1);
$multiAction->add($action2);
$multiAction->perform();
ITouchAction action = new TouchAction(driver);
action.Press(el, 10, 10).Release();
action.Perform ();

Swipe

Simulate a user swipe.

swipe start_x: 75, start_y: 500, end_x: 75, end_y: 0, duration: 0.8
driver.swipe(75, 500, 75, 0, 0.8)
driver.swipe(startx=75, starty=500, endx=75, endy=0, duration=800)
function swipe(opts) {
  var action = new wd.TouchAction(this);
  action
    .press({x: opts.startX, y: opts.startY})
    .wait(opts.duration)
    .moveTo({x: opts.endX, y: opts.endY})
    .release();
  return action.perform();
}
wd.addPromiseChainMethod('swipe', swipe);
// ...
return driver.swipe({ startX: 75, startY: 500,
  endX: 75,  endY: 0, duration: 800 });
$this->swipe(75, 500, 75, 0, 800);
todo: c#

Pinch

Pinch the screen.

pinch 75
driver.pinch(element=el)
driver.pinch(element);
function pinch(el) {
  return Q.all([
    el.getSize(),
    el.getLocation(),
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2, 
      y: loc.y + size.height / 2
    };
    var a1 = new wd.TouchAction(this);
    a1.press({el: el, x: center.x, y:center.y - 100}).moveTo({el: el}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el, x: center.x, y: center.y + 100}).moveTo({el: el}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
  }.bind(this));
}; 
wd.addPromiseChainMethod('pinch', pinch);
wd.addElementPromiseChainMethod('pinch', function() { 
  return this.browser.pinch(this); 
});
// ...
return driver.pinch(el);
// ...
return el.pinch();
$this->pinch($el);
driver.Pinch(25, 25)

Zoom

Zoom the screen.

zoom 200
driver.zoom(element=el)
driver.zoom(element);
function zoom(el) {
  return Q.all([
    this.getWindowSize(),
    this.getLocation(el),
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2, 
      y: loc.y + size.height / 2
    };
    var a1 = new wd.TouchAction(this);
    a1.press({el: el}).moveTo({el: el, x: center.x, y: center.y - 100}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el}).moveTo({el: el, x: center.x, y: center.y + 100}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
  }.bind(this));
}; 
wd.addPromiseChainMethod('zoom', zoom);
wd.addElementPromiseChainMethod('zoom', function() { 
  return this.browser.zoom(this); 
});
// ...
return driver.zoom(el);
// ...
return el.zoom();
$this->zoom($el);
driver.Zoom(100, 200);

Scroll To

Scroll to an element.

element = find_element :name, 'Element Name'
execute_script "mobile: scrollTo", :element => element.ref
todo: python
WebElement element = driver.findElement(By.name("Element Name"));
HashMap<String, String> arguments = new HashMap<String, String>();
arguments.put("element", element.getId());
(JavascriptExecutor)driver.executeScript("mobile: scrollTo", arguments);
return driver.elementByName().then(function (el) {
  return driver.execute('mobile: scrollTo', {element: el.value});
});
$els = $this->elements($this->using('class name')->value('android.widget.TextView'));
$this->scroll($els[count($els) - 1], $els[0]);
todo: csharp

Pull file

Pulls a file from the device.

pull_file 'Library/AddressBook/AddressBook.sqlitedb'
driver.pull_file('Library/AddressBook/AddressBook.sqlitedb')
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb");
driver.pullFile("Library/AddressBook/AddressBook.sqlitedb")
  .then(function (base64File) { /*...*/ })
$this->pullFile('Library/AddressBook/AddressBook.sqlitedb');
driver.PullFile("Library/AddressBook/AddressBook.sqlitedb");

Push File

Pushes a file to the device.

data = "some data for the file"
path = "/data/local/tmp/file.txt"
push_file path, data
data = "some data for the file"
path = "/data/local/tmp/file.txt"
driver.push_file(path, data.encode('base64'))
byte[] data = Base64.encodeBase64("some data for the file".getBytes());
String path = "/data/local/tmp/file.txt";
driver.pushFile(path, data)
driver.pushFile(path, data)
$path = 'data/local/tmp/test_push_file.txt';
$data = 'This is the contents of the file to push to the device.';
$this->pushFile($path, base64_encode($data));
driver.PushFile("/data/local/tmp/file.txt", "some data for the file");

Appium Desktop Apps

Appium’s desktop app supports OS X and Windows.

List of client libraries with Appium server support

Please see each library for installation instructions.

A Windows GUI for Appium

If you are new to Appium then please see the Getting started guide for more information about the project.

Pre-req: * Need .NET Framework 4.5 redistributable libraries

To install:

  1. Download the latest version from Appium.io.
  2. Extract the ZIP file.
  3. Launch appium.exe.

To update Appium Server manually:

  1. Close appium-dot-exe
  2. Go appium-dot-exe main directory
  3. Delete node_modules folder
  4. Delete node.exe file
  5. Launch appium.exe
  6. Download should occur automatically

Parameter Guide

Main Window

Appium Main Window

Android Settings

Preference Guide

Preferences can be accessed by clicking on the appropriate button in the main window.

Appium Preferences

General Settings

Developer Settings

Inspector / Recorder

Inspector can be accessed by clicking the magnifying glass next to the launch button once the Appium server has launched. Appium must be running with an app open for inspector to work. Otherwise, it will not work.

The Inspector can be use to connect to an external Appium server. This can be specified in the General Settings.

Appium Inspector

An OS X GUI for Appium

Build Status

If you are new to Appium then please see the Getting started guide for more information about the project.

To install:

  1. Download the latest version from Appium.io.
  2. Mount the disk image.
  3. Drag Appium.app to your Applications folder.

Build with XCode

Install CocoaPods:

  1. Open Termianl
  2. sudo gem install cocoapods
  3. pod setup
  4. cd appium-dot-app
  5. pod install

To Open in XCode:

open the appium-dot-app/Appium.xcworkspace project file

Parameter Guide

Main Window

Appium Main Window

Android Settings

iOS Settings

Preference Guide

Preferences can be accessed by clicking on the appropriate button in the main window.

Appium Preferences

General Settings

Developer Settings

Inspector / Recorder

Inspector can be accessed by clicking the magnifying glass next to the launch button once the Appium server has launched. Appium must be running with an app open for inspector to work. Otherwise, it will not work. Appium Inspector

Inspector Window

Action Palette

The action pallete contains buttons that will trigger actions on the device under test. You can try out actions here or enter them to be recorded.

Recorder Drawer

The recorder draw contains the code generated by recorded actions you’ve performed while recording is enabled.

iOS Predicate

It is worth looking at ’-ios uiautomation’ search strategy with Predicates. UIAutomation JavaScript API has following methods which can are very useful.

(UIAElement) UIAElementArray.firstWithPredicate(PredicateString predicateString)
(UIAElementArray) UIAElementArray.withPredicate(PredicateString predicateString)

Native JS search strategy (powered by Apple) provides much more flexibility and is like Xpath. Predicates can be used to restrict an elements set to select only those ones for which some condition is true.

For example:

appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")")

- will select only those UIACollectionCell elements that have visible UIAStaticText child elements, and themselves are childs of 1st UIACollectionView element that should be located under the main app window. Here staticTexts() and isVisible() are methods available in UIAElementArray and UIAElement classes respectively. Note that UIAElementArray numbering begins with 0 unlike Xpath where indexes counting starts from 1

Here’s a list of available Predicates (mostly taken from Predicates Programming Guide)

Basic Comparisons

= , == - The left-hand expression is equal to the right-hand expression: “` tableViews()1.cells().firstWithPredicate("label == 'Olivia’ ”)

same in Xpath: /UIATableView[2]/UIATableCell@label = 'Olivia’ “`

>= , => - The left-hand expression is greater than or equal to the right-hand expression.

<= , =< - The left-hand expression is less than or equal to the right-hand expression.

> - The left-hand expression is greater than the right-hand expression.

< - The left-hand expression is less than the right-hand expression.

!= , <> - The left-hand expression is not equal to the right-hand expression.

BETWEEN - The left-hand expression is between, or equal to either of, the values specified in the right-hand side. The right-hand side is a two value array (an array is required to specify order) giving upper and lower bounds. For example, 1 BETWEEN { 0 , 33 }, or $INPUT BETWEEN { $LOWER, $UPPER }. In Objective-C, you could create a BETWEEN predicate as shown in the following example:

NSPredicate *betweenPredicate =
    [NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];

This creates a predicate that matches ( ( 1 <= attributeValue ) && ( attributeValue <= 10 ) )

Boolean Value Predicates

TRUEPREDICATE - A predicate that always evaluates to TRUE .

FALSEPREDICATE - A predicate that always evaluates to FALSE.

Basic Compound Predicates

AND , && - Logical AND.

OR , || - Logical OR.

NOT , ! - Logical NOT.

String Comparisons

String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME

BEGINSWITH - The left-hand expression begins with the right-hand expression.

scrollViews()[3].buttons().firstWithPredicate("name BEGINSWITH 'results toggle' ")

same in Xpath: /UIAScrollView[4]/UIAButton[starts-with(@name, 'results toggle')][1]

CONTAINS - The left-hand expression contains the right-hand expression.

tableViews()[1].cells().withPredicate("ANY collectionViews[0].buttons.name CONTAINS 'opera'")

same in Xpath: /UIATableView[2]/UIATableCell[UIACollectionView[1]/UIAButton[contains(@name, 'opera')]]

ENDSWITH - The left-hand expression ends with the right-hand expression.

LIKE - The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters. In Mac OS X v10.4, wildcard characters do not match newline characters.

tableViews()[0].cells().firstWithPredicate("name LIKE '*Total: $*' ")

same in Xpath: /UIATableView[1]/UIATableCell[matches(@name, '.*Total: \$.*')][1]

MATCHES - The left hand expression equals the right hand expression using a regex -style comparison according to ICU v3 (for more details see the ICU User Guide for Regular Expressions).

tableViews().firstWithPredicate("value MATCHES '.*of 7' ")

same in Xpath: /UIATableView[matches(@value, '.*of 7')][1]

Aggregate Operations

ANY , SOME - Specifies any of the elements in the following expression. For example ANY children.age < 18 .

tableViews()[0].cells().firstWithPredicate("SOME staticTexts.name = 'red'").staticTexts().withName('red')

same in Xpath: /UIATableView[1]/UIATableCell[[email protected] = 'red'][1]/UIAStaticText[@name = 'red']

ALL - Specifies all of the elements in the following expression. For example ALL children.age < 18 .

NONE - Specifies none of the elements in the following expression. For example, NONE children.age < 18 . This is logically equivalent to NOT (ANY ...) .

IN - Equivalent to an SQL IN operation, the left-hand side must appear in the collection specified by the right-hand side. For example, name IN { 'Ben', 'Melissa', 'Matthew' } . The collection may be an array, a set, or a dictionary—in the case of a dictionary, its values are used.

array[index] - Specifies the element at the specified index in the array.

array[FIRST] - Specifies the first element in the array.

array[LAST] - Specifies the last element in the array.

array[SIZE] - Specifies the size of the array elements()[0].tableViews()[0].cells().withPredicate("staticTexts[SIZE] > 2") same in Xpath: /*[1]/UIATableView[1]/UIATableCell[count(UIAStaticText) > 2]

Identifiers

C style identifier - Any C style identifier that is not a reserved word.

#symbol - Used to escape a reserved word into a user identifier.

[\]{octaldigit}{3} - Used to escape an octal number ( \ followed by 3 octal digits).

[\][xX]{hexdigit}{2} - Used to escape a hex number ( \x or \X followed by 2 hex digits).

[\][uU]{hexdigit}{4} - Used to escape a Unicode number ( \u or \U followed by 4 hex digits).

Literals

Single and double quotes produce the same result, but they do not terminate each other. For example, "abc" and 'abc' are identical, whereas "a'b'c" is equivalent to a space-separated concatenation of a, 'b', c.

FALSE , NO - Logical false.

TRUE , YES - Logical true.

NULL , NIL - A null value.

SELF - Represents the object being evaluated.

"text” - A character string.

'text’ - A character string.

Comma-separated literal array - For example, { 'comma', 'separated', 'literal', 'array' } .

Standard integer and fixed-point notations - For example, 1 , 27 , 2.71828 , 19.75 .

Floating-point notation with exponentiation - For example, 9.2e-5 .

0x - Prefix used to denote a hexadecimal digit sequence.

0o - Prefix used to denote an octal digit sequence.

0b - Prefix used to denote a binary digit sequence.

Reserved Words

The following words are reserved:

AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE

Appium predicate helpers

Appium has helpers for predicate search in app.js:

Here’s a Ruby example:

# Ruby example
text = 'Various uses'
predicate = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
element = execute_script(%Q(au.mainApp().getFirstWithPredicate("#{predicate}");))

puts element.name # Buttons, Various uses of UIButton

Adjusting Network Connection

The Selenium Mobile JSON Wire Protocol Specification supports an API for getting and setting the network connection for a device. The API works through a bitmask, assigning an integer to each possible state:

Value (Alias) Data Wifi Airplane Mode
0 (None) 0 0 0
1 (Airplane Mode) 0 0 1
2 (Wifi only) 0 1 0
4 (Data only) 1 0 0
6 (All network on) 1 1 0

iOS

Unfortunately, at the moment Appium does not support the Selenium network connection API for iOS.

Android

Choose the setting you would like to use, and then send the correct bitmask from the table above.

// set airplane mode
driver.setNetworkConnection(1)

// set wifi only
driver.setNetworkConnection(2)

// set data only
driver.setNetworkConnection(4)

// set wifi and data
driver.setNetworkConnection(6)

Retrieving the network connection settings returns the same bitmask, from which the status can be decoded.

driver.getNetworkConnection().then(function (connectionType) {
  switch (connectionType) {
    case 0:
      // no network connection
      break;
    case 1:
      // airplane mode
      break;
    case 2:
      // wifi
      break;
    case 4:
      // data
      break;
    case 6:
      // wifi and data
      break;
  }  
});

uiautomator UiSelector

Appium enables searching using UiSelectors. UiScrollable is also supported.

Note that the index selector is unreliable so prefer instance instead. The following examples are written against the api demos apk using Ruby.

Find the first textview.

first_textview = find_element(:uiautomator, 'new UiSelector().className("android.widget.TextView").instance(0)');

Find the first element by text.

first_text = find_element(:uiautomator, 'new UiSelector().text("Animation")')
first_text.text # "Animation"

Find the first scrollable element, then find a TextView with the text “Tabs”. The “Tabs” element will be scrolled into view.

element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")')

As a special case, scrollIntoView returns the element that is scrolled into view. scrollIntoView allows scrolling to any UiSelector.

element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("WebView").instance(0));')
element.text # "WebView"

Multi-lingual Support

By default the automation tools for both iOS and Android do not support non-ASCII characters sent to editable fields through the keyboard.

iOS

Appium sends non-ASCII characters to iOS editable fields directly, bypassing the keyboard altogether. While this allows the text to be inputted in tests, it should be kept in mind that any business logic triggered by keyboard input will therefore not be tested.

One main caveat to this behavior is the encoding of the strings sent and received. Unicode also has the concept of “combining characters”, which are diacritical modifications of other characters. Rather than a single character representing what is seen, two (or more, in the case of heavily accented characters) separate characters are sometimes used to represent one, with the system overlaying them.

Thus, while in Unicode the letter é (Unicode’s “LATIN SMALL LETTER E WITH ACUTE”) can be encoded as a single letter, the iOS simulator will return the equally valid representation of the letter e followed by the accent, ́ (“COMBINING ACUTE ACCENT”). When this occurs a test may be reported but the expected and actual results will look exactly the same. The solution to this is to normalize the text before asserting on it.

var unorm = require('unorm');
var testText = unorm.nfd("é Œ ù ḍ");
driver
  .elementsByClassName('UIATextField').at(1)
    .sendKeys(testText)
    .text()
    .should.become(testText)
  .nodeify(done);

Android

Android tests allow for Unicode input by installing and using a specialized keyboard that allows the text to be passed as ASCII text between Appium and the application being tested.

In order to utilize this functionality, set the unicodeKeyboard desired capability is set to true. If the keyboard should be returned to its original state, the resetKeyboard desired capability should also be set to true. Otherwise Appium’s Unicode keyboard will remain enabled on the device after the tests are completed.

Then tests can pass Unicode text to editable fields using send_keys.

var desired = {
  app: '/path/to/app',
  deviceName: 'Android Emulator',
  deviceVersion: '4.4',
  platformName: 'Android',
  unicodeKeyboard: true,
  resetKeyboard: true
};
var testText = 'é Œ ù ḍ';
driver
  .elementByClassName('android.widget.EditText')
  .sendKeys(testText)
  .text()
  .should.eventually.become(testText)
  .nodeify(done);