GA-WDIO: Automating Mobile App Testing

A tool that creates and runs tests automatically and accurately.

What is GA-WDIO?

GA-WDIO is an automation CLI tool that creates tests for Web Apps, APIs & Mobile (iOS & Android) Apps/Browsers. Behind the curtains, it runs numerous tools like GeckoDriver, ChromeDriver & Appium internally for various stacks, browsers & modes for efficient testing.

GA-WDIO was conceptualized internally at GeekyAnts to automate the generic testing scenarios that every app, be it web or mobile, would have to go through to pass the first few levels of testing (apart from very specific test cases that need to be made manually). This tool managed to automate a lot of redundant testing work and cut down on the total development time for projects.

Why should you use GA-WDIO?

This tool comes with quite a lot of features that are inbuilt, like creating a boilerplate, checking Appium's necessary requirements & optional dependencies on the system, but that's not all.

Have a look at this comprehensive list of all the features provided by GA-WDIO here .

Setup For GA-WDIO & Appium For Mobile App Testing

To setup GA-WDIO & Appium, just run this simple npm command:

npm install -g ga-wdio appium

ga-wdio create

It will create a project using the boilerplate provided by GA-WDIO. Screenshot 2021-01-18 at 12.30.31 PM.png

That's It !
GA-WDIO is ready to use now.

Setting Up Android & iOS Automation Testing

Setting up an environment for Android and iOS is quite easy to do. You will need to follow the steps from the official documentation which can be found at this link.


Using GA-WDIO is pretty simple, but you might find yourself stuck with a few things if you're new to this tool. The following are some issues that you might face while writing tests for a mobile application and what you can do to solve them.

A Background On Performing tests

To perform automation tests, we need to find specific elements on which we can perform test actions. For this tutorial, we will be using xpath to find elements. Also, we have to pass testId and accessibilitylabel to react-native components to make them be able to locate these elements.

Adding testID & getting xpath In A React Native App

Let's first add testId and accessibilityLabel to our React Native project.

To add testId, we just need to pass accessibilityLabel and testID parameters as props to the component.

<Component accessibilityLabel={ 'FOO' } testID={ 'FOO' } />

Also in much cleaner way we can create a function in utils and pass an Id

 export function testProps (id) {
    return {testID: id, accessibilityLabel: id};
  }

<Component ...testProps('FOO') />

Finding & Interacting With Elements Using xpath.

We have used xpath to select and interact with elements using GA-WDIO.

For finding xpath or accessibilityLabel.id, I have used Appium Desktop

With Appium Desktop, you can find any element and its locators by either clicking the element on the screenshot or locating it in the source tree.

Checkout this link for more information about finding the element.

Screenshot 2021-01-18 at 1.45.53 PM.png

Using Gestures & Web View On GA-WDIO

Working With Gestures

Most applications use touch gestures for interactivity, navigation and scrolling content, which needs to be tested as well.

Appium provides the touchPerform function to automate and handle gestures.

/*    This is a swipe up
       const from = { x: 100, y: 250 }
        const to = { x: 100, y:50 }
*/

swipe (from, to) {
        driver.touchPerform([{
            action: 'press',
            options: from,
        }, {
            action: 'wait',
            options: { ms: 1000 },
        }, {
            action: 'moveTo',
            options: to,
        }, {
            action: 'release',
        }]);
        driver.pause(1000);
    }

In many applications, the content on the screen is longer than the height of the physical screen on which it is displayed, especially in the case of forms.

If the element we need to test is below the visible area on the device, testing tools will not be able to find that element. In such a situation, we have to scroll until we find the element and then perform the necessary tests.

checkIfDisplayedWithScrollDown (element, maxScrolls, amount = 0) {
        if ((!element.isExisting() || !element.isDisplayed()) && amount <= maxScrolls) {
            this.swipe(from, to);
            this.checkIfDisplayedWithScrollDown(element, maxScrolls, amount + 1);
        } else if (amount > maxScrolls) {
            throw new Error(`The element '${element}' could not be found or is not visible.`);
        }
    }

Working with webview

When we are working Hybrid apps (i.e. Native + webview), by default, we will have NATIVE_APP as the current context. If a webview is loaded, then we will have two contexts, much like the following:

["NATIVE_APP","WEBVIEW_28158.2"]

We can get a list of available contexts by using the driver.getContexts(); method.

We cannot look for a particular element in webview if webview is not rendered or not fully loaded.

We can use following methods to confirm these conditions:

export const CONTEXT_REF = {
    NATIVE: 'native',
    WEBVIEW: 'webview',
};
const DOCUMENT_READY_STATE = {
    COMPLETE: 'complete',
    INTERACTIVE: 'interactive',
    LOADING: 'loading',
};

// Wait for the webview context to be loaded

    waitForWebViewContextLoaded () {
        driver.waitUntil(
            () => {
                const currentContexts = this.getCurrentContexts();

                return currentContexts.length > 1 &&
                    currentContexts.find(context => context.toLowerCase().includes(CONTEXT_REF.WEBVIEW));
            }, {
                timeout: 10000,
                timeoutMsg: 'Webview context not loaded',
                interval: 100,
            },
        );
    }

 // Wait for the document to be full loaded

    waitForDocumentFullyLoaded () {
        driver.waitUntil(
            () => driver.execute(() => document.readyState) === DOCUMENT_READY_STATE.COMPLETE,
            {
                timeout: 15000,
                timeoutMsg: 'Website not loaded',
                interval: 100,
            },
        );
    }

Working with Hooks

GA-WDIO allows you to implement hooks, that are supported by webdriver.io. We can use these in the Android config(android.conf.js/ios.conf.js) files.

You can also create a custom log report and send it over mail after successful completion of the tests.

For implementing the same , you can use after, afterTest and onComplete hooks in the config files in the following manner:

  onComplete: async (result) => {
    await sendReport(process.env.GA_SESSION_ID);
  }

Check out all the hooks that are available for use here.

Writing Test Case Scenarios

Usually, when we are writing test cases in JS, we use tools like Chai or Mocha.

The following is a sample code snippet for testing the 'Login' feature:

import TabPage from "../common/TabPage";
import Login from "../common/Login";

describe("Test login elements", () => {
    it("It should go to login page", () => {
        TabPage.login.click();

        Login.email.click();

        Login.email.setValue("test@webdriver.io");
        Login.password.setValue("Test1234!");
        if (driver.isKeyboardShown()) {
            driver.hideKeyboard();
        }

        Login.loginButton.click();
        Login.loginAlert.click();
    });
})
const xpath = require("../xpath");
const tabXpath = xpath("tabPath.json");

class TabPage {
    get home() {
        return $(tabXpath.HOME);
    }
    get webView() {
        return $(tabXpath.WEB_VIEW);
    }
    get login() {
        return $(tabXpath.LOGIN);
    }
    get forms() {
        return $(tabXpath.FORMS);
    }
    get swipe() {
        return $(tabXpath.SWIPE);
    }
}

export default new TabPage;

Thank you for reading. I hope that you will give GA-WDIO a shot and make testing much easier and faster for your projects. Do leave some ❤️ if you like the article.

Cheers !

No Comments Yet