-
Notifications
You must be signed in to change notification settings - Fork 782
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Assert: Improve detection of bad calls to
assert.async()
callbacks
== Background == When creating two async pauses in a test, it was possible for a test to pass by invoking one of them twice, and the other not at all. Easy scenario (though perhaps not realistic): > Use `assert.async()` twice, assigned as done1 and done2 in the same > `QUnit.test()` case, and then simulate the failure scenario such that > you wrongly call done1 two times, and forget to call done2. Complex scenario across `QUnit.test()` and "afterEach" hooks, since these previously shared a single semaphore: > Use `assert.async()` once in a simple test, and schedule the resume > call in the future, but then fail with an uncaught error. The uncaught > error is found and `Test.run()` would internally kill the pause by > resetting the semaphore to zero (this make sense since we shouldn't > wait for the release once the test is known to have failed). > After this reset, we proceed to the "afterEach" hook. Suppose this > hook is also async, and during its execution, the originally scheduled > resume call happens. This would effectively end up releasing the > afterEach's async pause despite not being finished yet, and then we > proceed to the next test. That test would then fail when the afterEach's > own release call happens, failing as "release during a different test". This is the scenario of #1432. Fix this and numerous other edge cases by making the returned callbacks from `assert.async()` strict about which locks they release. Each lock now adds a unique token to a map, and invoking the release function decrements/removes this token from the map. == Notes == * es6-map.js assigns the fallback in all browsers. This is a bug, to be fixed later. * The `isNaN(semaphore)` logic was originally added in 2015 by ea3e350. At the time, the internal resume function was public, and NaN could emerge through `QUnit.start("bla")` as result of `semaphore += "bla"`. This has not been possible for a while. During PR #1590, I did not trace the origin of this code, and thus did not realize that it was already obsolete (the semaphore itself is not publicly supported). * The "during different test" error is now almost impossible to trigger since we now kill pending locks during test failures and tolerate all late calls equally. This meant the `drooling-done.js` test case now fails in a more limited way. I added a new test case for coverage, that reproduces it still, but it's a lot more obscure – it requires the original test to pass and then also have an unexpected call during a different test. Fixes #1432.
- Loading branch information
Showing
13 changed files
with
232 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,35 @@ | ||
// Support IE 9-10, PhantomJS: Fallback for fuzzysort.js used by ./html.js | ||
// Support IE 9-10, Safari 7, PhantomJS: Partial Map fallback. | ||
// Used by html.js (via fuzzysort.js), and test.js. | ||
// | ||
// FIXME: This check is broken. This file is embedded in the qunit.js closure, | ||
// thus the Map var is hoisted in that scope, and starts undefined (not a function). | ||
var Map = typeof Map === "function" ? Map : function StringMap() { | ||
var store = Object.create( null ); | ||
var hasOwn = Object.prototype.hasOwnProperty; | ||
this.get = function( strKey ) { | ||
return store[ strKey ]; | ||
}; | ||
this.set = function( strKey, val ) { | ||
if ( !hasOwn.call( store, strKey ) ) { | ||
this.size++; | ||
} | ||
store[ strKey ] = val; | ||
return this; | ||
}; | ||
this.delete = function( strKey ) { | ||
if ( hasOwn.call( store, strKey ) ) { | ||
delete store[ strKey ]; | ||
this.size--; | ||
} | ||
}; | ||
this.forEach = function( callback ) { | ||
for ( var strKey in store ) { | ||
callback( store[ strKey ], strKey ); | ||
} | ||
}; | ||
this.clear = function() { | ||
store = Object.create( null ); | ||
this.size = 0; | ||
}; | ||
this.size = 0; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
QUnit.config.reorder = false; | ||
|
||
let done; | ||
|
||
QUnit.test( "Test A", assert => { | ||
assert.ok( true ); | ||
done = assert.async(); | ||
|
||
// Passing. | ||
done(); | ||
} ); | ||
|
||
QUnit.test( "Test B", assert => { | ||
assert.ok( true ); | ||
|
||
// Boom | ||
done(); | ||
} ); |
Oops, something went wrong.