-
-
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
Duplicated failing test summary #2906
Comments
It's actually not a simple case of four copies of the second error, but rather, in addition to getting two copies of the second error rather than one of the first and one of the second, it's also running the whole end summary (which is where the stacktraces get printed, but also the pass/fail/pending-if-any counts) twice. There's probably multiple bugs in play here, which is impressive considering both of them are quite surprising. Thanks for spotting this and providing a perfect test case! We'll look into what's happening under the hood; but if anyone wants to jump on it and propose a fix, feel free! |
Quick followup observation:
|
I fall on this issue too with this code
As after rejecting the promise an uncaught error is throw by |
Hi @robininfo-edsx, When I run that code, I get a single print of a test failure and an unhandled promise rejection warning from Node. That seems like a different issue (assuming it is an issue; I'm not sure off the top of my head what the right behavior is if you give Mocha a promise that eventually becomes rejected but -- due to the effects of |
Ok, based on #2995 I think I've boiled @robininfo-edsx's example down to another, even more interesting case of this issue after all. Here's four different test files, each of which I've run individually: // no async, no describe
it('Bug', () => {
return new Promise(function(resolve, reject) {
reject(new Error('one'));
throw new Error('two');
});
});
// no async, describe
describe('suite', () => {
it('Bug', () => {
return new Promise(function(resolve, reject) {
reject(new Error('one'));
throw new Error('two');
});
});
});
// async, no describe
it('Bug', () => {
return new Promise(function(resolve, reject) {
process.nextTick(() => {
reject(new Error('one'));
throw new Error('two');
});
});
});
// async, describe
describe('suite', () => {
it('Bug', () => {
return new Promise(function(resolve, reject) {
process.nextTick(() => {
reject(new Error('one'));
throw new Error('two');
});
});
});
}); The two non-async examples work as expected. The async no-describe example gets a failed test printed correctly and an unhandled rejection warning. Adding describe to the async example turns it into another variation of the duplicated test run end/summary printing issue. Strange that being in a suite makes a difference -- that's a very specific combination of behaviors. Something we should start looking at is whether this problem is triggered by:
We've only covered the first of those possibilities so far. |
So effectively my last comment was not the same issue however it may play on this issue as mocka can have multiple result for a test. |
Just a heads-up -- since there are other issues about exceptions being clobbered when reporting multiple failures arising out of the same test (e.g. #2971) and I've been directing other reports of duplicated test summaries here, I've attempted to make the title more about what happens rather than how (although in the process it's not bringing up the angle of "second" being reported twice rather than "first" then "second", which I believe is distinct from the duplicated summary). |
This bug in combination with an afterEach have even more negative impact. The afterEach() is the one receiving this 2nd exception. Here the code to reproduce it, describe('Batch #1', function() {
afterEach (function () {});
it('should be OK :: A.1', function(done) {
process.nextTick(() => {
console.log('==> Code Inside A.1 / 1st Failule');
console.log('==> Test Title:', this.test.title);
throw Error('==> First failure <');
});
process.nextTick(() => {
console.log('--> Code Inside A.1 / 2nd Failure');
console.log('--> Test Title:', this.test.title);
done( Error('--> Second failure <'));
});
});
it('should be OK :: A.2', function() {});
});
describe('Batch #2', function() {
it('should be OK :: B.1', function() {});
}); And here part of the output where run with DEBUG=*
Here our observation:
Note, this is the most problematic configuration, a describe() with a afterEach() and two it() inside, where the first it() throw 2 exceptions. With more or less it() Mocha do not exit abruptly. The cause of the failure seams to be the afterEach() hook catching the exception thrown from the it(). My config: > mocha -V
4.0.1
> node -v
v8.9.1 |
See also #967
Unless I've missed something, I don't think it's crashing exactly: there's an expected behavior that failures in |
Per #3105's example, another way this can happen is with an |
I suspect all these cases come down to double-completions of some test or hook causing Mocha to redundantly run some of its logic that includes the final end summary. There's some code to suppress some reporting of double-completions, but it's obviously not a general solution. The general solution would be to refactor the flow of Mocha's suite/hooks/test running actions, such that after a hook or test is completed any subsequent completion of that hook or test:
For instance, this is easy to do with promise flows since promises only resolve once; if Mocha reaches (or has reached? I'll have to review for version 4) a point where only environments that have native promises are supported, or if it's possible for Mocha to use a promise library internally without polluting the environment of the tests or the code being tested, then one way to resolve the issue completely and permanently would be simply to rewrite the logic in terms of promises (on the inside anyway, converting to the existing callback-based interactions at the API boundaries). |
If I understand correctly, this might mask the true outcome of a test that succeeds and then fails, no? We might want to report all failures, and ignore subsequent "successes" (or report them as failures) and simply have additional info for the console. |
Those would need to be reported, but should not re-run any of Mocha's test run logic (that says "ok, that test is done, do the hooks, now do the next one; ok, that suite is done, do its after hooks, are we at the end? do the end..."). It should be entirely possible to get the logic un-repeatable with promises while leaving the immediate handlers for various test/hook results in a state where they'll emit a failure to the reporter -- not that it would be easy, but the hard part isn't leaving those handlers still correctly reporting redundant test/hook completions; the hard part is changing Mocha's overcomplex internals and using promises under the hood of a callback-based API. |
fixed by #4150
|
I am not sure if I am right here: I come Ticket #3105 to here when receiving the very same message while doing it("should only be possible for admins to pause an account", async function() {
let instance = await Accounts.deployed();
await truffleAssert.fails(
instance.pause({from: accounts[1]}),
truffleAssert.ErrorType.REVERT,
);
}) when switching the arguments by mistake to ...
await truffleAssert.fails(
truffleAssert.ErrorType.REVERT,
instance.pause({from: accounts[1]})
);
... you'll be presented with what is written in #3105. |
Running Mocha
3.4.2
on Node8.1.3
(also reproducible on Node7.6.0
).Output:
Not only does
mocha
output four (!) copies of the second error, it fails to output any copies of the first error. This makes it difficult to debug tests if the second error is merely a symptom of the first.The text was updated successfully, but these errors were encountered: