fix(junit): preserve suite identity for hook failures reported from workers#5664
Open
kapil971390 wants to merge 1 commit into
Open
fix(junit): preserve suite identity for hook failures reported from workers#5664kapil971390 wants to merge 1 commit into
kapil971390 wants to merge 1 commit into
Conversation
…orkers
Under run-workers, event.hook.failed for a BeforeSuite/AfterSuite failure
arrives in the main process via Hook.simplify(), which only carries
{hookName, title, error} — no ctx, so the reporter has no way to recover
the owning suite. groupBySuite() then falls back to key = the failure
entry itself, and buildXml's suiteName defaults to "Tests", splitting
each hook failure into its own <testsuite name="Tests"> instead of the
suite that actually failed.
- Hook.simplify() now also serializes suiteTitle/suiteFile/suiteTags
from this.runnable.parent (the real Suite, already used successfully
on the main-thread path — see the "adds suite hook failures as failed
testcases" unit test).
- junitReporter's event.hook.failed listener falls back to these fields
when hook.ctx is absent, reusing one synthetic suite object per
title+file pair so multiple failures from the same worker-reported
suite still group into a single <testsuite>.
Reproduced with the exact scenario from codeceptjs#5645 (BeforeSuite + AfterSuite
both throwing) run via `codecept run-workers 2`: before this change
both failures land under two separate <testsuite name="Tests"> entries;
after, both are under one <testsuite name="My">, matching the
main-thread output shape.
Contributor
Author
kapil971390
marked this pull request as ready for review
July 18, 2026 20:05
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


What's the bug
Under
run-workers, when aBeforeSuite/AfterSuitehook fails, the JUnit report puts the failure under a generic<testsuite name="Tests">instead of the suite that actually failed, and each failure gets split into its own<testsuite>element instead of being grouped with other failures from the same suite.This is a follow-up to #5657, which fixed the main bug from #5645 (hook failures not appearing in the report at all). That PR's description explicitly notes this as a known limitation:
This PR does that.
Root cause
lib/plugin/junitReporter.js'sevent.hook.failedlistener reads the suite fromhook.ctx.test.parent:On the main thread
hook.ctxis a live Mocha context and this works (verified separately with a real Mocha run —ctx.testfor a suite-level hook is the hook's own runnable, andrunnable.parentis the real Suite). But underrun-workers, the failure is forwarded from the worker process viaHook.simplify()(lib/mocha/hooks.js):No
ctx, sorunnableandsuiteare bothundefinedfor every worker-forwarded hook failure.buildXml'sgroupBySuitethen keys each failure by itself (test.parent || test), and the suite name falls back to the literal'Tests':Fix
Hook.simplify()now also serializes the suite identity fromthis.runnable.parent(the same object the main-thread path already reads successfully):junitReporter.js's listener falls back to these fields whenhook.ctxis absent, reusing one synthetic suite object pertitle+filepair so multiple failures from the same worker-reported suite still group into a single<testsuite>instead of one per failure:Reproduction steps
tests/My_test.js:codecept.conf.jswithjunitReporter: { enabled: true }node bin/codecept.js run-workers 2 --config codecept.conf.jsoutput/report.xmlBefore this change:
After:
(single element, both failures grouped inside)
Edge cases verified
All run against the actual
run-workerscommand, not simulated.<testsuite name="Tests">, one testcase each<testsuite name="My">, both testcases inside<testsuite>; no cross-suite mixingBeforehook failure (not BeforeSuite/AfterSuite), run-workersScenariofailure (no hook failure at all), run-workersresult.tests, nothookFailures)run-workers) BeforeSuite/AfterSuite failurehook.ctxpath)Existing test suite:
mocha test/unit/junitReporter_test.js— 10/10 passing, including the two hook-failure tests already in that file.Full suite:
mocha test/unit— 761 passing, 11 pending, 0 failing.mocha test/runner— 275 passing, 2 pending, 0 failing.Out of scope
lib/listener/result.jsalso listens onevent.hook.failedbut only for stats counting (failedHooks), unaffected by this change. The other known limitation mentioned in #5657 (_beforeSuite/_afterSuitehelper-level failures viasuiteSetup/suiteTeardownnot emittingevent.hook.failedat all) is a separate, pre-existing gap not touched here.