No one wants to build an amazing web app only to have it fall short due to software bugs that turn users away from everything you’ve worked so hard to build. Fortunately, WebdriverIO helps you plug your tests directly into your favourite browsers so you can iron out any kinks before going live.
This article will take a detailed look at what WebdriverIO is and how to use it to set up automated tests.
What is WebdriverIO?
WebdriverIO is an end-to-end test framework designed to automate modern web applications. In addition, WebdriverIO can also automate mobile applications through either emulation/simulation or on an actual device.
Not to be confused with Selenium Webdriver, WebdriverIO is an independent implementation of Selenium Webdriver’s communication protocol. WebdriverIO is supported by all browsers and does not require you to download a modified browser that you would not actually use.
WebdriverIO benefits
Here are some of the attributes that make WebdriverIO stand out:
Easy extendability
WebdriverIO is easily extendable, enabling you to quickly add helper functions or more complicated sets of existing commands. The framework also has a large distribution of both community-created and built-in plugins that easily integrate to fulfil your testing requirements.
In addition to supporting the WebDriver protocol, WebdriverIO supports protocols from popular mobile testing framework Appium and the Chromium DevTools protocol. This enables you to use WebdriverIO across many projects with varying requirements.
Front-end accessibility
WebdriverIO is built entirely in JavaScript, which is a blessing for most web testers and web developers, who work with JavaScript codebases. WebdriverIO tests are easier to read, write, and debug in teams where everyone works on JavaScript code day-to-day.
WebDriver protocol setting the bar
With the WebDriver wire protocol at its core, WebdriverIO has an industry-leading robust platform of tools for browser automation right at its back. You get the ability to use the best-quality browser automation drivers without the struggle of having to write Java-based tests.
Drivers for the WebDriver protocol exist for all major browsers, meaning that WebdriverIO has the same cross-compatibility.
Open-source
WebdriverIO is still completely open-source with a focus on the JavaScript ecosystem. It’s owned by the non-profit organisation OpenJSFoundation, which has undertaken to grow the platform and keep it up-to-date.
The framework has flexibility in development and is primarily shaped by the community as a whole. There is also a community channel where users can learn from and support each other.
How does WebdriverIO work?
To explain how WebdriverIO works, let’s quickly look at how the WebDriver protocol works under the hood. The WebDriver protocol standard specifies a set of HTTP endpoints for triggering actions in a web browser, like navigating to a specific URL or clicking on an element on a webpage. Each browser, like Firefox or Chromium, implements the WebDriver protocol in its own code to expose the HTTP endpoints described in the standard.
The WebdriverIO framework implements a client for the WebDriver protocol in JavaScript, so it’s able to speak the WebDriver “language” of HTTP endpoints with the various web browsers. (It also implements a different, Chromium-only DevTools standard.) On top of the WebDriver protocol, WebdriverIO also provides a convenient set of primitives for writing tests like CSS query selectors and mock objects, and a simple test runner.
When a developer writes a test using WebdriverIO, the framework interprets the JavaScript test code, issues the corresponding WebDriver protocol commands, ensures that the browser that’s used for testing runs those commands, and then evaluates the outcome of the commands to determine whether the test has succeeded or failed.
How to set up WebdriverIO
To start using WebdriverIO, we’ll first need to know how to set up the framework.
- Install Node.js
To use WebdriverIO, you will need to have a recent version of Node.js installed on your machine. If you’re not sure whether you already have Node.js installed, run node -v
from a command prompt. If you aren’t met with a version of Node.js, you’ll need to install a copy.
Installing Node.js will also install npm, a Node package manager. We’ll use npm in the next step to install the WebdriverIO framework.
- Install WebdriverIO
Next, you will need to install WebdriverIO. Yo can either use the npm package manager that comes with Node.js for this task, or, if your project uses Yarn, you can use that instead.
For npm, run the following command:
npm install @wdio/cli
In Yarn, you’ll need to make a slight variation:
yarn add @wdio/cli
Whichever route you take, the command will download the WebdriverIO tool needed to set up the framework.
- Generate a base config
With the help of the CLI, you’ll want to set up the system by running the following command:
npx wdio config
This prompt will run you through a series of questions to get WebdriverIO set up the way your project requires.
At this point, you are ready to try writing and running your first WebdriverIO test case.
An example WebdriverIO test case
With WebdriverIO installed, let’s put it through a test case.
Our test case uses Mailosaur as the API for automating an email test from a browser.
We add Mailosaur using the yarn add mailosaur
command or the npm install mailosaur
command.
In our example we use Firefox, but it’s possible to use other browsers like Chrome or Safari. Firefox’s implementation of the WebDriver protocol requires that you run the geckodriver proxy application which will in turn interface with the Firefox browser. So, on your machine, you’ll need to download geckodriver from its Releases page and run it in a shell with the command geckodriver --port 4444
.
Below is the folder structure for our WebdriverIO example:
$ tree -I node_modules -L 3
.
├── babel.config.js
├── package.json
├── test
│ ├── pageobjects
│ │ ├── page.js
│ │ └── signup.page.js
│ └── specs
│ └── signup.e2e.js
├── wdio.conf.js
├── yarn-error.log
└── yarn.lock
The key files in our example are as follows:
1 - test/pageobjects/page.js
First, we create a generic Page
page object. As we mentioned earlier, these are used as patterns to make test files more reusable. The Page
object in this example has just one property, but it’s possible to create as many as needed.
/**
* test/pageobjects/page.js
* main page object containing all methods, selectors and functionality
* that is shared across all page objects
*/
export default class Page {
/**
* Opens a sub page of the page
* @param path path of the sub page (e.g. /path/to/page.html)
*/
open (path) {
return browser.url(`https://example.mailosaur.com/${path}`)
}
}
2 - test/pageobjects/signup.page.js
Next, we call upon the Page Object from above that’s specific to the page we want to test. In this instance, we’re testing that a signup page sends an email to the user after they’ve signed up.
import Page from './page';
class SignupPage extends Page {
get inputFirstName () { return $('#firstName') }
get inputLastName () { return $('#lastName') }
get inputEmail () { return $('#email') }
get btnSubmit () { return $('button[type="submit"]') }
async signUp (firstName, lastName, email) {
await (await this.inputFirstName).setValue(firstName);
await (await this.inputLastName).setValue(lastName);
await (await this.inputEmail).setValue(email);
await (await this.btnSubmit).click();
}
open () {
return super.open('signup');
}
}
export default new SignupPage();
3 - test/specs/signup.e2e.js
Finally, we reference our signup page in our actual test file. Here, we use Mailosaur as a source for our test email addresses. Creating an account with Mailosaur generates a serverId
and Token
that we can use to test our outputs.
import SignupPage from '../pageobjects/signup.page';
const MailosaurClient = require('mailosaur');
const mailosaur = new MailosaurClient('token');
const serverId = 'm03agkv6';
const serverDomain = serverId + '.mailosaur.net';
describe('My signup page', () => {
it('should send an email to the signup address', async () => {
await SignupPage.open();
const raptorEmail = 'anchiornis@' + serverDomain;
await SignupPage.signUp('Anchiornis', 'McRaptor', raptorEmail);
const email = await mailosaur.messages.get(serverId, {
sentTo: raptorEmail
});
expect(email.subject).toBe('Welcome to ACME Product');
});
});
To run the test and ensure it works, we use the command npx wdio run ./wdio.conf.js
. As you can see from the output below, our test is successfuland is able to send emails to newly acquired users. In this case, the email is sent to our Mailosaur account to verify the result.
------------------------------------------------------------------
[firefox 88.0.1 mac #0-0] Running: firefox (v88.0.1) on mac
[firefox 88.0.1 mac #0-0] Session ID: 2726969b-50c1-5d49-9acf-c754e6552638
[firefox 88.0.1 mac #0-0]
[firefox 88.0.1 mac #0-0] » /test/specs/signup.e2e.js
[firefox 88.0.1 mac #0-0] My signup page
[firefox 88.0.1 mac #0-0] ✓ should send an email to the signup address
[firefox 88.0.1 mac #0-0]
[firefox 88.0.1 mac #0-0] 1 passing (2s)
Spec Files: 1 passed, 1 total (100% completed) in 00:00:08
Try out Mailosaur to maximise your automated testing in WebdriverIO
In this guide, we saw how Mailosaur can be used to leverage our automated testing process by generating email addresses to which we can send test emails.
At Mailosaur, we offer detailed guides and always have support on hand to help you get started.