hcoelho.com

my blog

Making a test suite for the front-end client

:

Test cases are a very important tool to have: they help us to know whether or not the program is working properly, and they also assure that future updates will not break what was already done. Making these tests on the backend of a program is relatively simple and common, but when we need to test the user interface, it gets a little more complicated. For our project, we have a JavaScript code that goes in the browser (the Observer), and we need to make sure all its functions that depend on the user input are working properly. In this post I will explain how I used Webdriver.io to simulate user interactions for our client module.

Selenium is an application that automates your browser - it provides the tools that we need to create the user interactions, while Webdriver.io is a Selenium ported for Node.js; but to use Webdriver.io, we need selenium installed. It was simple enough, just using these commands:

$ curl -O http://selenium-release.storage.googleapis.com/3.0/selenium-server-standalone-3.0.1.jar
$ curl -L https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz | tar xz
$ java -jar -Dwebdriver.gecko.driver=./geckodriver selenium-server-standalone-3.0.1.jar

And done, Selenium is installed and running.

Now, to install Webdriver.io in our node project, we can simply use NPM:

npm install --save-dev webdriverio

And we are ready to go.

In a javascript file - the one we used to run the routines in the browser, we configure and start Webdriver.io this way:

const webdriverio = require('webdriverio');

const options = {
    desiredCapabilities: { browserName: 'firefox' }
};

It is a very simple configuration in our case, since we want to use Firefox to run the test cases, and no other options were necessary. We can also use PhantomJS (an "invisible browser", but I think it is useful to have Firefox appearing, so we can inspect what exactly is happening).

Now to start Webdriver.io and make it go to our test page:

webdriverio
    .remote(options)
    .init()
    .url('file:///<path>/file.html')

When we run this javascript file, Firefox will pop up and open that file specified.

Now some commands we used to simulate user interaction:

webdriverio
    .remote(options)
    .init()
    .url('file:///<path>/file.html')

    // Telling Webdriver.io to click on a link (<a> tag) with the id "my-link":
    .click('a#my-link')

    // Scrolling 300 pixels to the bottom and to the right
    .scroll(300, 300)

    // Filling an input (<input> tag) with the class "my-input" (the first input with this class, in this case) with the value "text""
    .setValue('input.my-input', 'text')

    // Selecting the third option of a select box (<select> tag) with the id "my-select"
    .selectByIndex('select#my-select', 2)

    // Pausing for 2 seconds
    .pause(2000)

    // Executing a JavaScript function in the browser and logging "Hello world" in the browser's console
    .execute(function () {
        console.log('Hello world');
    })

    // Closing the browser and ending the tests
    .end();

That's it! Using Webdriver.io was surprisingly simple, and I was able to complete all the tests in a few hours.

Some commands were not available by Webdriver.io, for example: selecting a text on the page. But I could overcome this using the .execute command and passing a function to select the text I wanted directly from the browser:

.execute(function () {
    // Element with the text to be selected
    const element = document.getElementById('div-with-text-to-select');

    // Creating a range around the element and setting it as the selection
    const range = document.createRange();
    range.setStartBefore(element);
    range.setEndAfter(element);
    window.getSelection().addRange(range);
})

I was also able to fire custom events in the browser using the .execute command:

.execute(function () {
    // I want to fire the event from this element
    const element = document.getElementById('source-of-event');

    // Creating my custom event
    const event = new CustomEvent('eventName');

    // Firing
    element.dispatchEvent(event);
})

cdot javascript frontend test selenium webdriver