Speed Up iOS Appium Test Automation

vector-frameworks-appium_2x

     Appium users have the question like how to speed up the iOS tests, citing the length of time it takes to start tests which use the WebDriverAgent library (all tests using the XCUITest driver).

     Most of the perceived speed of an Appium test can’t be improved due to the base speed of booting devices or the UI actions themselves. The slowest part, which users were asking how to avoid, is the initial startup of a test: the time between sending the first POST /session command and the response indicating that your test script can begin sending commands. We can call this time period the “session creation” time.

     There are desired capabilities we can specify to greatly reduce the time it takes to create a session. Appium is built to cater to a large number of devices, for use in many different situations, but we also want to make sure that it is easy to get started automating your first test. When specifying desired capabilities, Appium will analyze the state of your system and choose default values for every desired capability which you don’t specify. By being more specific, we can have Appium skip the work it does to choose the default values.

     Our first improvement is to set the app location to a file already on the host device. Then you can directly use the bundleId 

caps.setCapability(“bundleId”, “io.test.app”);

      Please ignore the remote path of your application in the code instead of that you can use the local application path, once it gets installed on the device avoid the local path and stick to use bundleId

     Running the tests, it’s easy to notice that the app gets reinstalled on the device for each test. This takes a lot of time and can be skipped. You may have certain tests which require a fresh install or need all the app data cleaned, but those tests could be put into a separate suite, leaving the majority of tests to run faster by reusing the same app. Most users should be familiar with the noReset desired capability.

 caps.setCapability(“noReset”, true)

    Appium uses the simctl command-line tool provided by Apple to match the deviceName desired capability to the udid of the device. We can skip this step by specifying the device udid ourselves.

caps.setCapability(“udid”, “009D802528AB4A1BA7C885A9F6FDBE95”);

      When loading the WedDriverAgent server, Appium loads the files from wherever XCode saved it after compilation. This location is called the “Derived Data Directory” and Appium executes an xcodebuild command in order to get the location. Below desired capability derivedDataPath allowing Appium to skip the work of calculating it:

caps.setCapability(“derivedDataPath”, “/Users/sanojs/Library/Developer/Xcode/DerivedData/WebDriverAgent-apridxpigtzdjdecthgzpygcmdkp”);

     The last optimization is to specify the webDriverAgentUrl desired capability. If specified, Appium skips a step where it checks to make sure that there are no obsolete or abandoned WebDriverAgent processes still running. The WebDriverAgent server needs to already be running at this location, so we can only use this desired capability after the first test starts the server.

caps.setCapability(“webDriverAgentUrl”, “http://localhost:8100”);

       I hope the above tips will help you to speed up the iOS automation using Appium. Please try to change your Desired Capability today to get a better speed of automation on the iOS platform.

Refer the tips to improve the speed for Android @https://journeyofquality.wordpress.com/category/speed-up-android-appium-test-automation/

Reference: Appium Pro

make it perfect!

iOS Specific Touch Gestures With Appium

Appium-for-Android-on-mac

     Nowadays the iOS automation is very popular especially doing with help of Appium. Here I would like to explain some important iOS specific touch gestures.  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.

mobile: swipe

     This command ultimately calls the XCUIElement.swipe* family of methods provided by XCUITest, and thus takes two parameters: a direction (whether to swipe up, down, left, or right), and the ID of an element within which the swipe is to take place (Appium defaults to the entire Application element if no element is specified). Following is an example,

// swipe up then down
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: scroll

     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

Following are some examples:

// scroll down then up
Map<String, Object> args = new HashMap<>();
args.put("direction", "down");
driver.executeScript("mobile: scroll", args);
args.put("direction", "up");
driver.executeScript("mobile: scroll", args);

// scroll to the last item in the list by accessibility id
args.put("direction", "down");
args.put("name", "Stratus");
driver.executeScript("mobile: scroll", args);

// scroll back to the first item in the list
MobileElement list = (MobileElement) driver.findElement(By.className("XCUIElementTypeScrollView"));
args.put("direction", "up");
args.put("name", null);
args.put("element", list.getId());
driver.executeScript("mobile: scroll", args);

mobile: pinch

     To pinch (described by a two-finger gesture where the fingers start far apart and come together) or to zoom (described by the inverse gesture where fingers start together and expand outward), use mobile: pinch, which calls XCUIElement.pinch under the hood. As with the other methods described so far, you can pass in an element parameter defining the element in which the pinch will take place (the entire application by default).

The only required parameter is scale:

  • Values between 0 and 1 refer to a “pinch”
  • Values greater than 1 refer to a “zoom”

An additional optional parameter velocity can be sent, which corresponds to “the velocity of the pinch in scale factor per second”. Following is an example:

// zoom in on something
Map<String, Object> args = new HashMap<>();
args.put("scale", 5);
driver.executeScript("mobile: pinch", args);

mobile: tap

The best way to tap on an element is using element.click(). So why do we have mobile: tap? This method allows for extra parameters x and y signifying the coordinate at which to click. 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 center. Following is an example:

// tap an element very near its top left corner
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: doubleTap

 There’s more to tapping than single-tapping! And while you can certainly build a double-tap option using the Actions API, XCUITest provides a XCUIElement.doubleTap method for this purpose, and it could presumably have greater reliability than synthesizing your own action. In terms of parameters, you should send in either an element parameter, with the ID of the element you want to tap, or both an x and y value representing the screen coordinate you wish to tap. Following is an example:

// 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: twoFingerTap

    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). Following is an example:

// 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: touchAndHold

    Many iOS apps allow a user to trigger special behavior 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. Following is an example:

// 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: dragFromToForDuration

     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. Really, what’s going on 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. Following are the required parameters:

  • 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

Following is an example:

// 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);

Please try to practice all the touch gestured during your iOS automation using Appium.

Reference: Appium Pro

make it perfect !

Speed Up Android Appium Test Automation

android-automation

      There are three special capabilities available in Appium for speeding up Android test initialization (available in the latest Appium version). Also using the appPackage and appActivity desired capabilities instead of the app capability helps for speeding up Android test automation.

  1. skipDeviceInitialization
  2. skipServerInstallation
  3. ignoreUnimportantViews

     skipDeviceInitialization is available for all Android platforms, this desired capability can be passed with the boolean value true to skip installing the io.appium.settings app on the device. This special app is installed by the Appium Android Driver at the beginning of each test and is used to manage specific settings on the device, such as:

  • Wifi/data settings
  • Disabling animation
  • Setting a locale
  • IME settings

Without the io.appium.settings app, the Appium Android driver cannot automate these functions, but if the device previously had this app installed by Appium, it doesn’t need to install it again. If you know that your device is already in the proper state then you can set skipDeviceInitialization to true and skip the time it takes to reinstall it. Appium already checks if the settings app is already installed on the device, but with this capability enabled it even skips the check to see if the app is installed.

     skipServerInstallation desired capability only applies when using the UiAutomator2 automation method. The way the UIAutomator2 driver works, it installs a special server onto the device, which listens to test commands from Appium and executes them. By default, Appium installs this server onto the device at the beginning of every test session. If the value of skipServerInstallation is set to true, you can skip the time it takes to install this server. Of course, without the server on the device Appium can’t automate it, but if you know that the server was installed during a previous test run you can safely skip this step.

   ignoreUnimportantViews desired capability is not new, but it deserves to be mentioned as another way to potentially speed up Android automation tests, especially if your tests focus on finding many elements using XPath locators. Set this to true to speed up Appium’s ability to find elements in Android apps.

     Another major time-saver when it comes to Android tests is using the appPackage and appActivity desired capabilities instead of the app capability. We need to tell Appium which app to test. Usually we use the app capability, which can be a path to a .apk, .apks, or .zip file stored on your computer’s filesystem or stored on a public website. If the app under test is known to already be installed on the device (most likely from a previous test run), the app package name and main activity can be passed instead (using appPackage and appActivity desired capabilities). Skipping the time to download a large file or install it on the Android operating system leads to big savings.

Below is the sample code which explain how can we use it in your automation script:

DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability(“platformName”, “Android”);
caps.setCapability(“deviceName”, “Android Emulator”);
caps.setCapability(“automationName”, “UiAutomator2”);
// App is already installed on device, so can be launched by Package name and Activity
caps.setCapability(“appPackage”, “io.cloudgrey.the_app”);
caps.setCapability(“appActivity”, “io.cloudgrey.the_app.MainActivity”);
// Skip the installation of io.appium.settings app and the UIAutomator 2 server.
caps.setCapability(“skipDeviceInitialization”, true);
caps.setCapability(“skipServerInstallation”, true);
caps.setCapability(“ignoreUnimportantViews”, true);
driver = new AppiumDriver(new URL(“http://localhost:4723/wd/hub&#8221;), caps);

Try to practice the above mentioned methods in your Android Automation and feel the difference in execution speed.

Reference: Appium Pro

make it perfect !

Automating Voice Commands With Siri

iphone-6s-siri

     It’s very common with modern mobile devices to rely on virtual “assistants” to get tasks done, whether in a hands-free situation utilizing voice commands, or just to save the trouble of tapping out search queries. On iOS these interactions take place through the Siri interface.

Hey Siri

     How on earth would you test this aspect of your app’s behavior? Ideally you’d be able to have a recording of the particular voice command or phrase used to trigger your app’s Siri integration, which you could then somehow apply to the simulator or device under test. This is not currently possible, outside of rigging up some speakers!

     Fortunately, Appium has recently added a command (as of Appium 1.10.0), that lets you specify the text you want Siri to parse, as if it had been spoken by a person.

The command itself is accessible via the executeScript “mobile” interface:

HashMap<String, String> args = new HashMap<>();
args.put(“text”, “Hey Siri, what’s happening?”);
driver.executeScript(“mobile: siriCommand”, args);

     Essentially, we construct an options hash with our desired text string, and pass it to the siriCommand “mobile” method. We can run this command at any point in our automation, and it will take care of getting to the Siri prompt for us as well (we don’t need to long-hold the home button).

     At this point we can use the typical native automation methods to verify Siri’s response on the screen, tap on action items, etc…

     That’s basically it! There’s not much to it. So let’s have a look at a full example that asks Siri a math question (What’s two plus two?) and verifies the result (notice how the result text shows up as accessibility IDs, which found by looking at the page source).

@Test
public void testSiriTalk() {
HashMap<String, String> args = new HashMap<>();
args.put(“text”, “What’s two plus two?”);
driver.executeScript(“mobile: siriCommand“, args);
wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId(“2 + 2 =”)));
wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId(“4”)));}

     You have to use java-client version as 6.1.0 and Appium server version as 1.10.0. Try to use above sample test case to see what exactly automating voice command with Siri.

Reference: Appium Pro

make it perfect !

AI for Appium Test Automation

Capture

     Perhaps the most buzzy of the buzzwords in tech these days is “AI” (Artificial Intelligence), or “AI/ML” (throwing in Machine Learning). To most of us, these phrases seem like magical fairy dust that promises to make the hard parts of our tech jobs go away. To be sure, AI is largely over-hyped, or at least its methods and applications are largely misunderstood and therefore assumed to be much more magical than they are.

         How you can use AI with Appium! It’s a bit surprising, but the Appium project has developed an AI-powered element finding plugin for use specifically with Appium.

          First, let’s discuss element finding plugin. In a recent addition to Appium, added the ability for third-party developers to create “plugins” for Appium that can use an Appium driver together with their own unique capabilities to find elements. As we’ll see below, users can access these plugins simply by installing the plugin as an NPM module in their Appium directory, and then using the customFindModules capability to register the plugin with the Appium server.

       The first plugin worked on within this new structure was one that incorporates a machine learning model from Test.ai designed to classify app icons, the training data for which was just open-sourced. This is a model which can tell us, given the input of an icon, what sort of thing the icon represents (for example, a shopping cart button, or a back arrow button). The application we developed with this model was the Appium Classifier Plugin, which conforms to the new element finding plugin format.

      Basically, we can use this plugin to find icons on the screen based on their appearance, rather than knowing anything about the structure of our app or needing to ask developers for internal identifiers to use as selectors. For the time being the plugin is limited to finding elements by their visual appearance, so it really only works for elements which display a single icon. Luckily, these kinds of elements are pretty common in mobile apps.

         This approach is more flexible than existing locator strategies (like accessibility id, or image) in many cases, because the AI model is trained to recognize icons without needing any context, and without requiring them to match only one precise image style. What this means is that using the plugin to find a “cart” icon will work across apps and across platforms, without needing to worry about minor differences.

         So let’s take a look at a concrete example, demonstrating the simplest possible use case. If you fire up an iOS simulator you have access to the Photos application, which looks something like this:

The Photos app with search icon

        Notice the little magnifying glass icon near the top which, when clicked, opens up a search bar:

The Photos app with search bar and cancel text

             Let’s write a test that uses the new plugin to find and click that icon. First, we need to follow the setup instructions to make sure everything will work. Then, we can set up our Desired Capabilities for running a test against the Photos app:

DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "iOS");
        caps.setCapability("platformVersion", "11.4");
        caps.setCapability("deviceName", "iPhone 6");
        caps.setCapability("bundleId", "com.apple.mobileslideshow"); 

Now we need to add some new capabilities: customFindModules (to tell Appium about the AI plugin we want to use), and shouldUseCompactResponses (because the plugin itself told us we need to set this capability in its setup instructions):

HashMap<String, String> customFindModules = new HashMap<>();
      customFindModules.put("ai", "test-ai-classifier");
      caps.setCapability("customFindModules", customFindModules);
      caps.setCapability("shouldUseCompactResponses", false); 

         You can see that customFindModules is a capability which has some internal structure: in this case “ai” is the shortcut name for the plugin that we can use internally in our test, and “test-ai-classifier” is the fully-qualified reference that Appium will need to be able to find and require the plugin when we request elements with it.

Once we’ve done all this, finding the element is super simple:

driver.findElement(MobileBy.custom("ai:search")); 

           Here we’re using a new custom locator strategy so that Appium knows we want a plugin, not one of its supported locator strategies. Then, we’re prefixing our selector with ai: to let Appium know which plugin specifically we want to use for this request (because there could be multiple). Of course since we are in fact only using one plugin for this test, we could do away with the prefix (and for good measure we could use the different find command style, too):

driver.findElementByCustom("search");

           And that’s it! As mentioned above, this technology has some significant limitations at the current time, for example that it can really only reliably find elements which are one of the icons that the model has been trained to detect. On top of that, the process is fairly slow, both in the plugin code (since it has to retrieve every element on screen in order to send information into the model), and in the model itself. All of these areas will see improvement in the future, however. And even if this particular plugin isn’t useful for your day-to-day, it demonstrates that concrete applications of AI in the testing space are not only possible, but actual!

Please try to implement above mentioned AI component in your automation script.

make it perfect !

Reference: Appium Pro