What’s new in WebdriverIO v3?

Some big changes came along with v3. We’ve rewritten the whole core to an ajax/promise based monad. Instead of implementing a complex command scheduler or request queues we built the whole library on top of a monad construct. This allows us to chain commands as we are used to and keep stacktraces sane. In addition to that we wanted to have 1st level promise support. Therefore we used the Q library (there are already plans to move to native Promises) to integrate promises into the monad system. This works astoundingly well. Each command execution represents a promise. If you chain commands, the command waits until the previous command is resolved. On top of that, the optional modifier that you can pass to a monad makes the library incredibly flexible and extensible.

Where do I have to change my tests?

Actually, you should be fine with most of your tests. Except all execute commands v3 will support the good old callbacks, so tests like

1
2
3
4
5
6
7
8
9
it('should test something', function(done) {
client
.click('#button')
.getValue('#someInput', function(err, value) {
expect(err).to.be.undefined;
expect(value).to.be.exactly('some value');
})
.call(done);
});

should still pass after moving to v3. However, I strongly recommend rewriting tests as you can remove a lot of obsolete code. Most test frameworks support Promises these days so we should make use of it:

1
2
3
4
5
it('should test something', function() {
return client.click('#button').getValue('#someInput').then(function(value) {
expect(value).to.be.exactly('some value');
});
});

Looks great doesn’t it? Instead of callbacks, call the then function if you are interested in the result of the command. If the command fails for whatever reason, it throws an exception and notifies the test framework. No unnecessary error checks anymore.

Handling asynchronicity in addCommand

In v2.x the function parameter used to have a callback that would get called once you were done with your steps. Here is an example:

1
2
3
4
5
6
7
8
9
client.addCommand("getUrlAndTitle", function(customVar, cb) {
this.url(function(err,urlResult) {
this.getTitle(function(err,titleResult) {
var specialResult = {url: urlResult.value, title: titleResult};
cb(err,specialResult);
console.log(customVar); // "a custom variable"
})
});
});

With v3 we switched over to a promised based execution flow. Therefore the callback parameter is gone and gets replaced by a promise you need to return in that function. Once that promise is resolved the command queue continues. The example above looks in v3 like this:

1
2
3
4
5
6
7
8
client.addCommand("getUrlAndTitle", function(customVar) {
return this.url().then(function(urlResult) {
return this.getTitle().then(function(titleResult) {
console.log(customVar); // "a custom variable"
return { url: urlResult.value, title: titleResult };
});
});
});

What else?

Here is a list of thing that got introduced with v3

  • Finally this release includes Multiremote functionality. It allows you to run multiple instances at the same time, enabling integration tests of applications that require more than one session. See more in the multiremote section.
  • WebdriverIO now provides its own test runner to run tests in parallel and to help you get your tests up- and running quickly. It is called wdio and takes a config file as parameter. After you’ve defined your capabilities and test specs in that config file just run the test runner to run test in parallel. See more in the test runner section.
  • Due to the new monad based core, WebdriverIO is now able to chain selectors. This makes querying deeply nested elements super easy. Checkout the selector section for more information.
  • Removed the waitFor command as it is basically the same as waitForExist
  • Added debug command to help you debug your tests. It stops the queue and allows you to jump into the browser to open dev tools and to check the state of your app. After you are done with debugging you can jump back into your terminal, press enter and continue running your test.