Mobile App Testing Archives - Automated Visual Testing | Applitools https://applitools.com/blog/tag/mobile-app-testing/ Applitools delivers the next generation of test automation powered by AI assisted computer vision technology known as Visual AI. Fri, 01 Dec 2023 18:25:40 +0000 en-US hourly 1 Mobile Testing for the First Time with Android, Appium, and Applitools https://applitools.com/blog/mobile-testing-android-appium-applitools/ Thu, 21 Jul 2022 16:41:51 +0000 https://applitools.com/?p=40910 Learn how to get started with mobile testing using Android and Appium, and then how to incorporate native mobile visual testing using Applitools.

The post Mobile Testing for the First Time with Android, Appium, and Applitools appeared first on Automated Visual Testing | Applitools.

]]>

For some of us, it’s hard to believe how long smartphones have existed. I remember when the first iPhone came out in June 2007. I was working at my first internship at IBM, and I remember hearing in the breakroom that someone on our floor got one. Oooooooh! So special! That was 15 years ago!

In that decade and a half, mobile devices of all shapes and sizes have become indispensable parts of our modern lives: The first thing I do every morning when I wake up is check my phone. My dad likes to play Candy Crush on his tablet. My wife takes countless photos of our French bulldog puppy on her phone. Her mom uses her tablet for her virtual English classes. I’m sure, like us, you would feel lost if you had to go a day without your device.

It’s vital for mobile apps to have high quality. If they crash, freeze, or plain don’t work, then we can’t do the things we need to do. So, being the Automation Panda, I wanted to give mobile testing a try! I had three main goals:

  1. Learn about mobile testing for Android – specifically how it relates to other kinds of testing.
  2. Automate my own Appium tests – not just run someone else’s examples.
  3. Add visual assertions to my tests with Applitools – instead of coding a bunch of checks with complicated locators.

This article covers my journey. Hopefully, it can help you get started with mobile testing, too! Let’s jump in.

Getting Started with Mobile

The mobile domain is divided into two ecosystems: Android and iOS. That means any app that wants to run on both operating systems must essentially have two implementations. To keep things easier for me, I chose to start with Android because I already knew Java and I actually did a little bit of Android development a number of years ago.

I started by reading a blog series by Gaurav Singh on getting started with Appium. Gaurav’s articles showed me how to set up my workbench and automate a basic test:

  1. Hello Appium, Part 1: What is Appium? An Introduction to Appium and its Tooling
  2. Hello Appium, Part 2: Writing Your First Android Test
  3. Appium Fast Boilerplate GitHub repository

Test Automation University also has a set of great mobile testing courses that are more than a quickstart guide:

Choosing an Android App

Next, I needed an Android app to test. Thankfully, Applitools had the perfect app ready: Applifashion, a shoe store demo. The code is available on GitHub at https://github.com/dmitryvinn/applifashion-android-legacy.

To do Android development, you need lots of tools:

I followed Gaurav’s guide to a T for setting these up. I also had to set the ANDROID_HOME environment variable to the SDK path.

Be warned: it might take a long time to download and install these tools. It took me a few hours and occupied about 13 GB of space!

Once my workbench was ready, I opened the Applifashion code in Android Studio, created a Pixel 3a emulator in Device Manager, and ran the app. Here’s what it looked like:

The Applifashion main page

An Applifashion product page

I chose to use an emulator instead of a real device because, well, I don’t own a physical Android phone! Plus, managing a lab full of devices can be a huge hassle. Phone manufacturers release new models all the time, and phones aren’t cheap. If you’re working with a team, you need to swap devices back and forth, keep them protected from theft, and be careful not to break them. As long as your machine is powerful and has enough storage space, you can emulate multiple devices.

Choosing Appium for Testing

It was awesome to see the Applifashion app running through Android Studio. I played around with scrolling and tapping different shoes to open their product pages. However, I really wanted to do some automated testing. I chose to use Appium for automation because its API is very similar to Selenium WebDriver, with which I am very familiar.

Appium adds on its own layer of tools:

Again, I followed Gaurav’s guide for full setup. Even though Appium has bindings for several popular programming languages, it still needs a server for relaying requests between the client (e.g., the test automation) and the app under test. I chose to install the Appium server via the NPM module, and I installed version 1.22.3. Appium Doctor gave me a little bit of trouble, but I was able to resolve all but one of the issues it raised, and the one remaining failure regarding ANDROID_HOME turned out to be not a problem for running tests.

Before jumping into automation code, I wanted to make sure that Appium was working properly. So, I built the Applifashion app into an Android package (.apk file) through Android Studio by doing BuildBuild Bundle(s) / APK(s)Build APK(s). Then, I configured Appium Inspector to run this .apk file on my Pixel 3a emulator. My settings looked like this:

My Appium Inspector configuration for targeting the Applifashion Android package in my Pixel 3a emulator (click for larger image)

Here were a few things to note:

  • The Appium server and Android device emulator were already running.
  • I used the default remote host (127.0.0.1) and remote port (4723).
  • Since I used Appium 1.x instead of 2.x, the remote path had to be /wd/hub.
  • appium: automationName had to be uiautomator2 – it could not be an arbitrary name.
  • The platform version, device name, and app path were specific to my environment. If you try to run this yourself, you’ll need to set them to match your environment.

I won’t lie – I needed a few tries to get all my capabilities right. But once I did, things worked! The app appeared in my emulator, and Appium Inspector mirrored the page from the emulator with the app source. I could click on elements within the inspector to see all their attributes. In this sense, Appium Inspector reminded me of my workflow for finding elements on a web page using Chrome DevTools. Here’s what it looked like:

The Appium Inspector with the Applifashion app loaded

Writing my First Appium Test

So far in my journey, I had done lots of setup, but I hadn’t yet automated any tests! Mobile testing certainly required a heftier stack than web app testing, but when I looked at Gaurav’s example test project, I realized that the core concepts were consistent.

I set up my own Java project with JUnit, Gradle, and Appium:

  • I chose Java to match the app’s code.
  • I chose JUnit to be my core test framework to keep things basic and familiar.
  • I chose Gradle to be the dependency manager to mirror the app’s project.

My example code is hosted here: https://github.com/AutomationPanda/applitools-appium-android-webinar.

Warning: The example code I share below won’t perfectly match what’s in the repository. Furthermore, the example code below will omit import statements for brevity. Nevertheless, the code in the repository should be a full, correct, executable example.

My build.gradle file looked like this with the required dependencies:

plugins {
    id 'java'
}

group 'com.automationpanda'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    testImplementation 'io.appium:java-client:8.1.1'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testImplementation 'org.seleniumhq.selenium:selenium-java:4.2.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}

test {
    useJUnitPlatform()
}

My test case class was located at /src/test/java/com/automationpanda/ApplifashionTest.java. Inside the class, I had two instance variables: the Appium driver for mobile interactions, and a WebDriver waiting object for synchronization:

public class ApplifashionTest {

    private AppiumDriver driver;
    private WebDriverWait wait;

    // …
}

I added a setup method to initialize the Appium driver. Basically, I copied all the capabilities from Appium Inspector:

    @BeforeEach
    public void setUpAppium(TestInfo testInfo) throws IOException {

        // Create Appium capabilities
        // Hard-coding these values is typically not a recommended practice
        // Instead, they should be read from a resource file (like a properties or JSON file)
        // They are set here like this to make this example code simpler
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("platformName", "android");
        capabilities.setCapability("appium:automationName", "uiautomator2");
        capabilities.setCapability("appium:platformVersion", "12");
        capabilities.setCapability("appium:deviceName", "Pixel 3a API 31");
        capabilities.setCapability("appium:app", "/Users/automationpanda/Desktop/Applifashion/main-app-debug.apk");
        capabilities.setCapability("appium:appPackage", "com.applitools.applifashion.main");
        capabilities.setCapability("appium:appActivity", "com.applitools.applifashion.main.activities.MainActivity");
        capabilities.setCapability("appium:fullReset", "true");

        // Initialize the Appium driver
        driver = new AppiumDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
        wait = new WebDriverWait(driver, Duration.ofSeconds(30));
    }

I also added a cleanup method to quit the Appium driver after each test:

    @AfterEach
    public void quitDriver() {
        driver.quit();
    }

I wrote one test case that performs shoe shopping. It loads the main page and then opens a product page using locators I found with Appium Inspector:

    @Test
    public void shopForShoes() {

        // Tap the first shoe
        final By shoeMainImageLocator = By.id("com.applitools.applifashion.main:id/shoe_image");
        wait.until(ExpectedConditions.presenceOfElementLocated(shoeMainImageLocator));
        driver.findElement(shoeMainImageLocator).click();

        // Wait for the product page to appear
        final By shoeProductImageLocator = By.id("com.applitools.applifashion.main:id/shoe_image_product_page");
        wait.until(ExpectedConditions.presenceOfElementLocated(shoeProductImageLocator));
    }

At this stage, I hadn’t written any assertions yet. I just wanted to see if my test could successfully interact with the app. Indeed, it could, and the test passed when I ran it! As the test ran, I could watch it interact with the app in the emulator.

Adding Visual Assertions

My next step was to write assertions. I could have picked out elements on each page to check, but there were a lot of shoes and words on those pages. I could’ve spent a whole afternoon poking around for locators through the Appium Inspector and then tweaking my automation code until things ran smoothly. Even then, my assertions wouldn’t capture things like layout, colors, or positioning.

I wanted to use visual assertions to verify app correctness. I could use the Applitools SDK for Appium in Java to take one-line visual snapshots at the end of each test method. However, I wanted more: I wanted to test multiple devices, not just my Pixel 3a emulator. There are countless Android device models on the market, and each has unique aspects like screen size. I wanted to make sure my app would look visually perfect everywhere.

In the past, I would need to set up each target device myself, either as an emulator or as a physical device. I’d also need to run my test suite in full against each target device. Now, I can use Applitools Native Mobile Grid (NMG) instead. NMG works just like Applitools Ultrafast Grid (UFG), except that instead of browsers, it provides emulated Android and iOS devices for visual checkpoints. It’s a great way to scale mobile test execution. In my Java code, I can set up Applitools Eyes to upload results to NMG and run checkpoints against any Android devices I want. I don’t need to set up a bunch of devices locally, and the visual checkpoints will run much faster than any local Appium reruns. Win-win!

To get started, I needed my Applitools account. If you don’t have one, you can register one for free.

Then, I added the Applitools Eyes SDK for Appium to my Gradle dependencies:

   testImplementation 'com.applitools:eyes-appium-java5:5.12.0'

I added a “before all” setup method to ApplifashionTest to set up the Applitools configuration for NMG. I put this in a “before all” method instead of a “before each” method because the same configuration applies for all tests in this suite:

    private static InputReader inputReader;
    private static Configuration config;
    private static VisualGridRunner runner;

    @BeforeAll
    public static void setUpAllTests() {

        // Create the runner for the Ultrafast Grid
        // Warning: If you have a free account, then concurrency will be limited to 1
        runner = new VisualGridRunner(new RunnerOptions().testConcurrency(5));

        // Create a configuration for Applitools Eyes
        config = new Configuration();

        // Set the Applitools API key so test results are uploaded to your account
        config.setApiKey("<insert-your-API-key-here>");

        // Create a new batch
        config.setBatch(new BatchInfo("Applifashion in the NMG"));

        // Add mobile devices to test in the Native Mobile Grid
        config.addMobileDevices(
                new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S21),
                new AndroidDeviceInfo(AndroidDeviceName.Galaxy_Note_10),
                new AndroidDeviceInfo(AndroidDeviceName.Pixel_4));
    }

The configuration for NMG was almost identical to a configuration for UFG. I created a runner, and I created a config object with my Applitools API key, a batch name, and all the devices I wanted to target. Here, I chose three different phones: Galaxy S21, Galaxy Note 10, and Pixel 4. Currently, NMG supports 18 different Android devices, and support for more is coming soon.

At the bottom of the “before each” method, I added code to set up the Applitools Eyes object for capturing snapshots:

    private Eyes eyes;

    @BeforeEach
    public void setUpAppium(TestInfo testInfo) throws IOException {

        // …

        // Initialize Applitools Eyes
        eyes = new Eyes(runner);
        eyes.setConfiguration(config);
        eyes.setIsDisabled(false);
        eyes.setForceFullPageScreenshot(true);

        // Open Eyes to start visual testing
        eyes.open(driver, "Applifashion Mobile App", testInfo.getDisplayName());
    }

Likewise, in the “after each” cleanup method, I added code to “close eyes,” indicating the end of a test for Applitools:

    @AfterEach
    public void quitDriver() {

        // …

        // Close Eyes to tell the server it should display the results
        eyes.closeAsync();
    }

Finally, I added code to each test method to capture snapshots using the Eyes object. Each snapshot is a one-line call that captures the full screen:

    @Test
    public void shopForShoes() {

        // Take a visual snapshot
        eyes.check("Main Page", Target.window().fully());

        // Tap the first shoe
        final By shoeMainImageLocator = By.id("com.applitools.applifashion.main:id/shoe_image");
        wait.until(ExpectedConditions.presenceOfElementLocated(shoeMainImageLocator));
        driver.findElement(shoeMainImageLocator).click();

        // Wait for the product page to appear
        final By shoeProductImageLocator = By.id("com.applitools.applifashion.main:id/shoe_image_product_page");
        wait.until(ExpectedConditions.presenceOfElementLocated(shoeProductImageLocator));

        // Take a visual snapshot
        eyes.check("Product Page", Target.window().fully());
    }

When I ran the test with these visual assertions, it ran one time locally, and then NMG ran each snapshot against the three target devices I specified. Here’s a look from the Applitools Eyes dashboard at some of the snapshots it captured:

My first visual snapshots of the Applifashion Android app using Applitools Native Mobile Grid!

The results are marked “New” because these are the first “baseline” snapshots. All future checkpoints will be compared to these images.

Another cool thing about these snapshots is that they capture the full page. For example, the main page will probably display only 2-3 rows of shoes within its viewport on a device. However, Applitools Eyes effectively scrolls down over the whole page and stitches together the full content as if it were one long image. That way, visual snapshots capture everything on the page – even what the user can’t immediately see!

The full main page for the Applifashion app, fully scrolled and stitched

Injecting Visual Bugs

Capturing baseline images is only the first step with visual testing. Tests should be run regularly, if not continuously, to catch problems as soon as they happen. Visual checkpoints should point out any differences to the tester, and the tester should judge if the change is good or bad.

I wanted to try this change detection with NMG, so I reran tests against a slightly broken “dev” version of the Applifashion app. Can you spot the bug?

The “main” version of the Applifashion product page compared to a “dev” version

The formatting for the product page was too narrow! “Traditional” assertions would probably miss this type of bug because all the content is still on the page, but visual assertions caught it right away. Visual checkpoints worked the same on NMG as they would on UFG or even with the classic (e.g. local machine) Applitools runner.

When I switched back to the “main” version of the app, the tests passed again because the visuals were “fixed:”

Applifashion tests marked as “passed” after fixing visual bugs

While running all these tests, I noticed that mobile test execution is pretty slow. The one test running on my laptop took about 45 seconds to complete. It needed time to load the app in the emulator, make its interactions, take the snapshots, and close everything down. However, I also noticed that the visual assertions in NMG were relatively fast compared to my local runs. Rendering six snapshots took about 30 seconds to complete – three times the coverage in significantly less time. If I had run tests against more devices in parallel, I could probably have seen an even greater coverage-to-time ratio.

Conclusion

My first foray into mobile testing was quite a journey. It required much more tooling than web UI testing, and setup was trickier. Overall, I’d say testing mobile is indeed more difficult than testing web. Thankfully, the principles of good test automation were the same, so I could still develop decent tests. If I were to add more tests, I’d create a class for reading capabilities as inputs from environment variables or resource files, and I’d create another class to handle Applitools setup.

Visual testing with Applitools Native Mobile Grid also made test development much easier. Setting everything up just to start testing was enough of a chore. Coding the test cases felt straightforward because I could focus my mental energy on interactions and take simple snapshots for verifications. Trying to decide all the elements I’d want to check on a page and then fumbling around the Appium Inspector to figure out decent locators would multiply my coding time. NMG also enabled me to run my tests across multiple different devices at the same time without needing to pay hundreds of dollars per device or sucking up a few gigs of storage and memory on my laptop. I’m excited to see NMG grow with support for more devices and more mobile development frameworks in the future.

Despite the prevalence of mobile devices in everyday life, mobile testing still feels far less mature as a practice than web testing. Anecdotally, it seems that there are fewer tools and frameworks for mobile testing, fewer tutorials and guides for learning, and fewer platforms that support mobile environments well. Perhaps this is because mobile test automation is an order of magnitude more difficult and therefore more folks shy away from it. There’s no reason for it to be left behind anymore. Given how much we all rely on mobile apps, the risks of failure are just too great. Technologies like Visual AI and Applitools Native Mobile Grid make it easier for folks like me to embrace mobile testing.

The post Mobile Testing for the First Time with Android, Appium, and Applitools appeared first on Automated Visual Testing | Applitools.

]]>
Modern Cross Device Testing for Android & iOS Apps https://applitools.com/blog/cross-device-testing-mobile-apps/ Wed, 13 Jul 2022 20:47:15 +0000 https://applitools.com/?p=40383 Learn the cross device testing practices you need to implement to get closer to Continuous Delivery for native mobile apps.

The post Modern Cross Device Testing for Android & iOS Apps appeared first on Automated Visual Testing | Applitools.

]]>

Learn the cross device testing practices you need to implement to get closer to Continuous Delivery for native mobile apps.

What is Cross Device Testing

Modern cross device testing is the system by which you verify that an application delivers the desired results on a wide variety of devices and formats. Ideally this testing will be done quickly and continuously.

There are many articles explaining how to do CI/CD for web applications, and many companies are already doing it successfully, but there is not much information available out there about how to achieve the same for native mobile apps.

This post will shed light on the cross device testing practices you need to implement to get a step closer to Continuous Delivery for native mobile apps.

Why is Cross Device Testing Important

The number of mobile devices used globally is staggering. Based on the data from bankmycell.com, we have 6.64 billion smartphones in use.

Source: https://www.bankmycell.com/blog/how-many-phones-are-in-the-world#part-1

Even if we are building and testing an app which impacts a fraction of this number, that is still a very huge number.

The below chart shows the market share by some leading smartphone vendors over the years.

Source: https://www.statista.com/statistics/271496/global-market-share-held-by-smartphone-vendors-since-4th-quarter-2009/

Challenges of Cross Device Testing

One of the biggest challenges for testing mobile apps is that across all manufacturers combined, there are 1000s of device types in use today. Depending on the popularity of your app, this means there are a huge number of devices your users could be using. 

These devices will have variations based on:

  • OS types and versions
  • potentially customized OS
  • hardware resources (memory, processing power, etc.)
  • screen sizes
  • screen resolutions
  • storage with different available capacity for each
  • Wifi Vs using mobile data (from different carriers)
  • And many more

It is clear that you cannot run our tests on each type of device that may be used by your users. 

So how do you get quick feedback and confidence from your testing that (almost) no user will get impacted negatively when you release a new version of your app?

Mobile Test Automation Execution Strategy

Mobile Testing Strategy

Before we think about the strategy for running your automated tests for mobile apps, we need to have a good and holistic mobile testing strategy

Along with testing the app functionality, mobile testing has additional dimensions, and hence complexities as compared with web-app testing. 

You need to understand the impact of the aspects mentioned above and see what may, or may not be applicable to you.

Here are some high-level aspects to consider in your mobile testing strategy:

  • Know where and how to run the tests – real devices, emulators / simulators available locally versus in some cloud-based device farm
  • Increasing test coverage by writing less code – using Applitools Visual AI to validate functionality and user-experience
  • Scaling your test execution – using Applitools Native Mobile Grid
  • Testing on different text fonts and display densities 
  • Testing for accessibility conformance and impact of dark mode on functionality and user experience
  • Chaos & Monkey Testing
  • Location-based testing
  • Testing the impact of Network bandwidth
  • Planning and setting up the release strategy for your mobile application including beta-testing, on-field testing, staged-rollouts. This differs for Google PlayStore and Apple
  • Building and testing for Observability & Analytics events

Once you have figured out your Mobile Testing Strategy, you now need to think about how and what type of automated tests can give you good, reliable, deterministic and fast feedback about the quality of your apps. This will result in you identifying the different layers of your test automation pyramid.

Remember: It is very important to execute all types of automated tests, on every code change and new app that is built. The functional / end-2-end / UI tests for your app should also be run at this time.

Additionally, you need to be able to run the tests on a local developer / qa machine, as well in your Continuous Integration (CI) system. In case of native / hybrid mobile apps, developers and QAs should be able to install the app on the (local) devices they have available with them, and run the tests against that. For CI-based execution, you need to have some form of device farm available locally in your network, or cloud-based to allow execution of the tests.

This continuous testing approach will provide you with quick feedback and allow you to fix issues almost as soon as they creep in the app. 

How to Run Functional Tests against Your Mobile Apps

Testing and automating mobile apps have additional complexities. You need to install the app in some device before your automated tests can be run against it.

Let’s explore your options for devices.

Real Devices

Real devices are ideal to run the tests. Your users / customers are going to use your app using a variety of real devices. 

In order to allow proper development and testing to be done, each team member needs access to relevant types of devices (which is subject to their user-base).

However, it is not as easy to have a variety of devices available for running the automated tests, for each team member (developer / tester). 

The challenges of having the real devices could be related to:

  • cost of procuring devices for each team member of a good variety to allow seamless development and testing work. 
  • maintenance of the devices (OS/software updates, battery issues, other problems the device may have at any point in time, etc.)
  • logistical issues like time to order and get devices, tracking of the devices assigned to the team, etc.
  • deprecating / disposing the older devices that are not used / required anymore.

Hence we need a different strategy for executing tests on mobile devices. Emulators and Simulators come to the rescue!

What is the Difference between Emulators & Simulators

Before we get into specifics about the execution strategy, it is good to understand the differences between an emulator and simulator.

Android-device emulators and iOS-device simulators make it easy for any team member to easily spin up a device.

An emulator is hardware or software that enables one computer system (called the host) to behave like another computer system (called the guest). An emulator typically enables the host system to run software or use peripheral devices designed for the guest system

An emulator can mimic the operating system, software and the hardware features of the android device.

A Simulator runs on your Mac and behaves like a standard Mac app while simulating iPhone, iPad, Apple Watch, or Apple TV environments. Each combination of a simulated device and software version is considered its own simulation environment, independent of the others, with its own settings and files. These settings and files exist on every device you test within a simulation environment. 

An iOS simulator mimics the internal behavior of the device. It cannot mimic the OS / hardware features of the device.

Emulators / Simulators are a great and cost-effective way to overcome the challenges of real devices. These can easily be created as per the requirements and needs by any team member and can be used for testing and also running automated tests. You can also relatively easily set up and use the emulators / simulators in your CI execution environment.

While emulators / simulators may seem like they will solve all the problems, that is not the case. Like with anything, you need to do a proper evaluation and figure out when to use real devices versus emulators / simulators.

Below are some guidelines that I refer to.

When to use Emulators / Simulators

  • You are able to validate all application functionality
  • There is no performance impact on the application-under-test

Why use Emulators / Simulators

  • To reduce cost
  • Scale as per needs, resulting in faster feedback
  • Can use in CI environment as well

When to use Real Devices for Testing

  • If Emulators / Simulators are used, then run “Sanity” / focussed testing on real devices before release
  • If Emulators / Simulators cannot validate all application functionality reliably, then invest in Real-Device testing
  • If Emulators / Simulators cause performance issues or slowness of interactions with the application-under-test

Cases when Emulators / Simulators May not Help

  • If the application-under-test has streaming content, or has high resource requirements
  • Applications relying on hardware capabilities
  • Applications dependent on customized OS version

Cross-Device Test Automation Strategy

The above approach of using real-devices or emulators / simulators will help your team to  shift-left and achieve continuous testing. 

There is one challenge that still remains – scaling! How do you ensure your tests run correctly on all supported devices?

A classic, or rather, a traditional way to solve this problem is to repeat the automated test execution on a carefully chosen variety of devices. This would mean, if you have 5 important types of devices, and you have a 100 tests automated, then you are essentially running 500 tests. 

This approach has multiple disadvantages:

  1. The feedback cycle is substantially delayed. If 100 tests took 1 hour to complete on 1 device, 500 tests would take 5 hours (for 5 devices). 
  2. The time to analyze the test results increases by 5x 
  3. The added number of tests could have flaky behavior based on device setup / location, network issues. This could result in re-runs or specific manual re-testing for validation.
  4. You need 5x more test data
  5. You are putting 5x more load on your backend systems to cater to executing the same test 5 times

We all know these disadvantages, however, there is no better way to overcome this. Or, is there?

Modern Cross-Device Device Test Automation Strategy

The Applitools Native Mobile Grid for Android and iOS apps can easily help you to overcome the disadvantages of traditional cross-device testing.

It does this by running your test on 1 device, but getting the execution results from all the devices of your choice, automatically. Well, almost automatically. This is how the Applitools Native Mobile Grid works:

  1. Integrate Applitools SDK in your functional automation.
  2. In the Applitools Eyes configuration, specify all the devices you want to do your functional testing. Added bonus, you will be able to leverage the Applitools Visual AI capabilities to also get increased functional and visual test coverage.

Below is an example of how to specify Android devices for Applitools Native Mobile Grid:

Configuration config = eyes.getConfiguration(); //Configure the 15 devices we want to validate asynchronously
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S9, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S9_Plus, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S8, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S8_Plus, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Pixel_4, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_Note_8, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_Note_9, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_Note_10, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_Note_10_Plus, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S10_Plus, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S20, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S20_PLUS, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S21, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S21_PLUS, ScreenOrientation.PORTRAIT));
config.addMobileDevice(new AndroidDeviceInfo(AndroidDeviceName.Galaxy_S21_ULTRA, ScreenOrientation.PORTRAIT));
eyes.setConfiguration(config);

Below is an example of how to specify iOS devices for Applitools Native Mobile Grid:

Configuration config = eyes.getConfiguration(); //Configure the 15 devices we want to validate asynchronously
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11_Pro));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11_Pro_Max));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_Pro));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_Pro_Max));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_mini));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_13_Pro));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_13_Pro_Max));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_XS));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_X));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_XR));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_8));
config.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_7));
eyes.setConfiguration(config);   

  1. Run the test on any 1 device – available locally or in CI. It could be a real device or a simulator / emulator. 

Every call to Applitools to do a visual validation will automatically do the functional and visual validation for each device specified in the configuration above.

  1. See the results from all the devices in the Applitools dashboard

Advantages of using the Applitools Native Mobile Grid

The Applitools Native Mobile Grid has many advantages.

  1. You do not need to repeat the same test execution on multiple devices. This will save the team members a lot of time for execution, flaky tests and result analysis
  2. Very fast feedback of test execution across all specified devices (10x faster than traditional cross device testing approach)
  3. There is no additional test data requirements 
  4. You do not need to procure, build and maintain the devices
  5. There is less load on your application backend-system
  6. A secure solution where your application does not need to be shared out of your corporate network
  7. Using visual assertions instead of functional assertions gives you increased test coverage while writing less code

Read this post on How to Scale Mobile Automation Testing Effectively for more specific details of this amazing solution!

Summary of Modern Cross-Device Testing of Mobile Apps

Using the Applitools Visual AI allows you to extend coverage at the top of your Test Automation Pyramid by including AI-based visual testing along with your UI/UX testing. 

Using the Applitools Native Mobile Grid for cross device testing of Android and iOS apps makes your CI loop faster by providing seamless scaling across all supported devices as part of the same test execution cycle. 

You can watch my video on Mobile Testing 360deg (https://applitools.com/event/mobile-testing-360deg/) where I share many examples and details related to the above to include as part of your mobile testing strategy.

To start using the Native Mobile Grid, simply sign up at the link below to request access. You can read more about the Applitools Native Mobile Grid in our blog post or on our website.

Happy testing!

The post Modern Cross Device Testing for Android & iOS Apps appeared first on Automated Visual Testing | Applitools.

]]>
How to Scale Mobile Automation Testing Effectively https://applitools.com/blog/how-to-scale-mobile-automation-testing/ Wed, 15 Jun 2022 16:53:24 +0000 https://applitools.com/?p=39239 Learn about mobile automation testing strategies and why each is and isn't effective, and what the best way is to scale mobile automation testing today.

The post How to Scale Mobile Automation Testing Effectively appeared first on Automated Visual Testing | Applitools.

]]>

Learn the best way to scale mobile automation testing today. We’ll look at a history of traditional mobile automation testing strategies and discuss why each one is and isn’t effective, and then see why a new tool, the Native Mobile Grid, is different.

In today’s mobile testing world there are many different approaches to scaling our test automation for native mobile applications. Your options range from running locally with virtual devices (simulators/emulators) or real devices, to a local mobile grid/lab, to docker containers / virtual machines, to remote cloud test services. 

As you’re probably aware, testing native mobile applications can sometimes be a difficult endeavor. There are a lot of moving parts and many points of failure involved. To successfully execute, everything needs to work in complete harmony.  

For example, just executing a single Appium test you need:

  • An Appium server & all required dependencies installed
  • A mobile device or emulator/simulator
  • Valid test code logic
  • A compiled mobile application 
  • Application web service APIs running and stable (if applicable)

Now let’s say you want to scale your tests across multiple devices for your cross-device validation needs. We’re now introducing more points of failure for each device that is tested. A test on one device may execute just fine but on another, it may fail for various unknown reasons. We then often have to spend a vast amount of time investigating and debugging these failures to find the root cause.

Let’s also consider that because we’re adding more devices we will likely need to add more conditional logic to our test code to accommodate these different devices. We may need to add conditionals for different device resolutions/screen sizes, OS versions, orientations, scroll views, locators/selectors, or maybe gestures for specific devices. This all adds more coded logic to our test suite or framework we need to maintain and thus refactor in the future when our application changes. 

Because of these reasons and/or perhaps others, many people often don’t scale their mobile test coverage across different devices. Either it might introduce more test maintenance, more test flakiness, a longer test execution time, or access to different devices is not possible. Crossing fingers and hoping for the best has been the approach for many…

Scaling Mobile Automation Testing

Now let’s cover some common mobile test scaling approaches. I’ll go over the benefits and drawbacks of each of these approaches and finally introduce you to a new modern approach and technology, the Applitools Native Mobile Grid.

Sequential Execution

The simplest but also the most inefficient and slowest approach. The example diagram below shows executing two tests (Test A & Test B) executing across three different mobile devices.

As stated before, this is the simplest approach but very inefficient and slow. Perhaps some people aren’t aware of different or better approaches. Or maybe some bad test practices are being used such as one test (Test B) is dependent on (Test A) to complete in order to proceed. Generally, a good test practice is to never have any tests dependent on another to execute. Test suites/frameworks should be architected in a way to run any test in any order by utilizing test hooks/annotations, database seeding, mocking, or API test data injection to set up each test independently. 

For example, say I have an app that has a shopping cart and I have a test “Add items to shopping cart” which failed due to a bug in the app. If I relied on that test to then run my “shopping cart” specific tests, I couldn’t. That is where good test architecture comes into play by setting up each test independently by some of the methods mentioned above or other means.

Parallel Device Execution

We live in a fast-paced CI/CD world these days, and feedback loops that are as fast as possible are crucial. So what can you do to help get this test feedback ASAP? Parallelization! 

In this scenario, we are parallelizing the devices needed for cross-device validation. It’s however still inefficient since the tests themselves are running sequentially. But still much better than the former sequential approach.

Parallel Test Execution

This approach to mobile automation testing is a bit more efficient as it’s parallelizing the tests in your test suite. Ultimately it should reduce the execution time and also promote good test practices keeping tests independent from one another to execute. However, the inefficiency now is that each device is sequentially tested. 

Parallel Test & Parallel Device Execution

This is the most efficient and fastest traditional approach as it parallelizes both your test suite and devices for cross-device validations. However, it comes at a cost of machine resources, cloud concurrency or minutes usage on license limits (if applicable), and added complexity in your test framework having to manage different sets of parallelization. Some frameworks have this architecture “baked” into them but for many others, it’s up to the developer/tester (or whomever) to implement this logic themselves.

With that said, all of the approaches above come with but are not limited to some of the challenges below:

  • Susceptible to continual dependency and versioning conflicts. 
  • Any single device (or devices) either locally or on a cloud test service can have issues at any given time resulting in test flakiness.
  • Network or latency timeout issues can occur.
  • Service crashes or issues occurring on any running parallel process or thread.
  • Added test code complexity for parallelization.
  • Added test code conditionals to accommodate different device form factors/resolutions and application layouts. 

Applitools Native Mobile Grid

The Future Is Now!

Now that we’ve talked about the typical traditional approaches to mobile automation testing, let’s talk about the next generation of mobile cross-device testing using the Applitiools Native Mobile Grid! Our Native Mobile Grid (NMG) uses a new technological approach to asynchronously validate your native mobile application in parallel and easily across many different devices in a single execution. 

What this means is the parallelization of devices is handled on the Applitools NMG. Since it’s asynchronous you are not waiting on the device to connect or the test results, which frees your tests to execute as fast as possible! 

Some key benefits:

  • Execute your mobile tests on just one device (emulator, simulator, or a real device)! 
  • Simplistic test authoring! ​​
    • Create tests with only one device and form factor/app layout in mind! You won’t need to add additional logic in your code for different devices or resolutions.
  • Less code maintenance. 
    • No extra coded conditionals for specific devices or supporting multiple execution environments (Local and Cloud). Tests only need to work on any single device and the environment you execute in.
    • Visually Perfect with Applitools Visual AI to perform full-page mobile UI validations. No more coded UI assertion logic!
  • Fast and easy cross-device scaling without complicated multi-parallelization logic and achieve 10x faster executions compared to traditional approaches.
  • Fewer points of failure.
    • No longer is there a need to execute the same test redundantly across different devices increasing test flakiness and execution time. Instead, run once on any real device or simulator/emulator and get validations across many devices.
  • Fast CI/CD feedback loop. 
    • Release faster with an assurance of cross-device coverage and your application UI is visually perfect. 
  • No Appium version pinning.
    • Use any version of Appium that works for you and your tests.
  • Secure!
    • No need to upload an application to 3rd party cloud test vendors and risk exposing sensitive proprietary data and/or information.  
    • Tests can run locally on your network without opening firewall access or proxies.

Now let’s look at some example execution architectures using the Applitools Native Mobile Grid! 

Asynchronous Parallel Device Execution

This next diagram is similar to the traditional Parallel Device Execution we talked about above. However, the parallelization is offloaded to the NMG to handle and no additional logic for parallel threads or processes is required. This approach is still not the most efficient since each test is running sequentially but it’s lightyears faster than the traditional approach.

Asynchronous Parallel Test Execution

Out of all the approaches for mobile test automation we’ve discussed thus far, this next example is by far the most superior, efficient, and fastest approach possible to scaling your native mobile test coverage! The added benefit of this approach is your entire test suite execution time will now only take as long as it takes to run your slowest test in your suite! 

This example is similar to the traditional Parallel Test & Parallel Device Execution above but the device parallelization is now offloaded to the NMG and handled asynchronously.

Code Example using Mobile Native Grid for Mobile Test Automation

The below code is an example using Appium Java, testing an iOS native application. For those of you familiar with the Applitools Ultrafast Test Cloud for desktop and mobile web applications, this should look very similar. All we need to do in the test code is define the devices we want to validate for our cross-device coverage needs. In this case, we’ve specified 15 iOS devices we’ll validate in the same execution time as it takes to run the tests on just one device! Additional settings such as setting the OS version and orientation per device can be specified (not shown).

public class iOSNativeUFGTest {
   private WebDriverWait wait;
   private IOSDriver driver;
   private VisualGridRunner runner;
   private Eyes eyes;

   private static IOSDriver startApp() throws Exception {
       DesiredCapabilities capabilities = new DesiredCapabilities();
       capabilities.setCapability("platformName", "iOS");
       capabilities.setCapability("automationName", "XCUITest");
       capabilities.setCapability("deviceName", "iPhone 12 Pro Max"); //Launch a single local simulator or real device
       capabilities.setCapability("platformVersion", "15.4");
       capabilities.setCapability("app", "/Users/justin/Desktop/MyApp.app");
       return new IOSDriver<>(new URL("http://localhost:4723/wd/hub"), capabilities);
   }

   @Before
   public void setup() throws Exception {
       runner = new VisualGridRunner(new RunnerOptions().testConcurrency(15));
       eyes = new Eyes(runner);
       eyes.setApiKey(System.getenv("APPLITOOLS_API_KEY"));;

       Configuration conf = eyes.getConfiguration(); //Configure the 15 devices we want to validate asynchronously
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11_Pro));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11_Pro_Max));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_Pro));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_Pro_Max));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_12_mini));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_13_Pro));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_13_Pro_Max));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_XS));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_X));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_XR));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_11));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_8));
       conf.addMobileDevice(new IosDeviceInfo(IosDeviceName.iPhone_7));

       eyes.setConfiguration(conf);

       driver = startApp();
   }

   @Test
   public void iOSNativeTest() throws Exception {
       eyes.open(driver, "My Native App", "Login View"); //Start a visual test
       eyes.check("Login", Target.window().fully(true)); //Capture the mobile UI view
       eyes.closeAsync(); //End the visual test
   }

   @After
   public void tearDownTest(){
       /The /results object contains validation results on all 15 devices which can then be asserted for visual and accessibility checks
       TestResultsSummary results = runner.getAllTestResults(false); 
       eyes.abortAsync();
       driver.quit();
   }
}

Conclusion

Now for the first time ever, native mobile developers can perform continuous testing, running their entire test suites on every pull request or code push across many different devices to get immediate quality feedback at once. Just like web application developers have for many years now! 

Hopefully, this article illustrated the benefits and superiority of the Applitools Native Mobile Grid to other traditional approaches for mobile automation testing. As you now can see how simple and efficient it is to expand your cross-device coverage with the Native Mobile Grid there are no more excuses not to. So what’s stopping you?! 

How do you get started with the Native Mobile Grid you may ask? To start using the Native Mobile Grid, simply sign up at the link below to request access. You can read more about the Applitools Native Mobile Grid in our introductory blog post or on our website.

 Happy testing!

The post How to Scale Mobile Automation Testing Effectively appeared first on Automated Visual Testing | Applitools.

]]>
Introducing Applitools Native Mobile Grid https://applitools.com/blog/introducing-applitools-native-mobile-grid/ Thu, 14 Apr 2022 14:09:56 +0000 https://applitools.com/?p=36100 Last year, Applitools launched the Ultrafast Grid, the next generation of browser testing clouds for faster testing across multiple browsers in parallel. The success of the new grid with our...

The post Introducing Applitools Native Mobile Grid appeared first on Automated Visual Testing | Applitools.

]]>

Last year, Applitools launched the Ultrafast Grid, the next generation of browser testing clouds for faster testing across multiple browsers in parallel. The success of the new grid with our customer base has been nothing short of amazing, having over 200 customers using Ultrafast Grid in the last year. But our customers are hungry for more innovation and we wanted to focus on extending our Applitools Test Cloud to the next frontier: native mobile apps.

Today, Applitools is excited to announce that the Native Mobile Grid is now ready for general availability – giving companies’ engineering and QA teams access to  the next generation of cross-device testing.

For those developing native mobile apps, there are often many challenges with testing across multiple devices and orientations, resulting in a high number of bugs slipping into production. Local devices are hard to set up and owning a vast collection don’t work well across remote companies in a post-Covid world. Not to mention each different device takes a bit of custom configuration and wizardry to get running without flakiness. And mobile test frameworks are often flaky on the big cloud providers. 

Applitools Native Mobile Grid is a cloud based testing grid that allows testers and developers to automate testing of their mobile applications across different iOS and Android devices quickly, accurately, and without hassle. After running just one test locally, the Applitools Native Mobile Grid will asynchronously run the tests in parallel using Visual AI, speeding up total execution tremendously and reducing flakiness. We’ve seen test time reduce by over 80% when run against other popular testing clouds.

The Benefits Of The Native Mobile Grid

Faster Test Execution, Broad Coverage

With access to over 40 devices, Applitools revolutionary async parallel test execution can reduce testing time by up to 90% compared to traditional device clouds while still expanding coverage over that single device you’ve been testing with.

Less Test Flakiness

Visual AI helps power Applitools industry leading stability and reliability, with flakiness and false positives reduced by 99%.

More Bugs Caught

Testing faster, on more devices, with Visual AI means that more bugs & defects are caught without having to write more tests.

Added Security

The Native Mobile Grid does not need to open a tunnel into your network so your application stays safe and secure

Get Started

To get started with Native Mobile Grid, just head on over and fill out this form.

The post Introducing Applitools Native Mobile Grid appeared first on Automated Visual Testing | Applitools.

]]>
Writing Your First Appium Test For iOS Devices https://applitools.com/blog/how-to-write-appium-ios-test/ Wed, 13 Apr 2022 01:47:33 +0000 https://applitools.com/?p=36632 Learn how to create your first Appium test for iOS. Set up and run your first test in this easy-to-follow guide.

The post Writing Your First Appium Test For iOS Devices appeared first on Automated Visual Testing | Applitools.

]]>

This is the third and final post in our Hello World introduction series to Appium, and we’ll discuss how to create your first Appium test for iOS. You can read the first post for an introduction to Appium, or the second to learn how to create your first Appium test for Android.

Congratulations on having made it so far. I hope you are slowly becoming more comfortable with Appium and realizing just how powerful a tool it really is for mobile automation, and that it’s not that difficult to get started with it.

This is the final post in this short series on helping you start with Appium and write your first tests. If you need a refresher on what Appium is and writing your first Android test with it, you can read the earlier parts here:

Say Hello to iOS! ?

In this post, we’ll learn how to set up your dev environment and write your first Appium based iOS test.

Setup Dependencies

We’ll need some dependencies to be preinstalled on your dev machine.

Let’s go over them one by one.

Also, remember it’s completely okay if you don’t understand all the details of these in the beginning since Appium pretty much abstracts those details away and you can always dig deeper later on if you need some very specific capabilities of these libraries.

Step 1: Install XCode Select

To run iOS tests, we need a machine running macOS with Xcode installed.

The below command would setup Command-line scripts that are needed for us to be able to run our first test:

xcode-select --install

Step 2: Install Carthage

You can think of Carthage as a tool to allow adding frameworks to your Cocoa applications and to build required dependencies:

brew install carthage

Step 3: Install libimobiledevice

libimobiledevice library allows Appium to talk to iOS devices using native protocols:

brew install libimobiledevice

Step 4: Install ios-deploy

ios-deploy helps to install and debug iOS apps from the command line:

brew install ios-deploy

Step 5: Install ios-webkit-debug-proxy

  • ios_webkit_debug_proxy (aka iwdp) proxies requests from usbmuxd daemon over a web socket connection
  • Allows developers to send commands to MobileSafari and UIWebViews on real and simulated iOS devices.
brew install ios-webkit-debug-proxy

Step 6: Optional Dependencies

IDB (iOS Device bridge) is a node JS wrapper over IDB that are a set of utilities made by Facebook:

brew tap facebook/fb
brew install idb-companion
pip3.6 install fb-idb

If you are curious, you could read the below reference blogs below that helped me come up with this shortlist of dependencies and are good reads for more context:

Your First Appium iOS Test

For our first iOS test, we’ll use a sample demo app provided by Appium.

You can download the zip file from here, unzip it and ensure you copy it under src/test/resources dir in the project, such that we have a TestApp.app file under the test resources folder.

If you are following these tests along by checking out the GitHub repo appium-fast-boilerplate, you’ll see the iOS app path is mentioned under a file ios-caps.json under src/main/resources/.

This file represents Appium capabilities in JSON format and you can change them based on which iOS device you want to run them on.

When we run the test DriverManager will pick these up and help create the Appium session. You can read part 2 of this blog series to know more about this flow.

{
  "platformName": "iOS",
  "automationName": "XCUITest",
  "deviceName": "iPhone 13",
  "app": "src/test/resources/TestApp.app"
}

Which Steps Would We Automate?

Our app has a set of UI controls with one section representing a calculator wherein we could enter two numbers and get their sum (see below snapshot):

TestApp from appium showing two text buttons, a compute sum button and a result textbox

We would automate the below flow:

  1. Open AUT (Application under test)
  2. Enter first no in Textbox
  3. Enter second no in Textbox
  4. Tap on Compute sum button
  5. Verify the total is indeed correct

Pretty basic right?

Below is how a sample test would look like (see the code here):

import constants.TestGroups;
import org.testng.Assert;
import org.testng.annotations.Test;
import pages.testapp.home.HomePage;

public class IOSTest extends BaseTest {

   @Test(groups = {TestGroups.IOS})
   public void addNumbers() {
       String actualSum = new HomePage(this.driver)
               .enterTwoNumbersAndCompute("5", "5")
               .getSum();

       Assert.assertEquals(actualSum, "10");
   }
}

Here, we follow the same good patterns that have served us well (like using Fluent, page objects, a base test, and driver manager) in our tests just as we did in our Android test.

You can read about these in detail in this earlier blog.

Your First iOS Page Object

The beauty of the page object pattern is that it looks very similar regardless of the platform.

Below is the complete page object for the above test that implements the desired behavior for this test.

package pages.testapp.home;

import core.page.BasePage;
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

public class HomePage extends BasePage {
   private final By firstNumber = By.name("IntegerA");
   private final By secondNumber = By.name("IntegerB");
   private final By computeSumButton = By.name("ComputeSumButton");
   private final By answer = By.name("Answer");

   public HomePage(AppiumDriver driver) {
       super(driver);
   }

   public HomePage enterTwoNumbersAndCompute(String first, String second) {
       typeFirstNumber(first);
       typeSecondNumber(second);
       compute();
       return this;
   }

   public HomePage typeFirstNumber(String number) {
       WebElement firstNoElement = getElement(firstNumber);
       type(firstNoElement, number);
       return this;
   }

   public HomePage typeSecondNumber(String number) {
       WebElement secondNoElement = getElement(secondNumber);
       type(secondNoElement, number);
       return this;
   }

   public HomePage compute() {
       WebElement computeBtn = getElement(computeSumButton);
       click(computeBtn);
       return this;
   }

   public String getSum() {
       waitForElementToBePresent(answer);
       return getText(getElement(answer));
   }
}

Let’s unpack this and understand its components.

We create a HomePage class that inherits from BasePage that has wrappers over Appium API methods.

public class HomePage extends BasePage

We define our selectors of type By, using the Appium inspector to discover that name is the unique selector for these elements, in your projects trying to depend on ID is probably a safer bet.

private final By firstNumber = By.name("IntegerA");
private final By secondNumber = By.name("IntegerB");
private final By computeSumButton = By.name("ComputeSumButton");
private final By answer = By.name("Answer");

Next, we initialize this class with a driver instance that’s passed the test and also its parent class to ensure we have the appropriate driver instance set:

public HomePage(AppiumDriver driver) {
   super(driver);
}

We then create a wrapper function that takes two numbers as strings, types numbers in the two text boxes, and taps on the button.

public HomePage enterTwoNumbersAndCompute(String first, String second) {
   typeFirstNumber(first);
   typeSecondNumber(second);
   compute();
   return this;
}

We implement these methods by reusing methods from BasePage while ensuring the correct page object is returned.

Since there is no redirection happening in these tests and it’s a single screen we just return this (i.e. the current page object in Java syntax). This enables writing tests in the Fluent style that you saw earlier.

public HomePage typeFirstNumber(String number) {
   WebElement firstNoElement = getElement(firstNumber);
   type(firstNoElement, number);
   return this;
}

public HomePage typeSecondNumber(String number) {
   WebElement secondNoElement = getElement(secondNumber);
   type(secondNoElement, number);
   return this;
}

public HomePage compute() {
   WebElement computeBtn = getElement(computeSumButton);
   click(computeBtn);
   return this;
}

Finally, we return the string that has the sum of two numbers in the getSum() method and let the test perform desired assertions:

public String getSum() {
   waitForElementToBePresent(answer);
   return getText(getElement(answer));
}

Running the Test

Before running the test, ensure that the Appium server is running in another terminal and that your appium 2.0 server has the XCUITest driver installed by following the below steps

# Ensure driver is installed
appium driver install xcuitest

# Start the appium server before running your test
appium

Within the project, you could run the test using the below command or use IntelliJ or equivalent editors test runner to run the desired test.

gradle wrapper clean build runTests -Dtag="IOS" -Dtarget="IOS"

Conclusion

With this, we come to an end to this short three-part series on getting started with Appium, from a general introduction to Appium to working with Android to this post on iOS. Hopefully, this series makes it a little bit easier for you or your friends to get set up with Appium.

Exploring the remainder of Appium’s API, capabilities and tooling is left as an exercise to you, my brave and curious reader. I’m sure pretty soon you’ll also be sharing similar posts and hopefully, I’ll learn a thing or two from you as well. Remember Appium docs, the community, and Appium Conf are great sources to go deeper into Appium ?.

So, what are you waiting for? Go for it!

Remember, you can see the entire project on Github at appium-fast-boilerplate, clone or fork it, and play around with it. Hopefully, this post helps you a little bit in starting on iOS automation using Appium. If you found it valuable, do leave a star on the repo and in case there is any feedback, don’t hesitate to create an issue.

You could also check out https://automationhacks.io for other posts that I’ve written about Software engineering and Testing and this page for a talk that I gave on the same topic.

As always, please do share this with your friends or colleagues and if you have thoughts or feedback, I’d be more than happy to chat over on Twitter or in the comments. Until next time. Happy testing and coding.

The post Writing Your First Appium Test For iOS Devices appeared first on Automated Visual Testing | Applitools.

]]>
How to Visually Test a Remix App with Applitools and Cypress https://applitools.com/blog/how-to-visually-test-remix-app-applitools-cypress/ Tue, 22 Mar 2022 20:59:50 +0000 https://applitools.com/?p=35712 Is Remix too new to be visually tested? Let’s find out with Applitools and Cypress.

The post How to Visually Test a Remix App with Applitools and Cypress appeared first on Automated Visual Testing | Applitools.

]]>

Is Remix too new to be visually tested? Let’s find out with Applitools and Cypress.

In this blog post, we answer a single question: how to best visually test a Remix-based app? 

We walk through Remix and build a demo app to best showcase the framework. Then, we take a deep dive into visual testing with Applitools and Cypress. We close on scaling our test coverage with the Ultrafast Test Cloud to perform cross-browser validation of the app.

So let our exciting journey begin in pursuit of learning how to visually test the Remix-based app.

What is Remix?

Remix Logo

Web development is an ever-growing space with almost as many ways to build web apps as there are stars in the sky. And it ultimately translates into just how many different User Interface (UI) frameworks and libraries there are. One such library is React, which most people in the web app space have heard about, or even used to build a website or two. 

For those unfamiliar with React, it’s a declarative, component-based library that developers can use to build web apps across different platforms. While React is a great way to develop robust and responsive UIs, many moving pieces still happen behind the scenes. Things like data loading, routing, and more complex work like Server-Side Rendering are what a new framework called Remix can handle for React apps.

Remix is a full-stack web framework that optimizes data loading and routing, making pages load faster and improving overall User Experience (UX). The days are long past when our customers would wait minutes while a website reloads, while moving from one page to another, or expecting an update on their feed. Features like Server-Side Rendering, effective routing, and data loading have become the must for getting our users the experience they want and need. The Remix framework is an excellent open-source solution for delivering these features to our audience and improving their UX.

What Does Remix Mean For UI Testing?

Testing Remix with Cypress and Applitools

Our end-users shouldn’t care what framework we used to build a website. What matters to our users is that the app works and lets them achieve their goals as fast as possible. In the same way, the testing principles always remain the same, so UI testing shouldn’t be impacted by the frameworks used to create an app. The basics of how we test stay the same although some testing aspects could change. For example, in the case of an Angular app, we might need to adjust how we wait for the site to fully load by using a specialized test framework like Protractor.

Most tests follow a straightforward pattern of Arrange, Act, and Assert. Whether you are writing a unit test, an integration test, or an end-to-end test, everything follows this cycle of setting up the data, running through a set of actions and validating the end state.

When writing these end-to-end tests, we need to put ourselves in the shoes of our users. What matters most in this type of testing is replicating a set of core use-cases that our end-users go through. It could be logging into an app, writing a new post, or navigating to a new page. That’s why UI test automation frameworks like Applitools and Cypress are fantastic for testing – they are largely agnostic of the platform they are testing. With these tools in hand, we can quickly check Remix-based apps the same way we would test any other web application.

What about Remix and Visual Testing?

The main goal of testing is to confirm the app’s behavior that our users see and go through. This reason is why simply loading UI elements and validating inner text or styling is not enough. Our customers are not interested in HTML or CSS. What they care about is what they can see and interact with on our site, not the code behind it. It’s not enough for a robust coverage of the complex UI that modern web apps have. We can close this gap with visual testing. 

Contrasting what our tests see (with an image of code) with what our customers see (with an image of a website's UI).
Functional vs Visual Testing Perspective

Visual testing allows us to see our app from our customers’ point of view. And that’s where the Applitools Eyes SDK comes in! This visual testing tool can enhance the existing end-to-end test coverage to ensure our app is pixel-perfect.

To simplify, what Applitools does for us is that it allows developers to effectively compare visual elements across various screens to find visible defects. Applitools can record our UI elements in their platform and then monitor any visual regressions that our customers might encounter. More specifically, this testing framework exposes the visible differences between baseline snapshots and future snapshots.

Applitools has integrations with numerous testing platforms like Cypress, WebdriverIO, Selenium, and many others. For this article, we will showcase Applitools with Cypress to add visual test coverage to our Remix app.

Introducing Remix Demo App

We can’t talk about a framework like Remix without seeing it in practice. That’s why we put together a demo app to best showcase Remix and later test it with Applitools and Cypress.

A screenshot of a Remix demo app
Remix Demo App

We based this app on the Remix Developer Blog app that highlights the core functionalities of Remix: data loading, actions, redirects, and more. We shared this demo app and all the tests we cover in this article in this repository so that our readers can follow along.

Running Demo App 

Before diving into writing tests, we must ensure that our Remix demo application is running.

To start, we need to clone a project from this repository:

git clone https://github.com/dmitryvinn/remix-demo-app-applitools

Then, we navigate into the project’s root directory and install all dependencies:

cd remix-demo-app-applitools
npm install

After we install the necessary dependencies, our app is ready to start:

npm run dev

After we launch the app, it should be available at http://localhost:3000/, unless the port is already taken. With our Remix demo app fully functional, we can transition into testing Remix with Applitools and Cypress.

Visual Testing of Remix App with Applitools and Cypress

There is this great quote from a famous American economist, Richard Thaler: “If you want people to do something, make it easy.” That’s what Applitools and Cypress did by making testing easy for developers, so people don’t see it as a chore anymore.

To run our visual test automation using Applitools, we first need to set up Cypress, which will play the role of test runner. We can think about Cypress as a car’s body, whereas Applitools is an engine that powers the vehicle and ultimately gets us to our destination: a well-tested Remix web app.

Setting up Cypress

Cypress is an open-source JavaScript end-to-end testing framework developers can use to write fast, reliable, and maintainable tests. But rather than reinventing the wheel and talking about the basics of Cypress, we invite our readers to learn more about using this automation framework on the official site, or from this course at Test Automation University.

To install Cypress, we only need to run a single command:

npm install cypress

Then, we need to initialize the cypress folder to write our tests. The easiest way to do it is by running the following:

npx cypress open

This command will open Cypress Studio, which we will cover later in the article, but for now we can safely close it. We also recommend deleting sample test suites that Cypress created for us under cypress/integration.

Note: If npx is missing on the local machine, follow these steps on how to update the Node package manager, or run ./node_modules/.bin/cypress open instead.

Setting up Applitools

Installing the Applitools Eyes SDK with Cypress is a very smooth process. In our case, because we already had Cypress installed, we only need to run the following:

npm install @applitools/eyes-cypress --save-dev

To run Applitools tests, we need to get the Applitools API key, so our test automation can use the Eyes platform, including recording the UI elements, validating any changes on the screen, and more. This page outlines how to get this APPLITOOLS_API_KEY from the platform.

After getting the API key, we have two options on how to add the key to our tests suite: using a CLI or an Applitools configuration file. Later in this post, we explore how to scale Applitools tests, and the configuration file will play a significant role in that effort. Hence, we continue by creating applitools.config.js in our root directory.

Our configuration file will begin with the most basic setup of running a single test thread (testConcurrency) for one browser (browser field). We also need to add our APPLITOOLS_API_KEY under the `apiKey’ field that will look something like this:

module.exports = {
  testConcurrency: 1,
  apiKey: "DONT_SHARE_OUR_APPLITOOLS_API_KEY",
  browser: [
    // Add browsers with different viewports
    { width: 800, height: 600, name: "chrome" },
  ],
  // set batch name to the configuration
  batchName: "Remix Demo App",
};

Now, we are ready to move onto the next stage of writing our visual tests with Applitools and Cypress.

Writing Tests with Applitools and Cypress

One of the best things about Applitools is that it nicely integrates with our existing tests with straightforward API.

For this example, we visually test a simple form on the Actions page of our Remix app.

An Action form in the demo remix app, showing a question: "What is more useful when it is broken?" with an answer field and an answer button.
Action Form in Remix App

To begin writing our tests, we need to create a new file named actions-page.spec.js in the cypress/integration folder:

Basic Applitools Test File

Since we rely on Cypress as our test runner, we will continue using its API for writing the tests. For the basic Actions page tests where we validate that the page renders visually correctly, we start with this code snippet:

describe("Actions page form", () => {
  it("Visually confirms action form renders", () => {
    // Arrange
    // ...

    // Act
    // ..

    // Assert
    // ..

    // Cleanup
    // ..
  });
});

We continue following the same pattern of Arrange-Act-Assert, but now we also want to ensure that we close all the resources we used while performing the visual testing. To begin our test case, we need to visit the Action page:

describe("Actions page form", () => {
  it("Visually confirms action form renders", () => {
    // Arrange
    cy.visit("http://localhost:3000/demos/actions");

    // Act
    // ..

    // Assert
    // ..

    // Cleanup
    // ..
  });
});

Now, we can begin the visual validation by using the Applitools Eyes framework. We need to “open our eyes,” so-to-speak by calling cy.eyesOpen(). It initializes our test runner for Applitools to capture critical visual elements just like we would with our own eyes:

describe("Actions page form", () => {
  it("Visually confirms action form renders", () => {
    // Arrange
    cy.visit("http://localhost:3000/demos/actions");

    // Act
    cy.eyesOpen({
      appName: "Remix Demo App",
      testName: "Validate Action Form",
    });

    // Assert
    // ..

    // Cleanup
    // ..
  });
});

Note: Technically speaking, cy.eyesOpen() should be a part of the Arrange step of writing the test, but for educational purposes, we are moving it under the Act portion of the test case.

Now, to move to the validation phase, we need Applitools to take a screenshot and match it against the existing version of the same UI elements. These screenshots are saved on our Applitools account, and unless we are running the test case for the first time, the Applitools framework will match these UI elements against the version that we previously saved:

describe("Actions page form", () => {
  it("Visually confirms action form renders", () => {
    // Arrange
    cy.visit("http://localhost:3000/demos/actions");

    // Act
    cy.eyesOpen({
      appName: "Remi Demo App",
      testName: "Validate Action Form",
    });

    // Assert
    cy.eyesCheckWindow("Action Page");

    // Cleanup
    // ..
  });
});

Lastly, we need to close our test runner for Applitools by calling cy.closeEyes(). With this step, we now have a complete Applitools test case for our Actions page:

describe("Actions page form", () => {
  it("Visually confirms action form renders", () => {
    // Arrange
    cy.visit("http://localhost:3000/demos/actions");

    // Act
    cy.eyesOpen({
      appName: "Remi Demo App",
      testName: "Validate Action Form",
    });

    // Assert
    cy.eyesCheckWindow("Action Page");

    // Cleanup
    cy.eyesClose();
  });
});

Note: Although we added a cleanup-stage with cy.eyesClose() in the test case itself, we highly recommend moving this method outside of the it() function into the afterEach() that will run for every test, avoiding code duplication.

Running Applitools Tests

After the hard work of planning and then writing our test suite, we can finally start running our tests. And it couldn’t be easier than with Applitools and Cypress! 

We have two options of either executing our tests by using Cypress CLI or Cypress Studio.

Cypress Studio is a great option when we first write our tests because we can walk through every case, stop the process at any point, or replay any failures. These reasons are why we should use Cypress Studio to demonstrate best how these tests function.

We begin running our cases by invoking the following from the project’s root directory:

npm run cypress-open

This operation opens Cypress Studio, where we can select what test suite to run:

The Cypress Studio dashboard, where we can select actions-page-spec.js
Actions Tests in Cypress Studio

To validate the result, we need to visit our Applitools dashboard:

The Applitools dashboard, displaying the Remix Demo App test with the Action Page.
Basic Visual Test in the Applitools Dashboard

To make it interesting, we can cause this test to fail by changing the text on the Actions page. We could change the heading to say “Failed Actions!” instead of the original “Actions!” and re-run our test. 

This change will cause our original test case to fail because it will catch a difference in the UI (in our case, it’s because of the intentional renaming of the heading). This error message is what we will see in the Cypress Studio:

Cypress Studio showing a red error message that reads, in part: "Eyes-Cypress detected diffs or errors during execution of visual tests."
Failed Visual Test in Cypress Studio

To further deal with this failure, we need to visit the Applitools dashboard:

Applitools dashboard showing the latest test results as "Unresolved."
Failed Visual Test in Applitools Dashboard

As we can see, the latest test run is shown as Unresolved, and we might need to resolve the failure. To see what the difference in the newest test run is, we only need to click on the image in question:

A closer look at the Applitools visual test results, highlighting the areas where the text changed in magenta.
Closer Look at the Failed Test in Applitools Dashboard

A great thing about Applitools is that their visual AI algorithm is so advanced that it can test our application on different levels to detect content changes as well as layout or color updates. What’s especially important is that Applitools’ algorithm prevents false positives with built-in functionalities like ignoring content changes for apps with dynamic content. 

In our case, the test correctly shows that the heading changed, and it’s now up to us to either accept the new UI or reject it and call this failure a legitimate bug. Applitools makes it easy to choose the correct course of action as we only need to press thumbs up to accept the test result or thumbs down to decline it.

Accepting or Rejecting Test Run in Applitools Dashboard

In our case, the test case failed due to a visual bug that we introduced by “unintentionally” updating the heading. 

After finishing our work in the Applitools Dashboard, we can bring the test results back to the developers and file a bug on whoever made the UI change.

But are we done? What about testing our web app on different browsers and devices? Fortunately, Applitools has a solution to quickly scale the tests automation and add cross-browser coverage.

Scaling Visual Tests Across Browsers

Testing an application against one browser is great, but what about all others? We have checked our Remix app on Chrome, but we didn’t see how the app performs on Firefox, Microsoft Edge, and so on. We haven’t even started looking into mobile platforms and our web app on Android or iOS. Introducing this additional test coverage can get out of hand quickly, but not with Applitools and their Ultrafast Test Cloud. It’s just one configuration change away!

With this cloud solution from Applitools, we can test our app across different browsers without any additional code. We only have to update our Applitools configuration file, applitools.config.js.

Below is an example of how to add coverage for desktop browsers like Chrome, Firefox, Safari and E11, plus two extra test cases for different models of mobile phones:

module.exports = {
  testConcurrency: 1,
  apiKey: "DONT_SHARE_YOUR_APPLITOOLS_API_KEY",
  browser: [
    // Add browsers with different viewports
    { width: 800, height: 600, name: "chrome" },
    { width: 700, height: 500, name: "firefox" },
    { width: 1600, height: 1200, name: "ie11" },
    { width: 800, height: 600, name: "safari" },
    // Add mobile emulation devices in Portrait or Landscape mode
    { deviceName: "iPhone X", screenOrientation: "landscape" },
    { deviceName: "Pixel 2", screenOrientation: "portrait" },
  ],
  // set batch name to the configuration
  batchName: "Remix Demo App",
};

It’s important to note that when specifying the configuration for different browsers, we need to define their width and height, with an additional property for screenOrientation to cover non-desktop devices. These settings are critical for testing responsive apps because many modern websites visually differ depending on the devices our customers use.

After updating the configuration file, we need to re-run our test suite with npm test. Fortunately, with the Applitools Ultrafast Test Cloud, it only takes a few seconds to finish running our tests on all browsers, so we can visit our Applitools Dashboard to view the results right away:

The Applitools dashboard, showing passed tests for our desired suite of browsers.
Cross-browser Coverage with Applitools

The Applitools dashboard, showing a visual checkpoint with a Pixel 2 mobile phone in portrait orientation.
Mobile Coverage with Applitools

As we can see, with only a few lines in the configuration file, we scaled our visual tests across multiple devices and browsers. We save ourselves time and money whenever we can get extra test coverage without explicitly writing new cases. Maintaining test automation that we write is one of the most resource-consuming steps of the Software Development Life Cycle. With solutions like Applitools Ultrafast Test Cloud, we can write fewer tests while increasing our test coverage for the entire app.

Verdict: Can Remix Apps be Visually Tested with Applitools and Cypress?

Hopefully, this article showed that the answer is yes; we can successfully visually test Remix-based apps with Applitools and Cypress! 

Remix is a fantastic framework to take User Experience to the next level, and we invite you to learn more about it during the webinar by Kent C. Dodds “Building Excellent User Experiences with Remix”.

For more information about Applitools, visit their website, blog and YouTube channel. They also provide free courses through Test Automation University that can help take anyone’s testing skills to the next level.

The post How to Visually Test a Remix App with Applitools and Cypress appeared first on Automated Visual Testing | Applitools.

]]>
Writing Your First Appium Test For Android Mobile Devices https://applitools.com/blog/how-to-write-android-test-appium/ Fri, 11 Mar 2022 20:51:39 +0000 https://applitools.com/?p=35292 Learn how to create your first Appium test for Android in this comprehensive, step-by-step walkthrough.

The post Writing Your First Appium Test For Android Mobile Devices appeared first on Automated Visual Testing | Applitools.

]]>

This is the second post in our Hello World introduction series to Appium, and we’ll discuss how to create your first Appium test for Android. You can read the first post where we discussed what Appium is, including its core concepts and how to set up the Appium server. You can also read the next post on setting up your first Appium iOS test.

Key Takeaways

In this post, we’ll build on top of earlier basics and focus on the below areas:

  • Setup Android SDK
  • Setup Android emulator/real devices
  • Setup Appium Inspector
  • Setup our first Android project with framework components

We have lots to cover but don’t worry, by the end of this post, you will have run your first Appium-based Android test. Excited? ✊? Let’s go.

Setup Android SDK

To run Android tests, we need to set up an Android SDK, ADB (Android debug bridge), and some other utilities. 

  • Android SDK will set up Android on your machine and provide you with all the tools required to do the development or in this case automation.
  • Android Debug Bridge (ADB) is a CMD line tool that lets you communicate with the Android device (either emulator or physical device).

The easiest way to set these up is to go to the Android site and download Android Studio (An IDE to develop Android apps), which will install all the desired libraries and also give us everything we need to run our first Android test.

Setup SDK Platforms and Tools

Once downloaded and installed, open Android Studio, click on Configure, and then SDK Manager. Using this you can download any android API version from SDK Platforms.

Shows Android studio home page and how someone can open SDK Manager by tapping on Configure button

Also, You can install any desired SDK Tools from here. 

We’ll go with the defaults for now. This tool can also install any required updates for these tools which is quite a convenient way of upgrading.

Shows SDK Tools in android studio

Add Android Home to Environment Variables

The Appium server needs to know where the Android SDK and other tools like Emulator, Platform Tools are present to help us run the tests. 

We can do so by adding the below variables in the system environment.

On Mac/Linux:

  • Add the below environment variables in the shell of your choice (.bash_profile for bash or .zshrc for zsh). These are usually the paths where Android studio installs these.
  • Run source <shell_profile_file_name> for e.g. source.zshrc
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$ANDROID_HOME/emulator:$PATH
export PATH=$ANDROID_HOME/tools:$PATH
export PATH=$ANDROID_HOME/tools/bin:$PATH
export PATH=$ANDROID_HOME/platform-tools:$PATH

If you are on Windows, you’ll need to add the path to Android SDK in the ANDROID_HOME variable under System environment variables.

Once done, run the adb command on the terminal to verify ADB is set up:

➜  appium-fast-boilerplate git:(main) adb
Android Debug Bridge version 1.0.41
Version 30.0.5-6877874
Installed as /Users/gauravsingh/Library/Android/sdk/platform-tools/adb

These are a lot of tedious steps and in case you want to set these up quickly, you can execute this excellent script written by Anand Bagmar.

Set up an Android Emulator or Real Device

Our Android tests will run either on an emulator or a real Android device plugged in. Let’s see how to create an Android emulator image.

  • Open Android Studio
  • Click configure
  • Click on AVD Manager

Shows Android studio home page and how someone can open AVD Manager by tapping on Configure button

You’ll be greeted with a blank screen with no virtual devices listed. Tap on Create a virtual device to launch the Virtual device Configuration flow:

Shows blank virtual devices screen with create virtual device button

Next, select an Android device like TV, Phone, Tablet, etc., and the desired size and resolution combination. 

It’s usually a good idea to set up an emulator with Play Store services available (see the Play Store icon under the column) as certain apps might need the latest play services to be installed.

We’ll go with Pixel 3a with Play Store available.

Shows device definition screen to select a device model

Next, we’ll need to select which Android version this emulator should have. You can choose any of the desired versions and download the image. We’ll choose Android Q (10.0 version).

Shows Android OS system image with option to Download and select one

You need to give this image a name. We’ll need to use this later in Appium capabilities so you can give any meaningful name or go with the default. We’ll name it Automation.

Shows Android emulator configuration with AVD Name

Nice, ✋?We have created our emulator. You can fire it up by tapping the Play icon under the Actions section.

Android Virtual Device Manager screen with and emulator named Automation

You should see an emulator boot up on your device similar to a real phone. 

Setting up a Real Device

While the emulator is an in-memory image of the Android OS that you can quickly spin up and destroy, it does take physical resources like Memory, RAM, and CPU. It’s always a good idea to verify your app on a real device.

We’ll see how to set up a real device so that we can run automation on it.

You need to connect your device to your machine via USB. Once done:

  • Go to About Phone.
  • Tap on Android build number multiple times until developer mode is enabled, you’ll see a Toast message show up under as you get closer to enabling this mode.
  • Go to Developer Options and Enable USB Debugging.

USB Debugging under Developer Options

And thats all you need to potentially run our automation on a connected real device.

Setting up Appium Inspector

Appium comes with a nifty inspector desktop app that can inspect your Application under test and help you identify element locators (i.e. ways to identify elements on the screen) and even play around with the app. 

It can easily run on any running Appium server and is really a cool utility to help you identify element locators and develop Appium scripts.

Download and Install Appium Inspector

You can download it by just going to the Appium Github repo, and searching for appium-inspector.

Appium Inspector Github page with releases option highlighted

Go to release and find the latest .dmg (on Mac) or .exe (on Windows) to download and install.

Appium Inspector Github releases page with mac .dmg file highlighted

On Mac, you may get a warning stating: “Appium Inspector” can’t be opened because Apple cannot check it for malicious software. 

 Apple warning for malicious software

To mitigate this, just go to System preferences > Security & Privacy > General and say Open Anyway for Appium Inspector. For more details see Issue 1217.

Give open anyway permission to Appium in System preferences

Setting up Desired Capabilities

Once you launch Appium inspector, you’ll be greeted with the below home screen. If you see there is a JSON representation sector under Desired Capabilities section.

 Steps highlighting how we can add our desired caps and save this config

What are Desired Capabilities?

Think of them as properties that you want your driver’s session to have. For example, you may want to reset your app after your test, or launch the app in a particular orientation. These are all achievable by specifying a Key-Value pair in a JSON that we provide to the Appium server session. 

Please see Appium docs for more idea on these capabilities.

Below are some sample capabilities we can give for Android:

{
    "platformName": "android",
    "automationName": "uiautomator2",
    "platformVersion": "10",
    "deviceName": "Automation",
    "app": "/<absolute_path_to_app>/ApiDemos-debug.apk",
    "appPackage": "io.appium.android.apis",
    "appActivity": "io.appium.android.apis.ApiDemos"
}

For this post, we’ll use the sample apps provided by Appium. You can see them here, once you’ve downloaded them. Keep track of its absolute path and update it in-app key in the JSON.

We’ll add this JSON under JSON representation and then tap on the Save button.

Saved caps in grid

It would be a good idea to save this config for the future. You can tap on ‘Save as’ and give it a meaningful name.

 Saving and giving caps a name

Starting the Inspector Session

To start the inspection session, You need to have an Appium server run locally, run it via typing appium on the command line:

➜  appium-fast-boilerplate git:(main) appium
[Appium] Welcome to Appium v2.0.0-beta.25
[Appium] Attempting to load driver uiautomator2...
[Appium] Appium REST http interface listener started on 0.0.0.0:4723
[Appium] Available drivers:
[Appium]   - uiautomator2@2.0.1 (automationName 'UiAutomator2')
[Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.

Let’s make sure our emulator is also up and running. We can start the emulator via AVD Manager in Android studio, or in case you are more command-line savvy, I have written an earlier post on how to do this via CMDline as well.

Once done, tap on the Start Session button, this should bring launch the API Demos app and show the inspector home screen.

Appium inspector home screen with controls highlighted

Using this you can tap on any element in the app and see its Element hierarchy, elements properties. This is very useful to author Appium scripts and I’ll encourage you to explore each section of this tool and get familiar since you’ll be using this a lot.

Writing Our First Android Test Using Appium

Phew, that seemed like a lot of setup steps but don’t worry, you only have to do this once and now we can get down to the real business of writing our first Automated test on Android.

You can download the project using Github from appium-fast-boilerplate.

We’ll also understand what the fundamental concepts of writing page objects and tests are based on these. Let’s take a look at the high-level architecture.

High-level architecture of an Android test written using Appium

What Would This Test Do?

Before automating any test, we need to be clear on what is the purpose of that test. I’ve found the Arrange Act Assert pattern quite useful to reason about it. Read this post by Andrew Knight in case you are interested to know more about it.

Our test would perform the below:

  • Opens API Demos app
  • Taps around and navigates to Log Text box and taps on Add once
  • Verify the log text is displayed

Our Test Class

Let’s start by seeing our test.

import constants.TestGroups;
import org.testng.Assert;
import org.testng.annotations.Test;
import pages.apidemos.home.APIDemosHomePage;

public class AndroidTest extends BaseTest {

    @Test(groups = {TestGroups.ANDROID})
    public void testLogText() {
        String logText = new APIDemosHomePage(this.driver)
                .openText()
                .tapOnLogTextBox()
                .tapOnAddButton()
                .getLogText();

        Assert.assertEquals(logText, "This is a test");
    }
}

There are a few things to notice above:

public class AndroidTest extends BaseTest

Our class extends a BaseTest, this is useful since we can perform common setup and tear down functions, including setting up driver sessions and closing it once our script is done. 

This ensures that the tests are as simple as possible and does not overload the reader with any more details than they need to see.

String logText = new APIDemosHomePage(this.driver)
                .openText()
                .tapOnLogTextBox()
                .tapOnAddButton()
                .getLogText();

We see our tests read like plain English with a series of actions following each other. This is called a Fluent pattern and we’ll see how this is set up in just a moment.

Base Test and Driver Setup

Let’s see our BaseTest class:

import constants.Target;
import core.driver.DriverManager;
import core.utils.PropertiesReader;
import exceptions.PlatformNotSupportException;
import io.appium.java_client.AppiumDriver;
import org.testng.ITestContext;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import java.io.IOException;

public class BaseTest {
    protected AppiumDriver driver;
    protected PropertiesReader reader = new PropertiesReader();

    @BeforeMethod(alwaysRun = true)
    public void setup(ITestContext context) {
        context.setAttribute("target", reader.getTarget());

        try {
            Target target = (Target) context.getAttribute("target");
            this.driver = new DriverManager().getInstance(target);
        } catch (IOException | PlatformNotSupportException e) {
            e.printStackTrace();
        }
    }

    @AfterMethod(alwaysRun = true)
    public void teardown() {
        driver.quit();
    }
}

Let’s unpack this class.

protected AppiumDriver driver;

We set our driver instance as protected so that all test classes will have access to it.

protected PropertiesReader reader = new PropertiesReader();

We create an instance of PropertiesReader class to read relevant properties. This is useful since we want to be able to switch our driver instances based on different test environments and conditions. If curious, please see its implementation here.

Target target = (Target) context.getAttribute("target");
this.driver = new DriverManager().getInstance(target);

We get the relevant Target and then using that gets an instance of AppiumDriver from a class called DriverManager.

Driver Manager to Setup Appium Driver

We’ll use this reusable class to:

  • Read capabilities JSON file based on platform (Android/iOS)
  • Setup a local driver instance with these capabilities
  • This class could independently evolve to setup desired driver instances, either local, the house or remote cloud lab
package core.driver;

import constants.Target;
import exceptions.PlatformNotSupportException;
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import static core.utils.CapabilitiesHelper.readAndMakeCapabilities;

public class DriverManager {
    private static AppiumDriver driver;
    // For Appium < 2.0, append /wd/hub to the APPIUM_SERVER_URL
    String APPIUM_SERVER_URL = "http://127.0.0.1:4723";

    public AppiumDriver getInstance(Target target) throws IOException, PlatformNotSupportException {
        System.out.println("Getting instance of: " + target.name());
        switch (target) {
            case ANDROID:
                return getAndroidDriver();
            case IOS:
                return getIOSDriver();
            default:
                throw new PlatformNotSupportException("Please provide supported target");
        }
    }

    private AppiumDriver getAndroidDriver() throws IOException {
        HashMap map = readAndMakeCapabilities("android-caps.json");
        return getDriver(map);
    }

    private AppiumDriver getIOSDriver() throws IOException {
        HashMap map = readAndMakeCapabilities("ios-caps.json");
        return getDriver(map);
    }

    private AppiumDriver getDriver(HashMap map) {
        DesiredCapabilities desiredCapabilities = new DesiredCapabilities(map);

        try {
            driver = new AppiumDriver(
                    new URL(APPIUM_SERVER_URL), desiredCapabilities);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return driver;
    }
}

You can observe:

  • getInstance method takes a target and based on that tries to get either an Android or an IOS Driver. In the future, if we want to run our tests against a cloud provider like Headspin, SauceLabs, BrowserStack, Applitools, then this class could handle creating the relevant session.
  • Both getAndroidDriver and getIOSDriver read a JSON file with similar capabilities as we saw in the Inspector section and then convert it into a Java Hashmap which could be passed into getDriver method that returns an Appium Instance. With this, we could later pass say an environmental context and based on that choose a different capabilities file.

A Simple Page Object with the Fluent Pattern

Let’s take a look at the example of a page object that enables a Fluent pattern.

package pages.apidemos.home;

import core.page.BasePage;
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import pages.apidemos.logtextbox.LogTextBoxPage;

public class APIDemosHomePage extends BasePage {
    private final By textButton = By.xpath("//android.widget.TextView[@content-desc=\"Text\"]");
    private final By logTextBoxButton = By.xpath("//android.widget.TextView[@content-desc=\"LogTextBox\"]");

    public APIDemosHomePage(AppiumDriver driver) {
        super(driver);
    }

    public APIDemosHomePage openText() {
        WebElement text = getElement(textButton);
        click(text);

        return this;
    }

    public LogTextBoxPage tapOnLogTextBox() {
        WebElement logTextBoxButtonElement = getElement(logTextBoxButton);
        waitForElementToBeVisible(logTextBoxButtonElement);

        click(logTextBoxButtonElement);

        return new LogTextBoxPage(driver);
    }
}

Notice the following:

Above is an example page object class:

  • With 2 XPath locators defined with By clause
  • We init the driver in BasePage class
  • The test actions return either this (i.e. current page) or next page object to enable a Fluent pattern. Following this, we can create a sort of action graph where any action that a test takes connects to the next set of actions this page can take and makes writing test scripts a breeze.

Base Page Class

package core.page;

import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.List;

public class BasePage {
    protected AppiumDriver driver;

    public BasePage(AppiumDriver driver) {
        this.driver = driver;
    }

    public void click(WebElement elem) {
        elem.click();
    }

    public WebElement getElement(By by) {
        return driver.findElement(by);
    }

    public List<WebElement> getElements(By by) {
        return driver.findElements(by);
    }

    public String getText(WebElement elem) {
        return elem.getText();
    }

    public void waitForElementToBeVisible(WebElement elem) {
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(ExpectedConditions.visibilityOf(elem));
    }

    public void waitForElementToBePresent(By by) {
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

    public void type(WebElement elem, String text) {
        elem.sendKeys(text);
    }
}

Every page object inherits from a BasePage that wraps Appium methods.

  • This provides us an abstraction and allows us to create our own project-specific reusable actions and methods. This is a very good pattern to follow for a few reasons
    • Say we want to provide some custom functionality like adding a logger line in our own logging infrastructure whenever an Appium action is performed, we can wrap those methods and perform this.
    • Also in the case in future Appium breaks an API, this change is not cascaded to all our page objects, rather only to this class where we can handle it in an appropriate manner to provide backward compatibility.
  • A word of caution ⚠: Do not dump every method in this class, try to compose only relevant actions.

Congratulations, you’ve written your first Appium Android test. You can run this either via the IDE or via a Gradle command

./gradlew clean build runTests -Dtag="ANDROID" -Ddevice="ANDROID"

Conclusion

You can see the entire project on the Github appium-fast-boilerplate, clone it and play around with it. Hopefully, this post helps you a little bit in starting on Android automation using Appium. 

In the next post, we’ll dive into the world of iOS Automation with Appium and write our first hello world test.

You could also check out https://automationhacks.io for other posts that I’ve written about software engineering and testing. 

As always, do share this with your friends or colleagues and if you have thoughts or feedback, I’d be more than happy to chat over at Twitter or elsewhere. Until next time. Happy testing and coding.

The post Writing Your First Appium Test For Android Mobile Devices appeared first on Automated Visual Testing | Applitools.

]]>
What’s New in Appium Java Client 8.0.0 https://applitools.com/blog/whats-new-appium-java-client-8/ Thu, 06 Jan 2022 02:24:16 +0000 https://applitools.com/?p=33588 Learn about the latest updates in the Appium Java Client 8.0.0 release, and how it affects your Appium mobile testing today.

The post What’s New in Appium Java Client 8.0.0 appeared first on Automated Visual Testing | Applitools.

]]>

Learn about the latest updates in the Appium Java Client 8.0.0 release, and how it affects your Appium mobile testing today. Sai Krishna and Srinivasan are members of the Appium team.

The Selenium team released Selenium 4 in September 2021 to much anticipation with tons of great features. Since then, the Appium team has been working on upgrading the Selenium dependency in all the clients of Appium to provide a seamless experience. Most of the Appium clients are updated and now in early beta, but with a lot of breaking changes. Let’s go through the changes introduced in Appium Java client 8.0.0 beta2 and what you would need to do.

WebDriver Protocol Compliance

With Appium 2.0, we on the Appium team are making sure we are strictly W3C compliant. Since the Java client supports Selenium 4.1.1, it’s strictly W3C compliant too. Methods that are non-w3c complaint are removed and the details can be seen here.

Driver-Specific Options Classes

It is now recommended to use driver-specific W3C option classes instead of Desired Capabilities. Below is the list of driver-specific classes.

  • XCUITestOptions to create an XCUITestDriver instance 
  • UiAutomator2Options to create a UIAutomator2Driver instance
  • EspressoOptions to create an EspressoDriver instance
  • WindowsOptions to create a WindowsDriver instance
  • Mac2Options to create a Mac2Driver instance
  • GeckoOptions to create a GeckoDriver instance
  • SafariOptions to create a SafariDriver instance

See the below example for changes required:

// From Appium Java Client version 8.0.0 Beta
UiAutomator2Options options = new UiAutomator2Options()
       .setDeviceName("Android Emulator")
       .setApp(System.getProperty("user.dir") + "/VodQA.apk")
       .eventTimings();
driver = new AndroidDriver(service.getUrl(), options);
// Older approach: Java Client version 7.X.X
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 700000);

Element Lookups

  • Like Selenium, Appium also removed all its findBy methods.
  • Since Appium supports both mobile and desktop platform applications, we replaced MobileBy with AppiumBy and introduced camelCase naming conventions. For example,  ​​MobileBy.AccessibilityId is now AppiumBy.accessibilityId. MobileBy is now deprecated.
  • windowsAutomation locator strategy is deprecated.

Starting Appium Server Programmatically

  • Java Client uses AppiumServiceBuilder to start a node server programmatically. With the updated version, it works slightly differently with different Appium server versions.
  • The default URL for the server has been changed at the server-side and it does not contain the /wd/hub by default.
  • Java Client starting from v8.0.0 has made required changes to align to Appium V2.
  • If you still would like to use Java Client v8 with Appium 1.2.X then consider providing the –base-path explicitly while building the AppiumServiceBuilder.
// From Appium 2.0 Beta
AppiumDriverLocalService service;
service = new AppiumServiceBuilder()
       .withIPAddress("127.0.0.1")
       .usingPort(4723)
       .build();
service.start();
// Older approach: Appium 1.22.X
AppiumDriverLocalService service;
service = new AppiumServiceBuilder()
       .withIPAddress("127.0.0.1")
       .withArgument(GeneralServerFlag.BASEPATH, "/wd/hub")
       .usingPort(4723)
       .build();
service.start();

Changes in Driver Classes

  • SelendroidDriver class is removed
  • Both GeckoDriver and SafariDriver are newly introduced drivers
    • GeckoDriver is an officially supported Appium driver to automate Mobile browsers and web views based on the gecko engine
    • SafariDriver is also an official driver for automating Safari on macOS and iOS

Changes in Element Classes

  • MobileElement classes including AndroidElement and iOSElement classes are removed. It is recommended to use WebElement instead.
  • replaceValue method is now called replaceElementvalue in AndroidDriver class
  • setValue method is removed in favor of the existing sendKeys method.

Touch Actions

The TouchActions and MultiTouchActions classes for automating gestures from your client code have been deprecated. Support for these actions will be removed from future Appium versions. It is recommended to use W3C Actions instead or the corresponding extension methods for the driver (if available). 

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

Refer to the links below to know more about how to work with gestures:

  • https://www.youtube.com/watch?v=oAJ7jwMNFVU
  • https://appiumpro.com/editions/30-ios-specific-touch-action-methods
  • https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/android/android-mobile-gestures.md
  • https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/ios/ios-xctest-mobile-gestures.md
  • https://appiumpro.com/editions/29-automating-complex-gestures-with-the-w3c-actions-api for more details on how to properly apply W3C Actions to your automation context.

App Management

AppiumDriver methods like resetApp, closeApp and launchApp have been deprecated as they are going to be removed from the future Appium versions. Alternatively, the suggested approach is to use removeApp, installApp, and activateApp methods available here. The non-standard way for App Management in iOS is using the mobile: methods to remove the app then install the new application and launch it using the methods here. For Android UIAutomator2 backend, the non-standard mobile: methods like clearApp deletes all data associated with a package, and installMultipleApks allows users to install multiple applications at the same time.

Appium Event Listeners

The current event firing mechanism that Appium Java Client uses has been deprecated in favor of the one that Selenium 4 provides natively. Read The-event_firing.md for more details on how to use it.

Summary

There are a lot of great new changes in this latest Appium Java Client update. You can check out a detailed migration guide here in Appium’s Java Client for reference. Do let us know where there’s been a problem, and thank you. We only have a chance to improve when we know that there’s something that needs work!

The post What’s New in Appium Java Client 8.0.0 appeared first on Automated Visual Testing | Applitools.

]]>
How to Test a Mobile Web App in Cypress https://applitools.com/blog/how-to-test-mobile-web-app-cypress/ Mon, 08 Nov 2021 19:00:32 +0000 https://applitools.com/?p=32376 Cypress is sometimes known as a tool for testing anything that runs in a browser. Here's how you can do mobile testing on the browser with mobile web apps.

The post How to Test a Mobile Web App in Cypress appeared first on Automated Visual Testing | Applitools.

]]>

Before we start, we need to clear up some areas that tend to confuse people when it comes to mobile testing. If you’d like to test a mobile application built for iOS or Android, Cypress will not be efficient and you should probably reach for a tool like Appium (although there are some interesting examples by Gleb Bahmutov for React Native). Cypress is best known as a tool for testing anything that runs in a browser. So in order to use Cypress for your mobile testing, your app needs to be able to run in a browser. That brings forward a question: “What’s the difference between desktop and mobile web app?”

To answer this question, it’s best to look at the application in test from a perspective of a developer. As someone who creates a web application, you might want to consider a couple of traits that make the mobile app different from a desktop one:

  • screen size
  • touch interface
  • any other information about the device

Let’s go through them one by one and see how we can write a Cypress test that would ensure our application works as expected. If you want to follow along, you can clone my repository with the application and attached Cypress tests. The simple example application shows different messages based on viewport width, presence of touch interface or user agent.

Testing the Viewport Size

We might want to test a responsive CSS on different screen widths to see if the application renders correctly. This can be easily done by using the cy.viewport() command. You can specify width and height of the viewport, or choose from one of the predefined devices:

View the code on Gist.

Using these commands will trigger visibility of a “it’s getting pretty narrow here” message:

<the text displays ‘it’s getting pretty narrow here’ on a narrow viewport.

CSS responsiveness can hide or show different content, like buttons or modals. A nice trick to test this is to run your existing tests with different resolution. To do that, pass a --config flag to your CLI command:

npx cypress run --config viewportWidth=320 viewportHeight=480

You can also set the viewport width and viewport height in cypress.json or programmatically via Cypress plugin API. I write about this on my personal blog in a slightly different context, but it still might be helpful in this case.

Depending on your application, you might want to consider testing responsiveness of your application by visual tests using a tool like Applitools. Functional tests might have a tendency to become too verbose if their sole purpose is to check for elements appearing/disappearing on different viewports.

Testing for Touch Devices

Your application might react differently or render slightly different content based on whether it is opened on a touch screen device or not. Manually you can test this with Chrome DevTools:

displays whether we’re viewing the page on a computer that is a touch device, or one that is not.

Notice how we can have a touch device, that is actually not a mobile. This is a nice case to consider when testing your app.

In Chrome DevTools, we are simply switching a mode of our browser. It’s like changing a setting to enable viewing our app as if it was opened on a touch device.

With Cypress we can do something very similar. There is an ontouchstart property which is present on a mobile browser. This is usually a very good clue for a web application to “know” that it is being opened on a touch device. In Cypress, we can add this property manually, and make our application “think” it is being opened on a touch device:

View the code on Gist.

With the onBeforeLoad function, we tap into the window object and add the property manually, essentially creating a similar situation as we did in DevTools, when we toggled the “touch” option:

displays whether we’re viewing the page on a computer that is a touch device, or one that is not, in Cypress.

To go even further with testing a touch interface I recommend using Dmitryi Kovalenko’s cypress-real-events plugin that fires events using Chrome devtools protocol. Your Cypress API will now get augmented with cy.realTouch() and cy.realSwipe() commands, which will help you test touch events.

Testing with User Agent

Some applications use information from user agent to determine whether an app is being viewed on mobile device. There are some neat plugins out there that are commonly used in web applications to help with that.

Although User Agent might sound like a super complicated thing, it is actually just a string that holds information about the device that is opening a web application. Cypress allows you to change this information directly in the cypress.json file. The following setup will set the user agent to the exact same value as on an iPhone:

View the code on Gist.

However, you might not want to change the user agent for all of your tests. Instead of adding the user agent string to cypress.json you can again tap into the onBeforeLoad event and change the viewport on your browser window directly:

View the code on Gist.

The reason why we are not changing win.navigator.userAgent directly via the assignment operator (=) is that this property is not directly configurable, so we need to use the defineProperty method. Opening our application in this way will, however, cause our application to render a message that it is being viewed on mobile device:

shows that we are viewing this page on a mobile

Conclusion

You cannot test native mobile apps with Cypress, but you can get pretty close with mobile web apps. Combining these three methods will help you narrowing the gap between desktop and mobile testing. To understand what makes an app behave differently, it is nice to look into your app as a developer at least for a little while.

If you enjoyed this blogpost, make sure to head over to my personal blog for some more Cypress tips.

The post How to Test a Mobile Web App in Cypress appeared first on Automated Visual Testing | Applitools.

]]>
Hello Appium, Part 1: What is Appium? An Introduction to Appium and its Tooling https://applitools.com/blog/what-is-appium-introduction-to-appium/ Wed, 27 Oct 2021 17:58:51 +0000 https://applitools.com/?p=31964 Learn how to get started with Appium, what Appium is, its architecture and how you can use it to solve your mobile test automation issues today.

The post Hello Appium, Part 1: What is Appium? An Introduction to Appium and its Tooling appeared first on Automated Visual Testing | Applitools.

]]>

In the first article in this series, learn how to get started with Appium. We’ll dig into what Appium is, the essentials of the Appium architecture and how you can use Appium to solve your mobile test automation issues today. You can also skip ahead to read about how to set up your first Appium Android test and how to set up your first Appium iOS test.

I recently had the privilege to speak at Appium Conf 2021 on a topic quite near to my heart: Getting started with Appium.

Why? Isn’t this Quite Basic?

If you are an intermediate or advanced Appium user, then sure, ??‍♂ you may be familiar with this already.

However, I’m a fan of a concept called Shoshin (loosely translated as “Beginner’s mind”) and believe that relearning something opens up new ways of solidifying concepts and often enlightens you about the gaps in your knowledge.

When I started learning Appium back in 2018, I remember I had to struggle a lot to figure out where to start, what setups are needed to run my first test, or just even the underlying architecture.

This was a lot of initial friction and I remember thinking to myself:

It shouldn’t be this hard just to get started, eh?

Appium is a great automation tool and now having used it for a few years and having gone through the trenches I wanted to improve this experience for beginners. Hence the reason for my talk and this blog series. If you are curious about the Appium talk, the video is out on YouTube and slides over a static site.

Key Takeaways

In this 3 part series we’ll deep dive into:

  • Introduction to Appium
    • Understand what Appium is, what problems does it solve?
    • Understand its architecture and tooling needed
  • Set up an Android test from scratch including dependencies
  • Set up an iOS test from scratch including dependencies

Let’s begin.

What is Appium?

Appium is an open source ecosystem of tools and libraries that help you drive your mobile apps (native, hybrid, and mobile web on platforms such as Android, iOS), desktop apps (Windows, Mac), and now even on platforms like Smart TV and much more ?.

Appium Core Philosophy

Language agnostic: With Appium you can choose the language binding of your choice (Such as Java, Kotlin, Python, JavaScript, Ruby, C# … ?) and don’t have to be tied to the programming language of the platform vendors (Kotlin, Swift, etc.).

Does not reinvent the wheel: Appium provides a convenient API compliant with Web driver protocol that wraps automation libraries from vendors (Google UIAutomator2/Espresso, Apple XCUITest/UIAutomation, Windows WinApp) and allows you to write cross-platform tests.

No requirement of SDK or recompilation of the app: Appium can drive the app from a grey box user perspective but does not need any app compilation step.

Cross-platform: Drives apps on different platforms and provided apps have the same business logic, could drive them with a single cross-platform test.

Core Concepts

Before diving into practical setup and tests, it’s important to understand the Appium ecosystem in a birds-eye so that you can make sense of all the different components at play

The below high-level architecture diagram gives the perspective:

Show E2E request from client, server to the target platform

The core components are:

  • Client-server architecture
  • Session
  • Desired capabilities
  • Appium Server
  • Appium Clients
  • Appium Desktop

Client-Server Architecture

Appium Server

  • Appium is a NodeJS-based web server that exposes REST APIs and bridges commands to native frameworks from vendors (Google, Apple)

Appium Clients

  • Appium provides client bindings in different languages that adhere to WebDriver protocol and exposes actions and behaviours for automation
  • Test code makes use of these clients to perform desired actions on devices

E2E Request Flow

A typical request in Appium loosely looks like below:

  • The server receives a connection request from the client
  • The server listens for commands
  • The client makes a request to server
  • Server talks to different platform drivers
  • Drivers talk to native frameworks and finally the common gets executed on the target device (mobile, desktop, TV, etc)
  • The server returns an HTTP response

Session

  • Each action in Appium happens under the context of a session
  • We generally start a session with a Desired capabilities object to specify the exact type of connection we want and what behaviours are we most interested in.

Desired Capabilities

  • Think of this as a Hashmap with the key being a unique capability/behaviour that you want the driver to expose and values with the configurations.
    • For example, you may want to set up the device in landscape or portrait mode for a test case, you can then use either of the below configurations
{
  "orientation": "LANDSCAPE|PORTRAIT"
}
  • You can find the complete reference on Appium docs and I’ll highly recommend you get versed with them. In fact, there was an interesting talk called All Desired Capabilities by Jonah Stiennon in Appium Conf 2019 on this exact topic. You could watch it here.

Appium Inspector

  • A desktop app that supports identifying selector strategies and aids in writing automated tests. Download it from Appium GitHub releases here.

Setup Appium

Now that we understand the high-level components at play, let’s install some of these to set up our environment regardless of the platform that we choose to automate.

To set up the Appium server and other utilities, we’ll need to install npm, node. These could be easily installed with a tool like homebrew (mac), Linux brew (Linux), or chocolatey (windows)

We’ll assume using a Mac/Linux or WSL (Windows Subsystem for Linux) environment for this series but you’ll be able to find equivalent steps for the Windows platform by googling.

Step 1: Install Homebrew

We’ll need it to install npm and node.

To install on macOS:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

On Linux or WSL (Windows Subsystem for Linux), you may need to install Linux brew.

Step 2: Install node and npm

You can download and install node (10+) for your platform. Prefer choosing LTS (Long term support version) since that would be the stable version.

On macOS:

brew install node

Verify running the below command returns desired version:

node -v

And verify that npm is installed as well:

npm -v

Step 3: Install Appium server

To install Appium server < 2.0

npm install -g appium
  • ? Do not use sudo to install Appium server
  • -g indicates that this package would be installed globally

Verify Appium server is installed by typing appium command in your terminal and see all server logs.

➜  appium-fast-boilerplate git:(main) appium
[Appium] Welcome to Appium v1.17.0
[Appium] Appium REST http interface listener started on 0.0.0.0:4723

Appium 2.0 ?

Appium 1.2x.x would be the last version supported by Appium devs and an EOL (End of Life) plan is already published on the Appium Github repo. Read it here. Since Appium 2.0 is the future of the project, let’s see how to install the new server and some key commands.

To install Appium 2.0:

npm install -g appium@next

You’ll get an output like:

/usr/local/bin/appium -> /usr/local/lib/node_modules/appium/build/lib/main.js

> appium@2.0.0-beta.16 postinstall /usr/local/lib/node_modules/appium
> node ./postinstall.js

Not auto-installing any drivers or plugins
+ appium@2.0.0-beta.16
added 113 packages from 587 contributors, removed 316 packages, updated 136 packages and moved 5 packages in 81.611s

With Appium 2.0, drivers are decoupled and not bundled into the main server. This makes sense since if your app is only on Android, you wouldn’t need iOS, desktop, and TV drivers anyways right?

We’ll install Android and iOS drivers for this project using the below commands:

appium driver install xcuitest
appium driver install uiautomator2

You can list all available drivers using the command:

appium driver list

Or list only installed drivers using:

appium driver list --installed

After running the appium command, you’ll see an output like this and as you can see our installed drivers:

[Appium] Welcome to Appium v2.0.0-beta.16
[Appium] Non-default server args:
[Appium]   tmpDir: /var/folders/5d/flg6q03n3j7769kffzly2x_r0000gp/T
[Appium] Attempting to load driver xcuitest...
[Appium] Attempting to load driver uiautomator2...
[Appium] Appium REST http interface listener started on 0.0.0.0:4723
[Appium] Available drivers:
[Appium]   - xcuitest@3.53.1 (automationName 'XCUITest')
[Appium]   - uiautomator2@1.67.0 (automationName 'UiAutomator2')

Step 4: Install Java and Set JAVA_HOME

You can install Java from the Oracle site or the OpenJDK version:

On macOS: If you choose to install OpenJDK, then execute the below command:

brew install openjdk@8
sudo ln -sfn /usr/local/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk

Add JDK home path as JAVA_HOME variable. Since we would use the Java client binding for this series, this is a needed step.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-8.jdk/Home
export PATH=$JAVA_HOME/bin:$PATH

Step 5: Verify Dependencies are Installed with Appium Doctor

Appium doctor is a CLI that provides insights on what dependencies are missing as well as how to install them. It even provides very helpful suggestions or notes on how exactly a dependency might be useful.

Make sure all required dependencies are installed:

npm install -g appium-doctor

Run below commands:

# For both android and iOS
appium-doctor
# For only android
appium-doctor --android
# For only iOS
appium-doctor --ios

If I run it at this point in time, it intelligently warns me about the required dependencies that are installed, optional dependencies that could be installed, and how to go about installing them.

Shows results of executing appium doctor command and dependencies setup

Conclusion

So hopefully you are set up with Appium, have a conceptual understanding of the different components, and are now ready to dive into writing our first tests for Android and iOS. Stay tuned for the next part. In the meantime, you can read the below docs to get further context.

References

Related Appium Articles

Looking for more? We’ve got other great content to help you dig in and get started with Appium. Here are a few places to help you get started with Appium today.

The post Hello Appium, Part 1: What is Appium? An Introduction to Appium and its Tooling appeared first on Automated Visual Testing | Applitools.

]]>
How to Automate Gesture Testing with Appium https://applitools.com/blog/how-to-automate-gesture-testing-appium/ Wed, 13 Oct 2021 07:58:00 +0000 https://applitools.com/?p=31549 Learn the evolution of touch gestures and how you can simplify the way you perform automated tests for gestures using a new plugin in Appium 2.0.

The post How to Automate Gesture Testing with Appium appeared first on Automated Visual Testing | Applitools.

]]>

In the previous blog posts in this Appium series, we discussed step-by-step instructions for creating your own Appium 2.0 Plugins as well as Appium 2.0 Drivers and Plugins usage and its installation. This article discusses the evolution of touch gestures and how you can simplify the way you perform automated tests for gestures using a new plugin in Appium 2.0.

What are Touch Gestures?

Gestures are the new clicks. Gesture-driven devices changed the way we think about interaction. The success of mobile applications depends on how well the gestures are implemented into the user experience. The definitive guide for gestures by Luke Wroblewski details a lot of different actions and how they actually work.

​​

credit: Touch Gesture Reference Guide. Creative Commons

Animations, when paired with Gestures, make users believe in interacting with tangible objects. Appium handles these gestures using the Actions API defined in the W3C WebDriver Specification. It’s great that the API was designed thinking of all interfaces like touch, pen, mouse, etc., but it is hard to understand. Since Appium 1.8, Appium supports the W3C Actions API for building any kind of gesture in mobile devices.

Let’s consider a situation where the application sets specific values based on the slider movements.

Let’s see using Actions API how this situation can be handled.

View the code on Gist.

In the above code snippet, we have three actions to look at which are to get the element location using location API and create a sequence with actions which includes pointerMove, pointerDown, pause, pointerUp, and then perform the sequence. So in this case we need to add these actions in the right order to get the gesture to work. Let’s break down the above in detail to understand what happens under the hood.

  1. Identify the slider element using any locator strategy.
  2. Find the location of the slider element on the screen.
  3. Create a PointerInput object of type TOUCH with a unique id as a finger.
  4. Create a Sequence object with a PointerInput object.
  5. Add individual actions to the sequence.
    1. Pointer move to the slider element location.
    2. Pointer down on the slider element.
    3. Hold for a few milliseconds.
    4. Pointer move the slider to the destination location.
    5. Pointer up from the slider element.
  6. Perform the sequence by calling the Actions API.

Refer to the below image to understand how the element location can be calculated.

A diagram showing a horizontal x axis and a vertical y axis. (x1, y1) is in the top left corner, (x2, y1) is partway across the x axis.

This way any complex gestures can be automated using Actions API.

How the Appium Gestures Plugin Helps

Let’s look at how the gestures plugin from Appium 2.0 simplifies this entire process:

View the code on Gist.

Internally appium-gesture-plugin finds the given element location and does the target location calculation based on the given percentage. It also creates the sequence of actions to perform the gestures on both iOS and Android platforms.

Refer here for a working example of the above swipe gesture using the gestures plugin. Follow the instruction specified here to install the Appium gestures plugin.

For any simple gesture actions (swipe, drag and drop, long press, double-tap, etc.) we can use the gestures plugin. For more custom actions, like if your application has a feature on digital signature, we could still use the Actions API.

Apart from the Actions API, Appium also supports native gesture API which is exposed by Android and iOS platforms through non-standard endpoints like below:

View the code on Gist.

For more such APIs, check out Android non-standard gesture APIs and iOS non-standard gesture APIs.

The post How to Automate Gesture Testing with Appium appeared first on Automated Visual Testing | Applitools.

]]>
Getting Started with Visual UI Testing for Android Apps with Applitools and Bitrise https://applitools.com/blog/getting-started-visual-ui-testing-android-apps-applitools-bitrise/ Wed, 22 Sep 2021 08:21:00 +0000 https://applitools.com/?p=30946 A hands-on guide for getting started with visual UI testing for mobile apps with Applitools and Bitrise easily. Mobile apps play a critical role nowadays in our life, especially during...

The post Getting Started with Visual UI Testing for Android Apps with Applitools and Bitrise appeared first on Automated Visual Testing | Applitools.

]]>

A hands-on guide for getting started with visual UI testing for mobile apps with Applitools and Bitrise easily.

Mobile apps play a critical role nowadays in our life, especially during the pandemic period, like e-commerce, groceries, medical, or banking apps. As we know there are different mobile apps, technologies, SDKs, and platforms that make mobile testing have a lot of challenges and which need special technical skills from the testing team to tackle. 

And because most of the mobile companies aim to release their apps on a weekly or bi-weekly release cadence based on the team decision to deploy new features to the customer before their competitors, they are using different techniques. One of them is test automation.

Based on that, in this article, I’ll walk you through the most important aspects of automating the Visual UI testing for mobile apps and running it via CI/CD pipelines using Applitools and Bitrise. 

What’s Visual Testing?

Visual Testing is a testing activity that helps us to verify that the GUI (Graphical User Interface) appears correctly and as expected to customers, by checking that each element on a mobile app appears in the right size and position on different devices and OS versions. 

Why should we automate Visual UI Testing?

Mobile companies nowadays are applying Mobile DevOps and implementing CI/CD (Continuous Integration and Continuous Delivery/Deployment) pipelines to deploy their mobile apps consistently and frequently. 

Mobile DevOps Lifecycle
Android CI/CD Pipeline

One of the vital parts of this process is test automation, to make sure that app functionalities are working as expected and test that there are no blockers or critical issues in the early stages (Fail Fast) by running these tests on every pull request or as a nightly build. And if we add Visual UI testing with this pipeline we will make sure that there are no issues in the GUI and all the features are displayed correctly. 

In this tutorial, I will add the Visual UI Testing to my Android UI tests with Appium and then run my tests on Bitrise as CI/CD pipeline, covering the following steps:

  1. Implement and run test and locally with Applitools Eyes SDK
  2. Push the code to the GitHub repository
  3. Create Bitrise account and add the project
  4. Add the Applitools Environment Variables 

Let’s get started! 

To get started with Appium for Android applications, you should prepare your local machine with the following requirements:

  • macOS High Sierra or Mojave or Windows 10
  • NodeJS and NPM
  • Java +8
  • Android Studio includes Android SDK +16 (Android Emulator and command-line tools)
  • Appium Desktop
  • Appium
  • Appium Doctor
  • Maven or Gradle for your automation project

More information about installing Appium can be found in the free Appium Course on Test Automation University or in this blog post.

If you don’t have an Android application, you can fork the Sunflower app from GitHub. Sunflower app is a gardening app illustrating Android development best practices with Android Jetpack.

Sunflower Android App

With Appium, you can test automation scripts or projects that are stand-alone. I created a Maven project (you can create a Gradle one if you’d like) with the following structure: 

  1. POM.xml: I added the project dependencies such as testNG, Appium, Eyes Appium Java and created a Maven profile to run the tests from the command line with the maven surefire plugin.
View the code on Gist.
  1. Android_testng.xml: I added my testcase to run it with the maven command line using the maven command (mvn clean test -Pandroid)
View the code on Gist.
  1. FirstAndroidTest.java: it’s the test class where I added my test case and Appium desired capabilities with the following scenario: 
  • Open App
  • Click on Plant List
  • Click on My Garden
  • Click on Add Plant button
  • Click on “Avocado”
  • Click Back
  • Click on My Garden and assert that the plant name is exist
View the code on Gist.

The full project can be found on GitHub.

And now we can run the test using the following command:

> mvn clean test -Pandroid 

And the results will be like the following image:

Run Appium Tests Locally

 

Now it’s time to add the Visual UI validation using Applitools Eyes SDK for Appium

Applitools Eyes is powered by Visual AI, the only AI-powered computer vision that replicates the human eyes and brain to quickly spot functional and visual regressions. 

If you don’t have an account you can create a free account from here.

  1. In the POM.xml file add the following dependency
View the code on Gist.
  1. In the FirstAndroidTest class, initialize the eyes SDK with the following command

Eyes eyes = new Eyes();

  1. In the setUp() void, you can set the private Applitools API key (you can find it in your account) and disable take the full screenshot with the following code: 

eyes.setApiKey("YOUR_API_KEY");

eyes.setForceFullPageScreenshot(false);

  1. In the add_plant_test() void, start the test with the following line:

 eyes.open(driver, "Sunflower", "Add My Plant");

  1. After we open the app, we will add the following line to check that the Plant List screen is displayed correctly: 

eyes.checkWindow("Plant list",false);

  1. Then after we clicked on My Garden, we can add this line: 

eyes.checkWindow("My Empty Garden",false);

  1. After we add the plant in the Garden “Avocado” we will add this line:

eyes.checkWindow("Avocado",false);

  1. At the end of the test, we will add this line to finish the test:

eyes.close();

  1. In the tearDown() void, we will add this line to abort the test if not closed:

eyes.abortIfNotClosed();

10. Now we can run our test again with the same Maven command and check the results in the Applitools Test manager with the steps view. 

Applitools Test Manager

Or the Batch Summary View:

Batch Summary View

11. Try to run the test again and check if the results are the same or if there is an issue. 

In my case when I run the tests again the test failed because the Eyes detected differences between the base images or the first run/batch and the 2nd run. 

Visual UI failed tests

And I checked the dashboard to check the results and the differences:

Failed Test Applitools Test Manager

And I found that I have a difference in the first image which was already highlighted. You can click on the image for more details or compare it with the base image to check the difference. 

Plant List Difference
Showing our base image

Because in my case sometimes the images loaded slowly, there was a difference between the two images. 

And also you can check the Batch Summary View for more details. 

The batch summary of failed tests

TIP: If you need to run on different mobile devices and OS versions in parallel, you can use Applitools Ultrafast Test Cloud. More info on that can be found here.

Configuring your CI for the Eyes

After we successfully run our tests locally, it’s time to integrate our tests with our Android CI using Bitrise. 

But first, we need to do a small change in the application path, Applitools API Key, and the Batch ID. Locally, we’re using the absolute path of the app and hardcoded values, but with Bitrise or our CI server, it should be as an environment variables with the following steps: 

  1. I will set up the values of the environment variables APPLITOOLS_API_KEY and APPLITOOLS_BATCH_ID to provide the API key and batch ID respectively in the setUp() void using the following code:
View the code on Gist.
  1. I will change the APK path to the Bitrise ENV Var because we will build the app in the CI server and then passing it to the Appium test using the following line 

         caps.setCapability("app", System.getenv("BITRISE_APK_PATH"));

  1. Push the code to the GitHub Repository

Now it’s time to integrate our Android app and the automation project with Bitrise.

  1. First, you need to create a new Bitrise account (it’s free). You can use your email or any other account name you prefer.
  1. After logging in, you will have an empty dashboard where you can start adding your projects.
  1. Click on the Add your first app button to add the Sunflower Android app first. 
Adding a new app on Bitrise
  1. Select your account and in the SET THE PRIVACY OF THE APP section select Private or Public, then click Next.
Selecting the privacy of our account
  1. Give Bitrise access rights to your source code provider and choose the repository. 
  1.  Now you need to set up the repository access: click on auto-add SSH key or add your SSH key.
Add SSH key
  1. Choose Branch name, for example, master/main, and click Next.
Selecting a branch name
  1.  After this, Bitrise will run a validation with your repository and configuration.
Bitrise scans the project
  1. After validating, the project build configuration will display successfully (for example, Android App).
Validating the Android Project
  1. Click on the Confirm button after reviewing the Workflow stack. You can add an app icon as well.
Adding an icon to your project

14. The final step is the Webhook setup. We just need to click on Register a Webhook for me! button and you will trigger your first Android build for your project 

Register a Webhook
Kick off the project

15. You will be redirected to the build log where you can check the Steps and the build status.

Trigger Bitrise Build
Bitrise build starter screen
install missing Android SDK

16.  In the end, you will find a summary of all the tasks you ran during the build and how much time they took, along with the Step names. You can download logs or check the apps and artifacts here.

final build results

17. Now let’s open the Workflow Editor to configure the CI Workflow with the new steps required for Appium and Applitools integration. 

open the workflow editor

You can rename the workflow as you like, for example from primary to appium-ui-tests:

rename the workflow name

18. Add a Script step to clone the Appium repository by clicking on the + button and it will open the steps screen, then you can search about the script then select it. 

clone Appium repository

19. As we know, we are using Appium Desktop as a server and inspector locally, but with CI servers we can’t use it, so we need to install and run Appium Server from the command line. Here I’ll add another Script step to install and run the Appium server in the background.

install and run Appium server

20. You will notice that I’m passing –log appium.log with the Appium command to export the server log as a .txt file for more debugging purposes if any tests failed. 

21. Add the AVD Manager Step to create an Android Emulator to use with your tests. You can choose any API level. For example, you can change it to 28 but you need to change it in the Appium desired capabilities and commit the change to your GitHub repository as well.

AVD Manager step

22. Add the Wait for the Android emulator Step and wait for the emulator to be ready before running our tests on it.

wait for Emulator step

23. Add another Script Step to run the UI tests. You need to switch inside the automation project to be able to run the maven command.

run the ui tests

24. Add the Script Step to copy the Appium log file to the Deploy directory of Bitrise to be able to find it in the artifacts tab.

export Appium log to the artifacts folder

25. Add a Step to Export the test results to the Bitrise Test Report Add-on and specify the test results search pattern like this: (*/target/surefire-reports/junitreports/*)

export test results to Test Report add-on

26. Add the Applitools API Key and the Batch ID as environment variables, by click on the Secrets menu option and click add button then add your APPLITOOLS_API_KEY and APPLITOOLS_BATCH_ID like the following image: 

open the Secrets menu
add Applitools Env Vars

The final Workflow will look like the following:

The complete workflow (part 1)
The complete workflow (Part 2)

To run the Workflow, go to the application page and click on the Start/Schedule Build button and select the Workflow then click on the Start Build button.

start the Bitrise build
The clone step in the build
install and run Appium server
create an Emulator with AVD Manager step
wait for the Emulator step
run the UI tests using the Maven command
the final successful build status

To check the test results and the Appium log file you can click on the Test Report add-on, and for the appium log and the app.apk file, you can click on Apps & Artifacts tab.

The test report with the Test Report add-on
the app and the build artifacts

Finally, we successfully added the Visual UI testing for our Android app and we can run the tests on every pull request or as a nightly build to make sure that we don’t have something breaking our codebase and to keep our master branch always green. 

I hope you found this article useful and thank you for reading it! 

Code Repositories

Future Reading

Useful Links

The post Getting Started with Visual UI Testing for Android Apps with Applitools and Bitrise appeared first on Automated Visual Testing | Applitools.

]]>