Open Krinkle opened 2 months ago
Inspired by https://github.com/qunitjs/qunit/issues/1328 (@raycohen), where afaik we did not change this order so this page could be version agnostic I think? (e.g. applicable to both QUnit 2 and 3).
- For each test:
hooks.before()
- global
QUnit.hooks.beforeEach()
hooks.beforeEach()
QUnit.test()
function
This is what I'm seeing, but it's not what the current docs imply should happen:
Hooks that run before a test, are ordered from outer-most to inner-most, in the order that they are added. This means that a test will first run any global beforeEach hooks, then the hooks of parent modules, and finally the hooks added to the current module that the test is part of.
This says to me that a top-level beforeEach
hook (the hooks of parent modules) will run before a nested before
hook (finally the hooks added to the current module), but that just isn't the case. Take this example:
import { module, test } from 'qunit';
module('Top-level module', function(hooks) {
hooks.before(function() {
console.log('>> top-level before');
});
hooks.beforeEach(function() {
console.log('>> top-level beforeEach');
});
module('Nested module', function(hooks) {
hooks.before(function() {
console.log('>> nested before');
});
hooks.beforeEach(function() {
console.log('>> nested beforeEach');
});
test('log', function() {});
});
});
If the docs are correct, and the hooks of parent modules are run before the hooks added to the current module that the test is part of, I would expect to see this:
>> top-level before
>> top-level beforeEach
>> nested before
>> nested beforeEach
However, what I actually see is:
>> top-level before
>> nested before
>> top-level beforeEach
>> nested beforeEach
Frustratingly, I actually want the expected behaviour in one of my suites, but regardless, it would be good to have clarity on the order - so thanks for documenting it 🙂 .
@BillyRayPreachersSon That text is referring to order within a single hook. "before", "beforeEach", "afterEach", and "after", are four different hooks.
This is important as it allows children to build on the work of parents, yet also allow each test to cleanly inherent the module state. For compatibility, and based on many years of use cases being expressed in satisfactory ways, we'd not likely change this. But, those docs can definitely be clearer.
If you provide a more detailed example of what you're trying to do, I'd be happy to review that for you and see if we can make it more intuitive. I'm sure you don't need help to make it work, but I wouldn't want you to feel the end result is counter-intuitive. Hence I'd like to see an example, and look for what may've led to that as an expectation, and to perhaps improve something aside or in addition (without breaking change) to better accommodate that!
We have:
While each is well-documented, and describes when it runs, and how (sync or async), we don't have yet provided an explicit overview of the overall order of events. Where this matters most is:
QUnit.begin()
andQUnit.on('runStart')
which logically run at the same time. Idem forQUnit.done()
andQUnit.on('runEnd')
. Consider a sentence like "QUnit.config.urlConfig
modifications must be made before QUnit.begin". Does that meanrunStart
is fine, or is that too late? And is that supported or accidental?hooks.afterEach
andQUnit.testDone()
, where the order is not obvious per se, ref https://github.com/qunitjs/qunit/issues/1475.Life cycle
I wrote up the following to get us started.
QUnit.on('runStart')
[reporter, sync]QUnit.begin()
[plugin, async-await]QUnit.on('suiteStart')
[reporter, sync]QUnit.moduleStart()
[plugin, async-await]QUnit.on('testStart')
[reporter, sync]QUnit.testStart()
[plugin, async-await]hooks.before()
[testing, async-await]QUnit.hooks.beforeEach()
[plugin, async-await]hooks.beforeEach()
[testing, async-await]QUnit.test()
function [testing, async-await]QUnit.log()
[plugin, sync]hooks.afterEach()
[testing, async-await]QUnit.hooks.afterEach()
[plugin, async-await]hooks.after()
[testing, async-await]QUnit.on('testEnd')
[reporter, sync]QUnit.testDone()
[plugin, async-await]QUnit.on('suiteEnd')
[reporter, sync]QUnit.moduleDone()
[plugin, async-await]QUnit.on('runEnd')
[reporter, sync]QUnit.done()
[plugin, async-await]Would a table be clearer?
QUnit.on('runStart')
QUnit.begin()
QUnit.on('suiteStart')
QUnit.moduleStart()
QUnit.on('testStart')
QUnit.testStart()
hooks.before()
QUnit.hooks.beforeEach()
hooks.beforeEach()
QUnit.test()
functionQUnit.log()
hooks.afterEach()
QUnit.hooks.afterEach()
hooks.after()
QUnit.on('testEnd')
QUnit.testDone()
QUnit.on('suiteEnd')
QUnit.moduleDone()
QUnit.on('runEnd')
QUnit.done()