webdriverio: Inconsistent error stack in standalone mode

OS: Mac OS X 10.11.4 x86_64 Node: v6.3.1 Selenium Version: v2.53.1, with Core v2.53.1. Built from revision a36b8b1 webdriver.io: 4.2.16

When a callback provided to webdriver.io throws an exception or returns a rejected promise, the client properly bubbles up the error, except when chaining .end().

I tested errors generated as follows:

  • throw new Error("an exception happens here")
  • return Promise.reject(new Error("a promise gets rejected"))
  • return Promise.reject("a promise gets rejected")

Here is a demonstration of throwing an exception that works properly:

var promise = webdriverio
    .remote(options).init()
    .url('http://www.google.com')
    .getTitle().then(function(title) {
        throw new Error("an exception happens here");
        console.log('Title was: ' + title);
    });
    promise.end();
showError(promise);

function showError(promise) {
    if (typeof promise.then === 'function') {
        promise.catch(function (err) {
            if (err instanceof Error)
                console.log(err);
            else
                console.log("Rejected promise: "+ err);
        });
    }
    else
        console.log("not a promise");
}

// Error: an exception happens here
//     at Object.<anonymous> (/repos/arepo/tests/test_errs.js:26:15)
//     at Object.exec (/repos/arepo/node_modules/webdriverio/build/lib/helpers/safeExecute.js:28:24)
//     at Object.resolve (/repos/arepo/node_modules/webdriverio/build/lib/webdriverio.js:189:29)

If we instead return the result of chaining .end(), we get this:

var promise = webdriverio
    .remote(options).init()
    .url('http://www.google.com')
    .getTitle().then(function(title) {
        throw new Error("an exception happens here");
        console.log('Title was: ' + title);
    })
    .end();
showError(promise);

// Error: an exception happens here
//     at title() - getTitle.js:29:28
//     at end() - webdriverio.js:16:6

For completeness, here are comparisons of chaining vs not chaining returning rejected promises:

        return Promise.reject(new Error("a promise gets rejected"));

/* NOT CHAINED */
// Error: a promise gets rejected
//     at Object.<anonymous> (/repos/arepo/tests/test_errs.js:56:31)
//     at Object.exec (/repos/arepo/node_modules/webdriverio/build/lib/helpers/safeExecute.js:28:24)
//     at Object.resolve (/repos/arepo/node_modules/webdriverio/build/lib/webdriverio.js:189:29)

/* CHAINED */
// Error: a promise gets rejected
//     at title() - getTitle.js:29:28
//     at end() - test_errs.js:45:6
        return Promise.reject("a promise gets rejected");

/* NOT CHAINED */
// Rejected promise: a promise gets rejected

/* CHAINED */
// (nothing is output in this scenario)

I suspect a decision must be made about whether .end() should return a promise that propagates a callback error. If the answer is yes, it should be made consistent. If the answer is no, .end() should return no error information instead of a confused mix of information. The inconsistencies had me pulling my hair out looking for the proper resolution.

My preference is to be able to include include the following in my tests and have it properly propagate errors to the test harness:

var t = require('tap');

t.test("load the home page", function (t) {
    return webdriverio
        .remote(options).init()
        .url('http://www.google.com')
        .getTitle().then(function(title) {
            console.log('Title was: ' + title);
        })
        .end();
});

Note that tap will handle properly returned promises in these error scenarios, reporting the errors.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 33 (8 by maintainers)

Most upvoted comments

I see. Thanks for the explanation.

Have you checked out our page object example (or this page)? This is how many WebdriverIO user write their e2e tests and do like it. I agree on the points you mentioned above on Mocha but starting monkeypatching a different framework also don’t seem to be a good solution. At the end of the day it matters how quick and stable you can write your e2e tests and with this solution (wdio + page objects + mocha) you can do so at high scale. Going back to something that runs commands on promises will introduce race conditions pretty quickly, also building the whole setup by yourself and maintaining it also eats up a lot of time. We will look into an integration with tape asap but it wouldn’t change much in regards of the test procedure.