Originally posted on blog.kevinlamping.com
Automated UI tests don't get a lot of love.
Sure, they're popular to give presentations and write blog posts about, but in my experience, not a lot of companies out there have a solid UI test suite set up.
Let's define UI tests as any automated test that controls a browser-like interface.
The point is that the tests are using a website in the traditional sense. We open a page, click some element, and verify some functionality.
So why the lack of use? Seems like these types of tests would be incredibly useful.
And they are, when you can get them to work.
There are four common issues I've run in to:
- Most tools use Java, which is way too verbose for testing purposes
- Tools written in NodeJS are often limited to PhantomJS, preventing you from testing in real browsers.
- Writing commands for Selenium is complex and error-prone
- Tools work great, until you scale them beyond their limits
Thankfully, WebdriverIO has the antidote to all of these ailments.
WebdriverIO is "Front-end Friendly"
Unlike a lot of Selenium tools out there, WebdriverIO is written entirely in JavaScript. Even the Selenium installation is done through an NPM module.
I always thought browser automation meant figuring out how to get some complex Java app running, which just never sounded appealing to me. There's also the Selenium IDE, but writing tests through page recordings reminded me too much of WYSIWYG web editors like Microsoft FrontPage.
Instead, WebdriverIO lets me write in a language I'm familiar with, and integrates with the same testing tools that I use for unit tests (Mocha and Chai).
The mental load to switch from writing the actual functionality in JavaScript to writing the test code in JavaScript is minimal, and I love that factor.
The other great thing, and this is more to credit Selenium than WebdriverIO, is that I can use advanced CSS selectors to find elements.
xPath scares me for no good reason. Something about slashes instead of spaces just chills my bones.
But I don't have to learn xPath.
Using WebdriverIO, I simply pass in my familiar CSS selector and it knows exactly what I'm talking about.
I believe Front-end developers should write tests for their code (both unit and functional). WebdriverIO makes it incredibly easy to do.
It Has the Power of Selenium
I always felt held back when writing tests in PhantomJS, knowing that it could never validate functionality in popular but buggy browsers like IE.
But because WebdriverIO uses Selenium under the hood, I'm able to run my tests in all sorts of browsers.
Selenium is an incredibly robust platform and an industry leader for running browser automation. WebdriverIO stands on the shoulders of giants by piggybacking on top of Selenium. All the great things about Selenium are available, without the overhead of writing Java based tests.
It Strives for Simplicity
The commands you use in your WebdriverIO tests are concise and common sense.
What I mean is that WebdriverIO doesn't make you write code to connect two parts together that obviously are meant for each other.
For example, if I want to click a button via a normal Selenium script, I have to use two commands. One to get the element and another to click it.
Why? It's obvious that if I want to click something, I'm going to need to identify it.
WebdriverIO simplifies the 'click' command by accepting the element selector right in to the command, then converts that in to the two Selenium actions needed. That means instead of writing this:
driver.findElement(webdriver.By.id('btnG')).click();
I can just write this:
browser.click('#btnG')
It's just so much less mind-numbing repetition when writing tests...
Speaking of simple, I love how WebdriverIO integrates in to Selenium. Instead of creating their own Selenium integration, they use the common REST API that Selenium 2.0 provides and make plain old Request calls to it.
Here's an example from core WebdriverIO code of the elementActive
protocol:
let elementActive = function () {
return this.requestHandler.create({
path: '/session/:sessionId/element/active',
method: 'POST'
})
}
That's it. That's basically the entirety of the file/function.
Understanding what's going on here is pretty simple. We're sending a POST request to the "element/active" endpoint and returning the response.
I'm still learning Node.js, so it's refreshing to see software where I have some idea what's going on.
Most of the library is made up of these small commands living in their own separate small file. This means that updates are easier, and integration into cloud Selenium services like Sauce Labs or BrowserStack are incredibly simple.
Too many tools out there try and re-invent the wheel, just for the sake of it. I'm glad WebdriverIO keeps it simple, in turn helping me easily understand what's going on behind the scenes.
It's Easily Extendable/Scalable
As someone who has spent a considerable portion of my career working for large organizations, it's important to me that the tools I'm using be easily extendable.
I'm going to have custom needs and want to write my own abstractions, in order to reduce the burden on the developers I'm supporting.
WebdriverIO does a great job at this in two ways:
Custom Commands
There are a ton of commands available by default via WebdriverIO, but a lot of times you want to write a custom command just for your application.
WebdriverIO makes this really easy.
Just call the "addCommand" function, and pass in your custom steps.
Here's an example from their docs:
browser.addCommand("getUrlAndTitle", function (customVar) {
return {
url: this.getUrl(),
title: this.getTitle(),
customVar: customVar
};
});
Now, any time I want both the URL and Title for my test, I've got a single command available to get that data.
Page Objects
With the 4.x release of WebdriverIO, they introduced a new pattern for writing Page Objects. For those unfamiliar with the term, Page Objects are a way of representing interactions with a page or component.
Rather than repeating the same selector across your entire test suite for a common page element, you can write a Page Object to reference that component.
Then, in your tests, you just ask the Page Object for what you need and it handles it for you.
This means tests are both more maintainable and easier to read.
They're more maintainable because updating selectors and actions occur in a single file.
When a simple HTML change to the login page breaks half your tests, you don't have to find every reference to input#username
in your code. You only have to update the Login Page Object and you're ready to go again.
They're easier to read because tests become less about the specific implementation of a page and more about what the page does.
For example, say we need to log in to our website for most of our tests. Without page objects, all our tests would begin with:
browser.url("login-page")
browser.setValue("#username", "testuser")
browser.setValue("#password", "hunter2")
browser.click("#login-btn")
With page objects, that can become as simple as:
LoginPage.open();
LoginPage.login('testuser', 'hunter2');
No reference to specific selectors. No knowledge of URLs. Just self-documenting steps that read out more like instructions than code.
Now, Page Objects aren't a new idea that WebdriverIO introduced. But they way they've set it up to use plain JavaScript objects is brilliant. There is no external library or custom domain language to understand. It's just JavaScript and a little bit of prototypical inheritance.
Summing It Up
I don't consider myself a tester.
I'm far too clumsy to be put in charge of ensuring a bug-free launch.
Yet I can't help but love what WebdriverIO provides me, and I'm really a fan of what they're doing and hope the project continues to grow strong.
If you're a front-end dev, or just familiar with JavaScript, check out WebdriverIO and see if you find it as awesome as I do.
Top comments (0)