Writing automation test cases using Ga-wdio for mobile application.

Ga-wdio what it is

Ga-wdio is an automation CLI tool that creates the tests project for the Web, the API & the Mobile (iOS & Android) App / Browser. Runs various things like GeckoDriver , ChromeDriver & Appium internally for various stacks, browsers & modes.

Why should you use Ga-wdio

Ga-wdio provides many features like creating a boilerplate, checking the appium's necessary & optional dependancies on the system

You can check all the features provided by ga-wdio here .

Setup for Ga-wdio & appium for mobile app testing

To setup Ga-wdio & appium just run the simple 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

To setup android and IOS environment you need to do follow some steps from the following link from the official documentation.

github.com/GeekyAnts/ga-wdio/wiki/Mobile-En..


Following are some issues you might face while writing tests for a mobile application and solutions for them.


To perform automation test 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 locate.

Adding testID & getting xpath in 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 params 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 and interacting with elements using Xpath

We have used Xpath to select and interact with element using ga-wdio. For finding Xptah or accessibility 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 image, 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 gesture & web view on ga-wdio

Working with gestures

In most of the application use touch gesture for interactivity, navigation and scrolling content.

Appium provides touchPerform function to handle the 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 application content on mobile screen is longer than the height of mobile specially for forms.

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

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 with Hybrid app, that is Native + webview. By default we will have NATIVE_APP as the current context. If a webview is loaded then we will have two context as ["NATIVE_APP","WEBVIEW_28158.2"] We can get list of available context by using driver.getContexts(); method.

We can not start looking 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 supported by webdriver.io. We can use these in config (android.conf.js/ios.conf.js )files.

I was asked to create a custom log report and send it over mail after completion on tests.

For implementing the same I have used after, afterTest and onComplete hooks in configs.

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

Checkout all the hooks here.

Writing test cases scenario

Usually we are writing test cases on JS using chai or mocha. Sample code snippet for login test .

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;

Useful links

Thank you for reading. Cheers !