Bruno Alassia
Software Engineer 🐳 rosarino en Canada
Who am I ?
Bruno Alassia
Software Engineer @ SauceLabs - Emulators & Simulators Team
Fullstack developer, Nodejs enthusiast
More than 300 combinations of browsers/OS
Test mobile & webapps in parallel
Watch videos, screenshots, logs,... of your automated tests
What is Appium ?
Appium is an open source test automation framework for use with native, hybrid and mobile web apps.
It drives iOS, Android, Windows desktop apps and more using the WebDriver protocol
Why Appium ?
How appium works
Demo
Appium news
Install
Android Requirements
iOS Requirements
npm install -g appium
Before testing, make sure you have emulators|simulators available
List devices
Create simulator
List devices
Create emulator
~$ xcrun simctl list devices
xcrun simctl create "iPhone 5s" com.apple.CoreSimulator.SimDeviceType.iPhone-5s \
com.apple.CoreSimulator.SimRuntime.iOS-9-3
~$ emulator -list-avds
~$ android create avd -n "Nexus-5" -t "android-22" -c "1024M" --abi x86_64 -d "Nexus 5"
Running appium
appium &
Let the tests begin!
Workshop repository
git clone https://github.com/vrunoa/appium-workshop
The idea is to follow this slides and start creating tests from knowing nothing to run a test on the cloud using a tunnel.
For order of this to happen we are going to follow the exercises under this repo. Check the README inside every exercise folder. And if you have any doubts ask me or cheat by looking at the solution.
import chai from 'chai';
chai.should();
import { sleep } from 'asyncbox';
import wd from 'wd';
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
import wd from 'wd';
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
The WebDriver client
import wd from 'wd';
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
The Capabilities
Capabilities are the way to tell Appium which kind of session we are interested in.
Most common capabilities
Capability | Description | Values |
---|---|---|
platformName | Which mobile OS platform to use | Android, iOS |
platformVersion | Mobile OS version | 9.3, 4.4.3 |
deviceVersion | The kind of mobile device or emulator to use | iPhone Simulator, iPad Simulator,iPhone Retina 4-inch, Android Emulator... |
automationName | Which automation engine to use | Appium(default), Selendroid, XCuiTest |
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 |
orientation | (Sim/Emu-only) start in a certain orientation | LANDSCAPE or PORTRAIT |
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
Test body
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
Starting a session
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
Opening an url
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
Getting the page title
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Safari",
"deviceName" : "iPhone 5s",
"platformName" : "iOS",
"platformVersion" : "10.0",
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async () => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
});
});
Closing current session
Running
What if I want to run the same test on an Android emulator ?
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Browser",
"deviceName" : "Android Emulator",
"platformName" : "Android",
"platformVersion" : "4.4.3",
"avd": "Nexus-5"
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async (done) => {
await sleep(5000);
await driver.get('https://vrunoa.github.io/appium-workshop/');
await sleep(500);
let title = await driver.title();
title.should.equal("Appium Workshop");
done();
});
});
Change the capabilities
Finding elements
.elementById
.elementByClassName
.elementByName
.elementByTagName
Playing with elements
.click
.flick
.sendKeys
.clear
.getAttribute
.tap
.setValue
.getValue
.text
.isDisplayed
Miscelaneous commands
.back
.getPageSource
.getPageTitle
.getWindowSize
.hideKeyboard
.getGeoLocation
.setGeoLocation
.getOrientation
.setOrientation
.setUrl
Touch gestures
let action = new TouchAction()
action.press(100,100)
.wait(100)
.moveTo(150,150)
.release()
await action.perform();
What about native apps testing ?
Use native application capabilities
let driver = wd.promiseChainRemote('localhost', 4723);
let capabilities = {
"browserName" : "Browser",
"deviceName" : "Android Emulator",
"platformName" : "Android",
"platformVersion" : "4.4.3",
"appPackage": "com.example.android",
"appActivity": "com.example.android.SplashActivity",
"appWaitActivity": "com.example.android.MainActivity",
"app": "~/Sauce/appium-workshop/examples/android/android-debug.apk"
"avd": "Nexus-5"
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async (done) => {
await sleep(500);
let el = await.findElementById("button1");
let bttText = await el.getText();
bttText.should.equal("Button1")
done();
});
});
Android common capabilities
Capability | Description | Values |
---|---|---|
appActivity | Activity name for the Android activity you want to launch from your package. | .MainActivity, .Settings, .SplashActivity |
appPackage | Java package of the Android app you want to run | com.example.android.app |
appWaitActivity | Activity name for the Android activity you want to wait for | .MainActivity |
avd | Name of avd to launch | Nexus-5-API-19 |
avdArgs | Additional emulator arguments used when launching an avd | -netfast, -http-proxy, -camera-front |
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 | /abs/path/to/my.apk orhttp://myapp.com/app.ipa |
iOS common capabilities
Capability | Description | Values |
---|---|---|
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. To run a test on a real device using the bundle ID, you may omit the 'app' capability, but you must provide 'udid'. | io.appium.TestApp |
udid | Unique device identifier of the connected physical device | 1ae203187fc012g |
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 bundleIdcapability to send in your app's bundle ID. | true or false |
autoAcceptAlerts | Accept all iOS alerts automatically if they pop up. This includes privacy access permission alerts | true or false |
autoDismissAlerts | Dismiss all iOS alerts automatically if they pop up. | true or false |
Changing contexts to test Hybrid apps
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async (done) => {
await sleep(500);
let contexts = await driver.getContexts()
let webViewContexts = null;
for (let i in contexts) {
if(contexts[i].indexOf("WEBVIEW") webViewContexts = contexts[i]
}
webViewContexts.should.not.equal(null);
await driver.setContexts(webViewContexts);
let bttText = await el.getText();
bttText.should.equal("Button1")
done();
});
});
Using cloud devices at SauceLabs
let driver = wd.promiseChainRemote('ondemand.saucelabs.com', 8080);
let capabilities = {
"browserName" : "Browser",
"deviceName" : "Android Emulator",
"platformName" : "Android",
"platformVersion" : "4.4",
"appPackage": "com.example.android",
"appActivity": "com.example.android.SplashActivity",
"appWaitActivity": "com.example.android.MainActivity",
"app": "sauce-storage:android-debug.apk"
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async (done) => {
await sleep(500);
let el = await.findElementById("button1");
let bttText = await el.getText();
bttText.should.equal("Button1")
done();
});
});
https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/
Testing grid
{
"browsers": [
{
"browserName": "browser", "version": "4.4",
"platformName": "Android", "device": "Android Emulator"
}, {
"browserName": "browser", "version": "5.0",
"platformName": "Android", "device": "Android Emulator"
}, {
"browserName": "browser", "version": "5.1",
"platformName": "Android", "device": "Android GoogleApi Emulator"
}, {
"browserName": "safari", "version": "10.0",
"platformName": "iOS", "device": "iPhone 6s Simulator"
}, {
"browserName": "safari", "version": "9.3",
"platformName": "iOS", "device": "iPhone 6s Simulator"
}, {
"browserName": "safari", "version": "9.3",
"platformName": "iOS", "device": "iPad Air Simulator"
}
],
"remoteCfg": {
"hostname": "ondemand.saucelabs.com",
"port": 80,
"username": "YOUR USERNAME",
"accessKey": "YOUR-ACCESS-KEY"
}
}
https://github.com/themouette/selenium-grid
Sauce connect, use a tunnel in the cloud
let driver = wd.promiseChainRemote('ondemand.saucelabs.com', 8080);
let capabilities = {
"browserName" : "Browser",
"deviceName" : "Android Emulator",
"platformName" : "Android",
"platformVersion" : "4.4"
};
describe("Test Appium workshop page", _ => {
before(async () => {
await driver.init(capabilities);
});
after(async () => {
await driver.quit();
});
it("Verify page title is Appium Workshop", async (done) => {
await sleep(5000);
await driver.get('http://localhost:2000');
await sleep(1000);
let el = await.findElementById("button1");
let bttText = await el.getText();
bttText.should.equal("Button1")
done();
});
});
https://wiki.saucelabs.com/display/DOCS/Setting+Up+Sauce+Connect
The future of Appium
Appium, rather than bundling all the separate drivers by default, becomes a driver management interface (in addition to continuing to play the role of automation frontend server). Appium gets a set of CLI tools for users to pick and choose which drivers and versions of drivers they want to use via Appium.
https://github.com/appium/appium/blob/master/ROADMAP.md
By Bruno Alassia