Table of Contents

Extensions (Static Methods)

Due to the way we structure our framework, we can create static methods that we can use as extensions on methods involving different object types, such as tapping or long-pressing on a MobileElement, swiping from one element to another, explicitly waiting for an AppiumDriver, or waiting for a MobileElement to be displayed or clickable etc.

MobileElement Extensions

We will begin each method name with ‘me’ (for MobileElement).

First things first, let’s add a private static iOSDriver variable and set it to what’s returned from our ‘appDriver()’ method.

  1. Open up the ‘MobileElementExtensions’ class in the ‘utils.extensions’ package and add the following static variable inside the class at the top…

meWaitForSeconds() Static Method

  1. Open up the ‘MobileElementExtensions’ class in the ‘utils.extensions’ package and add the following static method for making the Driver wait for a specified number of seconds…
  2. Make sure the import for ‘WebDriverWait’ and the static import for appDriver() method have been added above the class…
  3. Add a static integer variable set to a value of 10 for ‘sec’, and make it private to the class it is in, just above the weWaitForSeconds() method…

meElementIsDisplayed() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to check that a given MobileElement is displayed, after waiting the specified amount of time from the weWaitForSeconds() method …
  2. Also make sure the import for ‘ExpectedConditions’ is added above the class, as well as an import for ‘WebElement’…

meElementToBeClickable() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to check that a given MobileElement is clickable, after waiting the specified amount of time from the meWaitForSeconds() method…

meTap() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to wait for a given MobileElement to be clickable/tappable, highlight the clickable/tappable MobileElement, and then tap the MobileElement (this is better than simply clicking as on mobile the more realistic action would actually be tapping)…

    For the above to work, we need to add the following static imports…

    We also need to make sure we import the TouchAction class…

    We then need to add a a private static TouchAction object in the top of our class (this way we can reuse the TouchAction class in other similar methods)…

meLongPress() Static Method

  1. Edit the meTap() method so it looks like below…
  2. Add the following method for long pressing on a Mobile element for two seconds, and then releasing your finger from it…

    For the above to work, we need to add two more static imports for all Duration methods (* is wildcard for all) and LongPressOptions longPressOptions method

meSwipeFromElementToElement() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to check that the elements to swipe to and from are clickable and highlighted, and then press down on one element and swipe it to another element and then release the finger / touch…

meSwipeDirection() Static Methods

  1. Add the following DIRECTION enum to the MobileExtensions class…
  2. Add the following method which uses a switch case with the enum we made to swipe in any given direction…

meSendKeys() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to wait for a given textfield MobileElement to be displayed, clear the textfield if necessary (if ‘clearFirst’ is true), and then input a given String into the textfield…

meElementIsInvisible() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to wait for a given MobileElement to not be visible anymore…

meGetAttribute() Static Method

  1. Add the following static method in the ‘MobileElementExtensions’ class to find a specified attribute of a given element…

iOS Specific Gestures (XCUITest)

Unfortunately Apple’s XCTest framework does not natively support W3C standards for TouchAction interface implementation.  It has to serialise the XML into a format XCTest will understand, which can often times be slow in performance.  Although, XCTest does provide a rich set of gestures, including these, that are unique for iOS platform.

If you ever run into difficulty using the W3C Action API, Appium provides direct access to these vendor-supported action methods as well. In this article we’ll take a look at the ones available for iOS. Because these are not part of the WebDriver spec, Appium provides this access by overloading the executeScript command, as you’ll see in the examples below.

We will being each method name with ‘xc’ (as it is specific to XCUITest mobile gestures).

First things first, let’s make this ‘XCTestExtensions’ class extend ‘MobileElementExtensions’ class and also add a private static iOSDriver variable and set it to what’s returned from our ‘appDriver()’ method (making sure we add the correct static import), like below…

xcSwipe() Static Methods

xcSwipe(String direction) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class in the ‘utils.extensions’ package to swipe the whole screen in a given direction…

    Also make sure the following imports are added…

xcSwipe(String direction, MobileElement element) Static Method

This is an overloaded version of the above method that also takes a given element that can be swiped on specifically.

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to swipe a given element in a given direction…

    Unfortunately, XCUITest does not provide any parameters to modify the speed or distance of the swipe. For that, use the more general Actions API.

    Also make sure the following import is added for MobileElement…

xcScroll() Static Methods

xcScroll(String direction) Static Method

If you want to try and make sure that each movement of your gesture moves a view by the height of the scrollable content, or if you want to scroll until a particular element is visible, try mobile: scroll. It works similarly to mobile: swipe but takes more parameters:

  • element: the id of the element to scroll within (the application element by default). Call this the “bounding element”
  • direction: the opposite of how direction is used in mobile: swipe. A swipe “up” will scroll view contents down, whereas this is what a scroll “down” will do.
  • name: the accessibility ID of an element to scroll to within the bounding element
  • predicateString: the NSPredicate of an element to scroll to within the bounding element
  • toVisible: if true, and if element is set to a custom element, then simply scroll to the first visible child of element
  1. Add the following static method in the ‘XCTestExtensions’ class to scroll the screen a given direction (direction is opposite to swipe, so swiping up would be the same as scrolling down)…

xcScroll(String direction, MobileElement element) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class to scroll a given direction on a given element…

xcScroll(String direction, String parameter, String nameOrPredicateString) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to scroll a given direction to a child element (found by either ‘name’ [accessibility ID] or ‘predicateString’)…

xcPinchOrZoom() Static Methods

This method is to pinch (described by a two-finger gesture where the fingers start far apart and come together).

The only required parameter is scale:

  • Values between 0 and 1 refer to a “pinch”
  • Values greater than 1 refer to a “zoom in” (or pinching open).

xcPinchOrZoom(double scale) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to pinch or zoom the whole application based on a given ‘double’ scale number (between 0 and 1) that we pass…

xcPinchOrZoom(MobileElement element, double scale) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to pinch or zoom a given element based on a given ‘double’ scale number (between 0 and 1) that we pass…

xcTapOn() Static Methods

The best way to tap on an element is using element.click(). So why do we have mobile: tap? This method allows for extra mandatory parameters x and y signifying the coordinate at which to tap. The nice thing is that this coordinate is either screen-relative (if an element parameter is not included, the default), or element-relative (if an element parameter is included).

This means that if you want to tap at the very top left corner of an element rather than dead centre, you can!

xcTapOn(double x, double y) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to tap on the screen at given x and y coordinates…

xcTapOn(MobileElement element, double x, double y) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to tap on a given element at the given x and y coordinates of that element…

xcDoubleTapOn() Static Methods

xcDoubleTapOn(double x, double y) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to double tap on the screen at the given x and y coordinates…

xcDoubleTapOn(MobileElement element) Static Method

  1. Add the following overloaded static method in the ‘XCTestExtensions’ class to double tap on a given element…

xcTwoFingerTapOn(MobileElement element) Static Method

Not to be confused with a double-tap, a two-finger-tap is a single tap using two fingers! This method has only one parameter, which is required: good old element (it only works in the context of an element, not a point on the screen).

  1. Add the following static method in the ‘XCTestExtensions’ class to two-finger tap on a given element…

xcTouchAndHoldOn(MobileElement element, double duration) Static Method

Many iOS apps allow a user to trigger special behaviour by tapping and holding the finger down on a certain UI element. You can specify all the same parameters as for doubleTap (elementx, and y) with the same semantics. In addition you must set the duration parameter to specify how many seconds you want the touch to be held.

  1. Add the following static method in the ‘XCTestExtensions’ class to touch and hold on a given element for a given duration…

xcDragFromToForDuration() Static Methods

Another commonly-implemented app gesture is “drag-and-drop”. As with all of these gestures, it’s possible to build a respectable drag-and-drop using the Actions API, but if for some reason this doesn’t work, XCUITest has provided a method directly for this purpose. It’s a method on the XCUICoordinate class.

What’s going on here is that we’re defining a start and an end coordinate, and also the duration of the hold on the start coordinate. In other words, we have no control over the drag duration itself, only on how long the first coordinate is held before the drag happens. What parameters do we use?

  • element: an element ID, which if provided will cause Appium to treat the coordinates as relative to this element. Absolute screen coordinates otherwise.
  • duration: the number of seconds (between 0.5 and 6.0) that the start coordinates should be held
  • fromX: the x-coordinate of the start position
  • fromY: the y-coordinate of the start position
  • toX: the x-coordinate of the end position
  • toY: the y-coordinate of the end position

xcDragFromToForDuration(double duration, double fromX, double fromY, double toX, double toY) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class to drag and drop from given x and y coordinates of the whole screen/application, to given x and y coordinates, again of the whole screen/application…

xcDragFromToForDuration(MobileElement element, double duration, double fromX, double fromY, double toX, double toY) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class to drag and drop from given x and y coordinates of the given element, to given x and y coordinates, again of the same given element…

xcSelectPickerWheelValue(MobileElement element, String order, double offset) Static Method

This method performs selection of the next or previous picker wheel value.

Supported arguments

  • element: PickerWheel’s internal element id (as hexadecimal hash string) to perform value selection on. The element must be of type XCUIElementTypePickerWheel. Mandatory parameter
  • order: Either next to select the value next to the current one from the target picker wheel or previous to select the previous one. Mandatory parameter
  • offset: The value in range [0.01, 0.5]. It defines how far from picker wheel’s centre the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small offset value may not change the picker wheel value and too high value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range [0.15, 0.3]. 0.2 by default
  1. Add the following static method in the ‘XCTestExtensions’ class to select the next or previous picker wheel value from the current value…

xcPerformActionOnAlert() Static Methods

These methods perform operations on NSAlert instance.

When we see an alert popup, it will generally always have ‘accept’ and ‘dismiss’ options available for selection, and may also optionally have other options with different labels that can be selected.  Therefore, our method should account for when there are more than the standard ‘accept’ and ‘dismiss’ options and when there are just the simple ones

xcPerformActionOnAlert(String action) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class to select a given action on a simple alert…

    Also make sure you add the following import for ‘ExpectedConditions’…

xcPerformActionOnAlert(String action, String buttonLabel) Static Method

  1. Add the following static method in the ‘XCTestExtensions’ class to select a given action on a given button label in an alert…

Note: The whole list of XCUITest specific mobile commands can be found at http://appium.io/docs/en/commands/mobile-command/#ios-xcuitest-only

WebDriver Extensions

We will begin each method name with ‘wd’ (for WebDriver).

wdHighlight() Static Method

  1. Open up the ‘WebDriverExtensions’ class in the ‘utils.extensions’ package and add the following static method for highlighting a given locator using JavaScript…
  2. You will notice that an error is thrown due to not knowing what ‘wdHighlightedColour’ is, so let’s add that in the ‘Settings’ class of the ‘utils.selenium’ package (of course you can also customise this to change the colour and size of the border etc.)…
  3. Next, go back to the ‘WebDriverExtensions’ class and add a static import for ‘wdHighlightedColour’ in the ‘Settings’ class…
  4. Of course, also check that the imports for ‘WebDriver’, ‘WebElement’, ‘JavaScriptExecutor’ and ‘By’ have been added above the class, as well as a static import again for the browser() method in the ‘Drivers’ class of the ‘utils.selenium’ package…

wdElementIsDisplayed() Static Method

  1. Open up the ‘WebDriverExtensions’ class in the ‘utils.extensions’ package and add the following static method for checking that a highlighted locator is displayed…
  2. Make sure the import for ‘WebDriverWait’ and ‘ExpectedConditions’ have been added above the class…
  3. Add a static integer variable set to a value of 10 for ‘sec’, and make it private to the class it is in, just above the weWaitForSeconds() method…

wdElementIsInvisible() Static Method

  1. Add the following static method in the ‘WebDriverExtensions’ class to wait for a given locator to not be visible…

wdFindElement() Static Method

  1. Add the following static method in the ‘WebDriverExtensions’ class to find a displayed element by its locator…

wdClick() Static Method

  1. Add the following static method in the ‘WebDriverExtensions’ class to click on an element which has been found by its locator…

wdSendKeys() Static Method

  1. Add the following static method in the ‘WebDriverExtensions’ class to wait for a given textfield element (which has been found by its locator) to be displayed, clear the textfield if necessary (if ‘clearFirst’ is true), and then input a given String into the textfield…

Refactoring our Test Scenario to use the Extensions

We can now use our extensions (static methods) to replace previous lines of code in our test methods.  Over time, this helps us follow DRY principles (Don’t Repeat Yourself) as well as make our code easier to read 🙂

‘navToPabloPicasso()’ method

  1. Edit the ‘navToPabloPicasso()’ method in the ‘BasePage’ class so it uses the meTap() static method from the ‘MobileElementExtensions’ class (you will have to add a static import to access all the static methods in the MobileElementExtensions class)…

‘viewMoreInfoGuernica()’ method

  1. Edit the ‘viewMoreInfoGuernica()’ method in the ‘BasePage’ class so it uses the meTap() static method from the ‘MobileElementExtensions’ class again (you will have to add a static import to access all the static methods in the MobileElementExtensions class)…

Running the Test Scenario

Running the Test

  1. Open up ‘BaseScenarios.feature’ file and make sure you have the ‘@Iphone8’ tag at the top of the feature file or above each test scenario you want to run
  2. Right-click on the test scenario and run it

It should pass 😀

Liked it? Take a second to support Thomas on Patreon!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.