-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allowUncaught in 2.3.0 doesn't work for async errors #1801
Comments
It looks like this is going to be a little harder to get right. I'm using expect.js which throws an exception if an |
I've been writing my tests like this: it('foo', function (done) {
visit('/bar');
andThen(() => {
expect(baz).equal(quux);
done();
});
});
Then I switched to async/await for readability: it('foo', async function (done) {
await visit('/bar');
expect(baz).equal(quux);
done();
}); When the assertion fails, I receive an "Unhandled promise rejection" error in browser console. To avoid it, I had to do this: it('foo', async function (done) {
try {
await visit('/bar');
expect(baz).equal(quux);
done();
} catch (e) {
done(e);
}
}); I hate try/catch, but the try block is still more readable than with It works now, except that To resolve this, |
This monkey patch is a proof of concept: Mocha.Runnable.prototype.run = function (fn) {
var self = this;
var start = new Date();
var ctx = this.ctx;
var finished;
var emitted;
// Sometimes the ctx exists, but it is not runnable
if (ctx && ctx.runnable) {
ctx.runnable(this);
}
// called multiple times
function multiple(err) {
if (emitted) {
return;
}
emitted = true;
self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
}
// finished
function done(err) {
var ms = self.timeout();
if (self.timedOut) {
return;
}
if (finished) {
return multiple(err || self._trace);
}
self.clearTimeout();
self.duration = new Date() - start;
finished = true;
if (!err && self.duration > ms && self._enableTimeouts) {
err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.');
}
fn(err);
}
// for .resetTimeout()
this.callback = done;
// explicit async with `done` argument
if (this.async) {
this.resetTimeout();
if (this.allowUncaught) {
return callFnAsync(this.fn);
}
try {
callFnAsync(this.fn);
} catch (err) {
done(Mocha.utils.getError(err));
}
return;
}
if (this.allowUncaught) {
callFn(this.fn);
done();
return;
}
// sync or promise-returning
try {
if (this.pending) {
done();
} else {
callFn(this.fn);
}
} catch (err) {
done(Mocha.utils.getError(err));
}
function callFn(fn) {
var result = fn.call(ctx);
if (result && typeof result.then === 'function') {
self.resetTimeout();
result
.then(function () {
done();
// Return null so libraries like bluebird do not warn about
// subsequently constructed Promises.
return null;
},
function (reason) {
done(reason || new Error('Promise rejected with no or falsy reason'));
});
} else {
if (self.asyncOnly) {
return done(new Error('--async-only option in use without declaring `done()` or returning a promise'));
}
done();
}
}
function callFnAsync(fn) {
fn.call(ctx, function (err) {
if (err instanceof Error || Object.prototype.toString.call(err) === '[object Error]') {
if (mocha.options.allowUncaught) {
throw(err);
}
return done(err);
}
if (err) {
if (Object.prototype.toString.call(err) === '[object Object]') {
return done(new Error('done() invoked with non-Error: '
+ JSON.stringify(err)));
}
return done(new Error('done() invoked with non-Error: ' + err));
}
done();
});
}
}; Too bad we can't override |
Please see if 5e1cd44 addresses this issue. |
@boneskull I've just tried it and it does help, but there's a quirk. I have a test like this: it('works', function() {
const foo = {}
foo.bar()
}); It fails with "TypeError: foo.bar is not a function". When I enable But if I run the test directly (via the |
I am a bot that watches issues for inactivity. |
not stale |
This has since been fixed |
Runner.prototype.run
adds on awindow.onerror
handler when it callsThis causes tests that throw async errors to fail even if I add my own
window.onerror
handler. To fix this it should check the value ofthis.allowUncaught
first, e.g.I made this change and the tests I was writing passed. Would you be willing to accept a pull request for this change?
The text was updated successfully, but these errors were encountered: