February 3, 2016

Appium Tips and Tricks for iOS

In this blog, I am sharing my experience of exploring Appium on iOS when I migrated to it from Selenium Webdriver. Mobile automation poses different types of challenges in comparison to the automation of Web browsers. In this blog, I will be exploring a few interesting challenges that I faced while doing iOS App automation.

First let’s see why automating mobile apps is important:

  1. There is huge fragmentation of both devices and mobile operating system versions, which makes it difficult to do manual comprehensive testing across all of the versions for all of the devices. So the best possible solution seems to be automation testing where devices and mobile OS can be configured dynamically.
  2. It is difficult for a manual tester to hold a device and keep testing an app for around 6-7 hours, as well as do this for different devices.

Appium is the most widely-used open source tool to automate mobile apps, Android and iOS, and works on the philosophy of Webdriver’s HTTP JSON Wire Protocol client server architecture.

Now let’s try to launch an iOS app through code. In the Appium 3.2 Java client, there is a provision to start/stop the Appium server programmatically through code. Let’s look into it:



In order to run this code snippet without any errors, I need to have the following jar files in my buildpath:

  1. java-client-3.2.0
  2. commons-validator-1.4.1
  3. selenium-java-2.47.1

Now, I will be discussing some challenges and findings that I came across while automating an iOS app.

Scrolling in an iOS App

Scrolling is one of the important functions that we need to perform when we are using or manually testing an app. Appium has given this functionality to make our mobile test automation suite more robust.

So, let’s explore how scrolling is implemented in an iOS app for different scenarios:

a. Scrolling Element as per text

Scrolling can be performed on UIATableViews. So, in order to use the scrollTo() or scrollToExact() methods, we need to find the required UIATableView because it has UIATableCells that we need to scroll down to.



This is how our screen appears when we navigate to it.




When we execute the scrollTo() method, it puts focus on that element where “THE PURSUIT” text is found first. So in the above figure, the focus is on the first cell having “THE PURSUIT” text.



After the scroll and click operation is performed.

b. Scrolling element as per index

In the above method, we have successfully scrolled and clicked on the element with “THE PURSUIT” text. But if we want to click on the second cell with “THE PURSUIT” text, that approach won’t work. Therefore, in order to do this we need to consider indexes while performing scrolling.



We will be clicking the second element with the text "THE PURSUIT."



Here we have successfully clicked on the second element with the desired text. We have made the scrolling operation dynamic by considering indexes.

Geolocation Testing

Appium has the capabilities to perform geolocation testing. So, we will see different variations of it.

In order to set the simulator to a specific country, we can send this information with the “locale” capability provided by Appium.




But when we try to start iOSDriver with the “locale” capability, an error is shown, as given below, and execution halts.

(Original error: Appium was unable to set locale info: Error: Settings file /Users/Administrator/Library/Developer/CoreSimulator/Devices/BAD846F7-14D4-4704-A299-E6BD05FFFDC5/data/Library/Preferences/.GlobalPreferences.plist did not exist)","origValue":"Appium was unable to set locale info: Error: Settings file /Users/Administrator/Library/Developer/CoreSimulator/Devices/BAD846F7-14D4-4704-A299-E6BD05FFFDC5/data/Library/Preferences/.GlobalPreferences.plist did not exist"},"sessionId":null}
info: <-- POST /wd/hub/session 500 31292.624 ms - 562

So in order to perform geolocation testing, we will be setting the latitudes, longitudes, and altitudes of a particular region using the Location object provided by Selenium Webdriver API.



This way we can set the simulator to a specific region within a country with some precision. This is a much better workaround to perform geolocation testing because an exact region can be set. However, there is no method to fetch the location set by setLocation() method. If we do Locale.getDefault(), we will be getting our System’s locale, whereas the Simulator’s locale has been changed programmatically. Once the location is set correctly, the simulator’s maps can manually verify it.

Embedded Images

It is not possible to access images embedded in Table Cells. Let’s take a scenario where there is a star icon on the app and I need to verify that it toggles when clicked. So, when I inspect this star icon, I see that it is embedded in table cell; therefore, it can’t be accessed because there is no UIAImage element present. In the below screenshots, the star icon is toggled but the properties are exactly same. In comparison, in the case of the checkbox, the “value” property gets changed to 1 when checked.






Inspecting Webviews

Webview is a browser bundled inside of a mobile app that allows mobile apps to be built using web technologies (HTML, Javascript, CSS, etc.) but still packages them as a native app.

In order to inspect elements in a Webview opened in an iPhone/simulator, we should be able to see its DOM. These are the steps to see an iPhone/simulator’s DOM on the Safari browser.

  1. Open on iPhone/simulator: Settings > Safari > Advanced > Switch On Web Inspector
  2. Open Safari on laptop/iMac: Develop > iOS Simulator > Select Webview opened on device/simulator
  3. Now Webview can be inspected just like we inspect elements in a web browser

Enable Web Inspector in iPhone/simulator



After enabling Web Inspector, the Webview can be seen in the Safari browser as explained above.



Dragging Images

Dragging images to a certain level with precision is another challenge that I faced while automating an iOS app.

Let’s take a scenario where I have an image that shows different results when dragged to different levels. To do this, I have made use of the UI Automation library’s dragInsideWithOptions(startOffset, endoffset).

Below is the screen appearance when I navigated to the image. The image is present in the center and can be dragged to see different results. To do this, I made use of the x and y offsets.

When image is in the center, the x offset = 0.5 and the y offset = 0.5. Now I intend to move the image on the y-axis to see varied results. In a similar manner, the x offset can also be moved.



Let's see what happens when the y offset moves from 0.5 to 1.0.




Let's see what happens when the y offset is moves from 0.5 to -0.5.



Traversing Through Page Indicators

Page indicators are used to implement pagination in an iOS app. Let’s take a scenario where some new features are added in an app and page indicators are added to inform users about those new features. Page Indicators move when a user swipes it to see the next one. Performing the swipe precisely is a bit difficult using the swipe() method, So its workaround is to find UIAPageIndicators and perform the click operation on it.





Optimizing Test Execution

  • Automated tests run much faster on an iPhone simulator in comparison to execution on real devices.
  • When running your automated tests on a real device, it can be observed that performance takes a hit because a real device has a built-in delay of 1 second between every request. Essentially, we may not find significant execution time until the login screen because there is less data we need to fetch. But after the login screen, execution becomes extremely slow as more data needs to be processed and fetched, which, when coupled with the 1 second delay per request, increases execution time.
  • When finding elements on an iOS app, use findElementByIosUIAutomation or findElementByAccessibilityId rather than using XPath because using IosUIAutomation natively interacts with its UIAutomation framework, giving better performance.
  • Only 1 simulator can be launched on a machine, which restricts parallel execution of the test.