Passion for quality is inculcated within everyone at Calcey and especially the QA professionals take the lead in ensuring every product, release, and delivery is meets expected standards. As a project-based company, we work with diverse business domains and functionalities. We all believe that testing plays an essential part of a project. Automating testing in every project regardless of its size, domain or the environment has been a challenge. To overcome this, we have come up with a handful of brittle tests but it has always been a challenging task to make it into a resilient test suite.

A few months ago we saw the extendable, compatible and feature rich WebdriverIO and decided to give it a go. We implemented a robust automation framework by customizing the features in the WebdriverIO and made it useful for any test environment such as mobile, web and API. Since then, progress with our automation plans has been extremely positive. The secret is that test scripts are easy to write, understand and maintain when it comes to WebdriverIO. Now we are able to write test cases for both web and mobile applications and with a coverage of nearly 70%. We can generally trust that a green build correctly means that the release is ready to go.

In this blog post, I’ll provide a walk through of how we managed to introduce this development and the tools that we have put in place to make it easier for our QA team to write and execute the tests.

I believe the famous Page Object Model (POM) made our path easier. Basically, the WebdriverIO is designed with the influence of page object design pattern. As stated in the WebdriverIO developer guide (http://webdriver.io/guide.html),

“By introducing the “elements as first-class citizens” principle it is now possible to build up large test suites using POM pattern. There are no additional packages required to create page objects. It turns out that “Object.create” provides all necessary features we need, such as inheritance between page objects, lazy loading of elements and encapsulation of methods and actions.”

Likewise, WebdriverIO facilitates quite a lot of necessary features to make the code look simple, concise and easy to read. In fact, it supports async programming concepts, so you don’t need to worry about handling a promise anymore. Typescript has been the buzzword these days due to many advantages it has, thus we have written our scripts with TypeScript which is a strongly typed superset of plain old Javascript. Further, Chai Assertion Library has been used for test assertion and Jasmine as the test runner both which allow you to write your tests in behavior driven development (BDD).

So far this has been a killer combination which provides a cleaner and faster control for testing any app thus meeting business requirements in a more reliable and scalable way!

So it’s time for us to get hands-on with WebdriverIO. For demo purposes, let’s use todomvc.com as guinea pig. This is a simple website built using react and the user can add his daily to-do notes one below the other.

Before we start, make sure to

Detailed steps can be found here.

Now that we are all set with our environment, it’s better we to plan out how we are going to maintain our tests and have a proper structure for writing our tests. After some research, we decided to go with the page object pattern. Page Object pattern is well-known in the world of test automation for enhancing test maintenance and reducing code duplication. Fortunately, the version 4 of WebdriverIO  test automation framework was designed with Page Object pattern in mind.

Let’s try to build a page object example for the to-do note page. The first step is to write the all important selectors that are required in our object as getter functions.

 

import { Client, Element, RawResult } from 'webdriverio';

import { CompletedPage } from '../completed/completed.page';

export class ToDoPage {

  private newTodo = 'input[class=new-todo]';
  private todoList = 'ul.todo-list li';
  private lastTodo = 'ul.todo-list li:last-child';
  private navigationLink = 'a[href=\'#/completed\']';
 
  get todoInput() : Client<RawResult<Element>> {
    return browser.$(this.newTodo);
  }
 
  get todoListLength() : number {
    return browser.$$(this.todoList).length;
  }
}

In the code shown above, we are using two get methods one to get a new to-do element and another to get the number of to-do lists present on that page.

Similarly, we can further write other methods needed such as navigating, completing and clicking an element as shown below.

 

public addToDo(todo): void {
  this.todoInput.waitForVisible();
  this.todoInput.setValue(todo);
  browser.keys('\uE007');
}

public navigate(): void {
  browser.windowHandleMaximize();
  browser.url('/examples/react/#/');
}

public completeLastTodo(): void {
  browser.$(this.lastTodo).click();
}

public navigateToCompleted(): CompletedPage {
  browser.$(this.navigationLink).click();
  return new CompletedPage();
}

After defining all required elements and methods for the page it’s time for us to write the tests using them. In the test class we are using the methods in the to-do class we created earlier using the import command as follows.

 

import { ToDoPage } from './todo.page';

We are using mocha’s BDD syntax to write our tests, therefore, each test suite and the case is defined by a describe or it block, respectively. The test suite begins with a describe function which takes two parameters:

  1. String – This describes what the test suite will be doing.
    eg: “Todo Page”
  2. function – This is the block of code that will execute what we described
    eg: describe(‘Todo page’, function() { });

 

describe('todo page', () => {
  let n = 0;
  let todoPage: ToDoPage;
  
  afterEach((done) => {
    const filename = './e2e/screenshots/Todo_'.concat(String(n), '.png');
    browser.saveScreenshot(filename);
    n += 1;
  });
}

Then, we will start to write the specs of the test which will begin with it function. The it function takes two parameters.

  1. String – This describes the test specification
    1. “Should add todo”
    2. “Should remove completed”
  2. function – This is the block of code that will execute what we described
    1. it(‘should add todo’, function() { });

WebdriverIO sets up the test hooks in it’s config file by default. Each hook is executed at different stages of the test’s flow, with the before hook running once per describe block, before any it blocks are run.

A spec contains one or more expectations that test the state of the code which is called assertions. In almost all cases, you will need to locate one or more elements using a selector, then perform some operation on the element(s)

  • Examples:
    • Find text on a page and verify the text
    • Verify CSS properties of an element

For the assertion purpose, we have installed an assertion library called Chai! Chai provides three different styles (Expect, Should, and Assert), that allow you to write syntactically attractive assertions. We’ll be going with Expect for the moment. We can either initialize Expect in the Before hook located in the wdio config file or just import it into our test class.

 

import { expect } from 'chai';

After declaring Chai and Expect, we can now add the first assertion to our test.

 

it('Should add todo', () => {
  let todoListLength = todoPage.todoListLength;
  todoPage.addToDo("New Todo");
  const newTodoListLength = todoPage.todoListLength;
  
  expect(newTodoListLength).to.be.equal(todoListLength + 1);
});

it("Should remove completed", () => {
  let todoListLength = todoPage.todoListLength;
  todoPage.addToDo("New Todo 2");
  const newTodoListLength = todoPage.todoListLength;
  
  expect(newTodoListLength).to.be.equal(todoListLength + 1);
  
  let completedPage = todoPage.navigateToCompleted();
  const currentCompletedTodos =  completedPage.todoListLength;
  
  todoPage = completedPage.navigateToToDoList();
  todoPage.completeLastTodo();
  
  completedPage = todoPage.navigateToCompleted();
  const newCompletedTodos = completedPage.todoListLength;
  
  expect(newCompletedTodos).to.be.equal(currentCompletedTodos + 1); 
});

In the above code, we are adding a new to-do form (‘Should add todo’). After adding the to-do form, using the expect command we verify whether the number of to-do forms available now is 1 more than the number of to-do forms before. If this expectation passes we can conclude that the particular test is passed.

Finally it’s time for us to run our tests. Open the terminal and change the directory to the folder where the wdio file is located

Enter the command “npm test” and press enter and your tests will start to run.

The test results will be shown as above in the terminal and if needed you can add 3rd party test reporters such as allure which is supported by WebdriverIO.

There you have it, that’s how you get started test automation with WebdriverIO. Try it out and let us know what you think.