Appium 2.0 Workshop
WiFi: tgr_guest / Tbartok105113
Appium Philosophy
- You’re testing the same app you are shipping
- Write tests in any language and framework you want
- Wrapped vendor-provided frameworks in WebDriver API (Webdriver Protocol)
- Open source
Appium 2.0 Evolution & What's New
Appium 2.0
The main differences
- Addition of Drivers & Plugin Support
- CLI Support for Drivers and Plugins
- No more JSONWP. Only W3C protocol.
- Expose common driver and functionality. Makes it easier for anyone to write new Drivers
- The core foundational modules have been moved to the 'Appium' monorepo
Appium 2.0 : Architecture
Android Architecture
W3C
Server Request
Server
Client
Appium Server
Driver(espresso)
Server Request
Plugins
iOS Architecture
W3C
Server Request
Client
Appium Server
Driver(xcuitest)
Server Request
Plugins
WDA
Appium 2.0 : Server
Server Installation
npm install -g appium
Not auto-installing any drivers or plugins
Server CLI
-ah APPIUMHOME The path to the directory where Appium will keep installed drivers, plugins,
and any other metadata necessary for its operation
--use-drivers DRIVERS A comma-separated list of installed driver names that should be active
for this server. All drivers will be active by default.
--use-plugins PLUGINS A comma-separated list of installed plugin names that should be active
for this server. To activate all plugins, you can use the single string "all" as the value (e.g. --plugins=all)
Appium Drivers & Plugins
Driver CLI
appium driver list
appium driver install xcuitest
appium driver install --source=local
--package=your-driver /path/to/your/driver
appium driver update --installed
appium driver uninstall xcuitest
Plugin CLI
appium plugin list
appium plugin install images
appium --use-plugins=images,fake
appium plugin update
appium plugin uninstall images
Appium Server : Advanced
Start Appium server programmatically
AppiumDriverLocalService service = AppiumDriverLocalService
.buildService(new AppiumServiceBuilder()
.usingPort(PORT)
.withArgument(GeneralServerFlag.BASEPATH, "/wd/hub"));
service.start();
.......
driver = new AndroidDriver(service.getUrl(), uiAutomator2Options);
Starting Appium Server Programmatically With Plugins
AppiumDriverLocalService service = AppiumDriverLocalService
.buildService(new AppiumServiceBuilder()
.usingPort(PORT)
.withArgument(GeneralServerFlag.BASEPATH, "/wd/hub")
.withArgument(GeneralServerFlag.PLUGINS, "device-farm"));
service.start();
.......
driver = new AndroidDriver(service.getUrl(), uiAutomator2Options);
Platform-wise desired capabilities
Android | iOS |
---|---|
skipUnlock | usePrebuiltWDA |
appWaitPackage | derivedDataPath |
appWaitActivity | useJSONSource |
androidInstallTimeout | iosInstallPause |
disableAndroidWatchers | maxTypingFrequency |
autoGrantPermission | mjpegServerPort |
avd | wdaLaunchTimeout |
Refer:-
https://appium.io/docs/en/writing-running-appium/caps/
https://caps.cloudgrey.io/
Android & iOS Options
UiAutomator2Options uiAutomator2Options = new UiAutomator2Options()
.setDeviceName("Android Emulator")
.setAutomationName(AutomationName.ANDROID_UIAUTOMATOR2)
.setApp(System.getProperty("user.dir") + "/VodQA.apk");
driver = new AndroidDriver(service.getUrl(), uiAutomator2Options);
wait = new WebDriverWait(driver, Duration.ofSeconds(30));
Gestures
Actions API for gestures
Horizontal Swipe using W3C Action API
x axis
y axis
(x1,y1)
(x2,y1)
Accessibility id: slider
getElementLocation - (X1,Y1)
pointerMove - (X1,Y1)
pointerDown
pointerMove - (X2,Y1)
pointerUp
pause
(0,0)
WebElement slider = driver.findElement(AppiumBy.accessibilityId("slider"));
Point source = slider.getLocation();
PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
Sequence sequence = new Sequence(finger, 1);
sequence.addAction(finger.createPointerMove(ofMillis(0),
PointerInput.Origin.viewport(), source.x, source.y));
sequence.addAction(finger.createPointerDown(PointerInput.MouseButton.MIDDLE.asArg()));
sequence.addAction(new Pause(finger, ofMillis(600)));
sequence.addAction(finger.createPointerMove(ofMillis(600),
PointerInput.Origin.viewport(), source.x + 400, source.y));
sequence.addAction(finger.createPointerUp(PointerInput.MouseButton.MIDDLE.asArg()));
driver.perform(singletonList(sequence));
Horizontal Swipe
Do It Yourself
Try yourself to perform a Drag and Drop operation on Android
iOS specific gestures
Map<String, Object> args = new HashMap<>();
args.put("direction", "up");
driver.executeScript("mobile: swipe", args);
args.put("direction", "down");
driver.executeScript("mobile: swipe", args);
mobile: swipe
Map<String, Object> args = new HashMap<>();
args.put("direction", "down");
driver.executeScript("mobile: scroll", args);
args.put("direction", "up");
driver.executeScript("mobile: scroll", args);
mobile: scroll
Map<String, Object> args = new HashMap<>();
args.put("scale", 5);
driver.executeScript("mobile: pinch", args);
mobile: pinch
iOS specific gestures
Map<String, Object> args = new HashMap<>();
args.put("element", ((MobileElement) element).getId());
args.put("x", 2);
args.put("y", 2);
driver.executeScript("mobile: tap", args);
mobile: tap
// double-tap the screen at a specific point
Map<String, Object> args = new HashMap<>();
args.put("x", 100);
args.put("y", 200);
driver.executeScript("mobile: doubleTap", args);
mobile: doubleTap
// two-finger-tap an element (assume element object already
exists)
Map<String, Object> args = new HashMap<>();
args.put("element", ((MobileElement) element).getId());
driver.executeScript("mobile: twoFingerTap", args);
mobile: twoFingerTap
iOS specific gestures
// touch and hold an element
Map<String, Object> args = new HashMap<>();
args.put("element", ((MobileElement) element).getId());
args.put("duration", 1.5);
driver.executeScript("mobile: touchAndHold", args);
mobile: touchAndHold
// touch, hold, and drag based on coordinates
Map<String, Object> args = new HashMap<>();
args.put("duration", 1.5);
args.put("fromX", 100);
args.put("fromY", 100);
args.put("toX", 300);
args.put("toY", 600);
driver.executeScript("mobile: dragFromToForDuration", args);
mobile:dragFromToForDuration
Android specific gestures
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/android/android-mobile-gestures.md
driver.executeScript("mobile: longClickGesture", ImmutableMap.of(
"elementId", ((RemoteWebElement) element).getId());
mobile: longClickGesture
driver.executeScript("mobile: doubleClickGesture", ImmutableMap.of(
"elementId", ((RemoteWebElement) element).getId());
mobile: doubleClickGesture
driver.executeScript("mobile: dragGesture", ImmutableMap.of(
"elementId", element.getId(),
"endX", 100,
"endY", 100
));
mobile: dragGesture
Do It Yourself
Try yourself to perform a Drag & Drop Gesture on Android
Wait Plugin
appium plugin install --source=npm appium-wait-plugin
appium --plugins=element-wait
wait = new WebDriverWait(driver, 30);
wait.until(presenceOfElementLocated(MobileBy.AccessibilityId("login")))
.click();
wait.until(presenceOfElementLocated(MobileBy.AccessibilityId("slider1")));
driver.findElementByAccessibilityId("login").click();
driver.findElementByAccessibilityId("slider1").click();
Before wait plugin
After wait plugin
Gestures Plugin
MobileElement source = (MobileElement) new WebDriverWait(driver, 30)
.until(elementToBeClickable(MobileBy.AccessibilityId("dragMe")));
MobileElement destination = (MobileElement) new WebDriverWait(driver, 30)
.until(elementToBeClickable(MobileBy.AccessibilityId("dropzone")));
driver.addCommand(HttpMethod.POST,
String.format("/session/%s/plugin/actions/dragAndDrop",
driver.getSessionId()), "dragAndDrop");
driver.execute("dragAndDrop", ImmutableMap.of(
"sourceId", source.getId(),
"destinationId", destination.getId()));
Appium Debugging & Maintenance
Android shell interactions
10057 ◯ : adb shell dumpsys battery
Current Battery Service state:
AC powered: true
USB powered: false
Wireless powered: false
Max charging current: 0
Max charging voltage: 0
Charge counter: 0
status: 2
health: 2
present: true
level: 100
scale: 100
voltage: 0
temperature: 0
technology: Li-ion
Get Battery Information
10078 ◯ : adb shell dumpsys cpuinfo
Load: 0.0 / 0.0 / 0.0
CPU usage from 312959ms to 312499ms ago (2018-10-07 10:49:37.267 to 2018-10-07 10:49:37.727):
151% 1523/system_server: 51% user + 100% kernel / faults: 7233 minor 83 major
15% 1365/surfaceflinger: 6.6% user + 8.8% kernel / faults: 1 minor
15% 1375/installd: 2.2% user + 13% kernel / faults: 113 minor
6.6% 1499/bootanimation: 4.4% user + 2.2% kernel
4.4% 1358/android.hardware.graphics.composer@2.1-service: 2.2% user + 2.2% kernel
2.2% 1288/kworker/0:1: 0% user + 2.2% kernel
2.2% 1298/logd: 0% user + 2.2% kernel / faults: 5 minor
2.2% 1299/servicemanager: 0% user + 2.2% kernel / faults: 1 minor
2.2% 1360/android.hardware.sensors@1.0-service: 0% user + 2.2% kernel / faults: 20 minor
50% TOTAL: 13% user + 26% kernel + 10% iowait
Get cpu Information
10079 ◯ : adb shell service list
List all services
Android - Espresso
- Provides automatic synchronization of test actions with UI
- Powerful Matchers available
- Access to App internals - WebViews
File appDir = new File("src/test/java/io/appium/java_client");
File app = new File(appDir, "ApiDemos-debug.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("automationName", AutomationName.ESPRESSO);
capabilities.setCapability("deviceName", "Android Emulator");
capabilities.setCapability("app", app.getAbsolutePath());
driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"),
capabilities);
Android Espresso Locator Strategy
Data Matcher
String selector = new Json().toJson(ImmutableMap.of(
"name", "hasEntry",
"args", ImmutableList.of("title", "Sweep")));
driver.findElement(MobileBy.androidDataMatcher(selector)).click();
http://appium.io/docs/en/writing-running-appium/android/espresso-datamatcher-selector/
iOS Locator Strategy
http://appium.io/docs/en/writing-running-appium/ios/ios-predicate/
https://github.com/facebook/WebDriverAgent/wiki/Predicate-Queries-Construction-Rules
Predicates
driver.findElementByIosNsPredicate("name like 'Answer'")
class chain
driver.findElementByIosClassChain("**/XCUIElementTypeTable
[`name == "table"`]/XCUIElementTypeCell[`visible == 1`]")
https://github.com/facebook/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules
https://github.com/facebook/WebDriverAgent/wiki/How-To-Achieve-The-Best-Lookup-Performance#select-the-most-effective-lookup-strategy
Accessibility Identifier
driver.findElementByAccessibilityId("ComputeSumButton")
Appium Advanced usecases
Parallel Test Execution
Android | iOS |
---|---|
UDID - Device ID | UDID - Real device/SimID |
chromedriverport - incase of webviews or chrome | wdalocalport - unique port no as WDA defaults to 8100 |
systemPort - If you are using UIA2 mode, set a different system port for each Appium instance set with systemPort capability since sometimes there can be a port conflict if different ports aren't used, such as in this issue.(https://github.com/appium/appium/issues/7745) |
deviceName - Simulator Name (sim only) platformVersion -Simulator OS version (sim only) |
Refer: http://appium.io/docs/en/advanced-concepts/parallel-tests/
Device Farm Plugin
appium plugin install --source=npm appium-device-farm
appium --use-plugins=device-farm
- Automatically detects connected Android, iOS Simulators, and Real devices before session creation and maintains it in the device pool.
- Dynamically allocates a free device from the device pool while creating a driver session.
- Updates the device pool with a new device during test execution.
- Queues the test cases when no free device is available for session creation.
- Allocates random ports for parallel execution.
Automating Hybrid Apps - Tips & Tricks
Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
System.out.println(contextName); //prints out something like NATIVE_APP \n WEBVIEW_1
}
driver.context(contextNames.toArray()[1]); // set context to WEBVIEW_1
//do some web testing
String myText = driver.findElement(By.cssSelector(".green_button")).click();
driver.context("NATIVE_APP");
Automating Geo Location
driver.setLocation(new Location(49, 123, 10));
SMS Simulation (Android)
driver.sendSMS("555-555-5555", "Your message here!");
Video Recording API
driver.startRecordingScreen();
driver.startRecordingScreen(new AndroidStartScreenRecordingOptions(...));
driver.stopRecordingScreen();
driver.stopRecordingScreen(new BaseStopScreenRecordingOptions(....));
Seeding Photos on Android & iOS Simulators
driver.pushFile("/mnt/sdcard/Pictures/myPhoto.jpg",
"/path/to/photo/locally/myPhoto.jpg");
Appium 2.0 for users
What you should do next?
- Read the documentation, understand the drivers and plugins way of working.
- Update client frameworks to the latest
- Validate whether they use W3C protocol
- The appium:automationName capability will be required
- Test your current scripts with 'appium@next' to make sure they are ready for an upgrade to Appium 2.0
- Drivers and plugins must be installed
Thank you
Appium 2.0 Workshop
By Srinivasan Sekar
Appium 2.0 Workshop
- 21