Browse Source

Try to fail test if assertions are added after test finishes

Though currently this error is likely to get lost unless there is a
pending assertion or `test.cb()` is used.
master
Mark Wubben 8 years ago
parent
commit
09b23e0d5f
  1. 29
      lib/test.js
  2. 27
      test/test.js

29
lib/test.js

@ -101,6 +101,7 @@ class Test {
this.calledEnd = false;
this.duration = null;
this.endCallbackFinisher = null;
this.finishing = false;
this.pendingAssertions = [];
this.planCount = null;
this.startedAt = 0;
@ -142,15 +143,27 @@ class Test {
}
countPassedAssertion() {
if (this.finishing) {
this.saveFirstError(new Error('Assertion passed, but test has already ended'));
}
this.assertCount++;
}
addPendingAssertion(promise) {
if (this.finishing) {
this.saveFirstError(new Error('Assertion passed, but test has already ended'));
}
this.assertCount++;
this.pendingAssertions.push(promise);
}
addFailedAssertion(error) {
if (this.finishing) {
this.saveFirstError(new Error('Assertion failed, but test has already ended'));
}
this.assertCount++;
this.saveFirstError(error);
}
@ -265,12 +278,13 @@ class Test {
}
finish() {
this.finishing = true;
this.verifyPlan();
if (this.pendingAssertions.length === 0) {
return this.finishImmediately();
return this.completeFinish();
}
this.verifyPlan();
// Consume errors, ensuring there are no unhandled rejections.
const consumedErrors = Promise.all(this.pendingAssertions)
.catch(err => this.saveFirstError(err));
@ -281,9 +295,7 @@ class Test {
}
// Finish after potential errors from pending assertions have been consumed.
// Note that the plan must be verified again in case a new assertion was
// added.
return consumedErrors.then(() => this.finishImmediately());
return consumedErrors.then(() => this.completeFinish());
}
finishPromised() {
@ -292,11 +304,6 @@ class Test {
});
}
finishImmediately() {
this.verifyPlan();
return this.completeFinish();
}
completeFinish() {
this.duration = globals.now() - this.startedAt;
globals.clearTimeout(this.timeoutHandle);

27
test/test.js

@ -508,21 +508,40 @@ test('multiple resolving and rejecting promises passed to t.throws/t.notThrows',
});
});
test('number of assertions matches t.plan when the test exits, but before all promises resolve another is added', t => {
test('number of assertions matches t.plan when the test exits, but before all pending assertions resolve another is added', t => {
let result;
ava(a => {
a.plan(2);
a.throws(delay.reject(10, new Error('foo')), 'foo');
a.notThrows(delay(10), 'foo');
setTimeout(() => {
a.throws(Promise.reject(new Error('foo')), 'foo');
a.pass();
}, 5);
}, null, r => {
result = r;
}).run().then(passed => {
t.is(passed, false);
t.match(result.reason.message, /Assertion passed, but test has already ended/);
t.is(result.reason.name, 'Error');
t.end();
});
});
test('number of assertions matches t.plan when the test exits, but before all pending assertions resolve, a failing assertion is added', t => {
let result;
ava(a => {
a.plan(2);
a.throws(delay.reject(10, new Error('foo')), 'foo');
a.notThrows(delay(10), 'foo');
setTimeout(() => {
a.fail();
}, 5);
}, null, r => {
result = r;
}).run().then(passed => {
t.is(passed, false);
t.is(result.reason.assertion, 'plan');
t.is(result.reason.operator, '===');
t.match(result.reason.message, /Assertion failed, but test has already ended/);
t.is(result.reason.name, 'Error');
t.end();
});
});

Loading…
Cancel
Save