Async hook rejection ordering with stacked before/after promises
0 reputation · 09 May 2023, 10:04 UTC
0 reputation · 09 May 2023, 10:04 UTC
In Jasmine 5.x, async before and after hooks return native Promises. When multiple such hooks are stacked within a single spec, the framework reports failure if any promise rejects, but the coordination mechanism between concurrent rejections is not explicitly documented. This creates ambiguity about whether rejections are aggregated, prioritized, or short-circuited.
The precise goal is to determine how Jasmine 5.x sequences rejection handling when several async before/after hooks are defined, and whether the test outcome reflects the first rejection, the last, or a combined signal. Version assumptions place this behavior within the 5.x line, where async hook semantics have not changed significantly since 4.x.
Questions: Does Jasmine 5.x process async hook rejections in declaration order, or does it adopt a first-rejection-wins model? When multiple rejections occur, are they aggregated into a single test failure, or does the framework report each independently? How does the timeout interval interact with pending hook rejections—does cancellation occur immediately upon the first rejection, or after all stacked hooks settle?
The premise of "concurrent rejections" doesn't apply: Jasmine 5.x runs async beforeEach/afterEach hooks sequentially, awaiting each hook's promise before starting the next one. There is no coordination mechanism between concurrent rejections because concurrent hook execution never happens within a spec. This sequential-await behavior has been stable across the 4.x and 5.x lines; the move to native promises changed the plumbing, not the ordering.
The model is effectively first-rejection-wins, but for a simpler reason than prioritization logic:
beforeEach rejects, Jasmine aborts the remaining beforeEach chain and skips the spec body.beforeEach hooks never run, so their rejections never occur. There is nothing to aggregate.afterEach hooks still run for cleanup, in reverse order of declaration (last-declared first), each awaited in turn.afterEach also rejects, that rejection is reported as an additional failure entry on the same spec — it doesn't replace the earlier one. This is the only place you'll see multiple failures from one spec.Each hook is independently subject to jasmine.DEFAULT_TIMEOUT_INTERVAL (5 seconds by default). Because hooks are awaited one at a time, there are never "pending stacked hooks" to cancel: a rejection that arrives before the interval fails the spec immediately, and a hook that neither settles nor rejects within the interval produces a timeout failure for that hook and aborts the spec. Cancellation is effectively immediate on the first terminal signal — but only because nothing else is in flight.
describe('hook ordering', () => {
beforeEach(async () => {
throw new Error('first hook');
});
beforeEach(async () => {
console.log('second hook ran'); // never prints
throw new Error('second hook');
});
afterEach(async () => {
console.log('cleanup ran'); // still prints
});
it('never executes', () => {});
});Expected: one failure citing first hook, no "second hook ran" log, "cleanup ran" present. Then make the afterEach reject and confirm a second failure entry appears. For timeout behavior, set jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 with a hook that never settles and confirm a timeout failure aborts the spec.
beforeAll/afterAll differ: a beforeAll rejection fails every spec in the suite, and afterAll runs regardless — don't conflate these with per-spec hooks. Also, if a hook spawns promises it doesn't await, those become unhandled rejections outside Jasmine's sequencing; that's the only path to something resembling concurrency. Exact reporter formatting for hook failures can vary between 5.x minor releases and between the browser and CLI runners, so confirm against your installed version (npm ls jasmine) if message wording matters to your CI parsing.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.