Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/runnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Runnable.prototype.reset = function () {
this.pending = false;
delete this.state;
delete this.err;
delete this._startTime;
};

/**
Expand Down Expand Up @@ -243,7 +244,11 @@ Runnable.prototype.resetTimeout = function () {
if (self.timeout() === 0) {
return;
}
self.callback(self._timeoutError(ms));
var duration;
if (self._startTime) {
duration = new Date() - self._startTime;
}
self.callback(self._timeoutError(ms, duration));
self.timedOut = true;
}, ms);
};
Expand All @@ -270,6 +275,7 @@ Runnable.prototype.globals = function (globals) {
Runnable.prototype.run = function (fn) {
var self = this;
var start = new Date();
this._startTime = start;
var ctx = this.ctx;
var finished;
var errorWasHandled = false;
Expand Down Expand Up @@ -305,7 +311,7 @@ Runnable.prototype.run = function (fn) {
self.duration = new Date() - start;
finished = true;
if (!err && self.duration > ms && ms > 0) {
err = self._timeoutError(ms);
err = self._timeoutError(ms, self.duration);
}
fn(err);
}
Expand Down Expand Up @@ -420,11 +426,15 @@ Runnable.prototype.run = function (fn) {
* Instantiates a "timeout" error
*
* @param {number} ms - Timeout (in milliseconds)
* @param {number} [duration] - Actual duration (in milliseconds), if available
* @returns {Error} a "timeout" error
* @private
*/
Runnable.prototype._timeoutError = function (ms) {
Runnable.prototype._timeoutError = function (ms, duration) {
let msg = `Timeout of ${ms}ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.`;
if (typeof duration === "number" && duration > 0) {
msg += ` Test ran for ${duration}ms.`;
}
if (this.file) {
msg += " (" + this.file + ")";
}
Expand Down
40 changes: 40 additions & 0 deletions test/unit/runnable.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,46 @@ describe("Runnable(title, fn)", function () {
});
});
});

it("should include duration in timeout error message when timeout fires", function (done) {
var runnable = new Runnable("foo", function (done) {
setTimeout(done, 50);
});
runnable.timeout(20);
runnable.run(function (err) {
expect(err, "to satisfy", { code: TIMEOUT, timeout: 20 });
expect(err.message, "to match", /Test ran for \d+ms/);
done();
});
});

it("should include duration in timeout error message when test finishes late", function (done) {
var runnable = new Runnable("foo", function (done) {
setTimeout(function () {
done();
}, 30);
});
runnable.timeout(10);
runnable.run(function (err) {
expect(err, "to satisfy", { code: TIMEOUT, timeout: 10 });
expect(err.message, "to match", /Test ran for \d+ms/);
done();
});
});

it("should include duration in timeout error message for promise-based tests", function (done) {
var runnable = new Runnable("foo", function () {
return new Promise(function (resolve) {
setTimeout(resolve, 30);
});
});
runnable.timeout(10);
runnable.run(function (err) {
expect(err, "to satisfy", { code: TIMEOUT, timeout: 10 });
expect(err.message, "to match", /Test ran for \d+ms/);
done();
});
});
});

describe("if async", function () {
Expand Down