#54950: test: keep running deferred cleanup and afterEach hooks when one throws or hangs
Description of Change
This fixes two ways that one bad defer()-ed cleanup could break more than its own test.
A throwing cleanup skipped every later afterEach hook. vitest runs a test's afterEach hooks in order and stops at the first one that throws. It skips the rest, including every enclosing suite's afterEach hooks. The spec runner registers defer()-ed cleanup as the first afterEach hook of every suite, so one failing cleanup also skipped hooks such as protocol.unhandle() and closeWindow().
In the no-cors protocol specs on CI, a cleanup that failed with ENOTEMPTY caused two problems:
- The
no-corshandler stayed registered, so the next try failed inbeforeEachwithFailed to register protocol: no-cors. - A window was left open, which a later
closeWindow()reported as a leak.
spec/vitest/runner.ts now catches what each afterEach hook throws, defer()-ed cleanup included, and lets the remaining hooks run. It rethrows the errors from an onTestFinished callback once all the hooks have finished. The test still fails, and vitest reports each error separately with its original stack. Hooks and cleanups run in the same order as before.
A cleanup that never settled would hang the whole spec file. defer()-ed cleanup has had no timeout since the move to vitest (#54264). The mocha shim registered it with vitest's hook timeout set to 0, which vitest treats as no timeout, and the runner from #54439 adds it to the hook list directly, without vitest's afterEach(). So a cleanup such as a closeWindow() whose window never emits closed would hang the worker until the CI job timed out. Each defer()-ed cleanup now gets the hook timeout, as an afterEach hook would. The timeout error points at the defer() call. A timed-out cleanup is handled like a throwing one, so the remaining cleanups and hooks still run; as with a timed-out vitest hook, it keeps running in the background.
The new spec/vitest-runner.spec.ts covers both cases in nested suites: cleanups and hooks that throw, and a cleanup that outlasts a short hook timeout set through vi.setConfig(). It checks that every later cleanup and hook still ran and that the test failed with the expected errors. It is a new spec file, so it adds one short Electron launch to the CI shard that runs it.
🤖 Generated with Claude Code
Checklist
- I have built and tested this change
- I have filled out the PR description
- I have reviewed and verified the changes
- tests are changed or added
Release Notes
Notes: none
Backports
Semver Impact
Semantic Versioning helps users understand the impact of updates:
- Major (X.y.z): Breaking changes that may require code modifications
- Minor (x.Y.z): New features that maintain backward compatibility
- Patch (x.y.Z): Bug fixes that don't change the API
- None: Changes that don't affect using facing parts of Electron