Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.

Commit d1de4b9

Browse files
committed
fix memory leak when run in v8; closes mochajs#3119
- this means "multiple calls to done" will once again fail to produce a stack trace in the case that those multiple calls happen in separate tasks. - however, if the `done()` is called with an error, Mocha will emit that error, but also a note about multiple calls - some reformatting, evidently - removed some pointless checks of Mocha's exit code from "multiple done" integration tests Signed-off-by: Christopher Hiller <[email protected]>
1 parent 908e2f0 commit d1de4b9

File tree

4 files changed

+48
-16
lines changed

4 files changed

+48
-16
lines changed

lib/runnable.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ function Runnable (title, fn) {
5353
this._slow = 75;
5454
this._enableTimeouts = true;
5555
this.timedOut = false;
56-
this._trace = new Error('done() called multiple times');
5756
this._retries = -1;
5857
this._currentRetry = 0;
5958
this.pending = false;
@@ -278,7 +277,13 @@ Runnable.prototype.run = function (fn) {
278277
return;
279278
}
280279
emitted = true;
281-
self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
280+
var msg = 'done() called multiple times';
281+
if (err && err.message) {
282+
err.message += " (and Mocha's " + msg + ')';
283+
self.emit('error', err);
284+
} else {
285+
self.emit('error', new Error(msg));
286+
}
282287
}
283288

284289
// finished
@@ -287,8 +292,9 @@ Runnable.prototype.run = function (fn) {
287292
if (self.timedOut) {
288293
return;
289294
}
295+
290296
if (finished) {
291-
return multiple(err || self._trace);
297+
return multiple(err);
292298
}
293299

294300
self.clearTimeout();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
3+
it('should fail in a test-case', function (done) {
4+
process.nextTick(function () {
5+
done();
6+
done(new Error('second error'));
7+
});
8+
});

test/integration/multiple-done.spec.js

+29-12
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,35 @@ describe('multiple calls to done()', function () {
1515
});
1616

1717
it('results in failures', function () {
18-
assert.equal(res.stats.pending, 0);
19-
assert.equal(res.stats.passes, 1);
20-
assert.equal(res.stats.failures, 1);
21-
assert.equal(res.code, 1);
18+
assert.equal(res.stats.pending, 0, 'wrong "pending" count');
19+
assert.equal(res.stats.passes, 1, 'wrong "passes" count');
20+
assert.equal(res.stats.failures, 1, 'wrong "failures" count');
2221
});
2322

2423
it('throws a descriptive error', function () {
25-
assert.equal(res.failures[0].err.message,
26-
'done() called multiple times');
24+
assert.equal(res.failures[0].err.message, 'done() called multiple times');
25+
});
26+
});
27+
28+
describe('with error passed on second call', function () {
29+
before(function (done) {
30+
run('multiple-done-with-error.fixture.js', args, function (err, result) {
31+
res = result;
32+
done(err);
33+
});
34+
});
35+
36+
it('results in failures', function () {
37+
assert.equal(res.stats.pending, 0, 'wrong "pending" count');
38+
assert.equal(res.stats.passes, 1, 'wrong "passes" count');
39+
assert.equal(res.stats.failures, 1, 'wrong "failures" count');
40+
});
41+
42+
it('should throw a descriptive error', function () {
43+
assert.equal(
44+
res.failures[0].err.message,
45+
"second error (and Mocha's done() called multiple times)"
46+
);
2747
});
2848
});
2949

@@ -44,8 +64,7 @@ describe('multiple calls to done()', function () {
4464

4565
it('correctly attributes the error', function () {
4666
assert.equal(res.failures[0].fullTitle, 'suite test1');
47-
assert.equal(res.failures[0].err.message,
48-
'done() called multiple times');
67+
assert.equal(res.failures[0].err.message, 'done() called multiple times');
4968
});
5069
});
5170

@@ -66,8 +85,7 @@ describe('multiple calls to done()', function () {
6685

6786
it('correctly attributes the error', function () {
6887
assert.equal(res.failures[0].fullTitle, 'suite "before all" hook');
69-
assert.equal(res.failures[0].err.message,
70-
'done() called multiple times');
88+
assert.equal(res.failures[0].err.message, 'done() called multiple times');
7189
});
7290
});
7391

@@ -90,8 +108,7 @@ describe('multiple calls to done()', function () {
90108
assert.equal(res.failures.length, 2);
91109
res.failures.forEach(function (failure) {
92110
assert.equal(failure.fullTitle, 'suite "before each" hook');
93-
assert.equal(failure.err.message,
94-
'done() called multiple times');
111+
assert.equal(failure.err.message, 'done() called multiple times');
95112
});
96113
});
97114
});

test/unit/runnable.spec.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ describe('Runnable(title, fn)', function () {
270270

271271
test.on('error', function (err) {
272272
++errCalls;
273-
expect(err.message).to.equal('fail');
273+
expect(err.message).to.equal(
274+
"fail (and Mocha's done() called multiple times)");
274275
expect(calls).to.equal(1);
275276
expect(errCalls).to.equal(1);
276277
done();

0 commit comments

Comments
 (0)