From 5205311b51b26f0233c807b898b88090e6bd89e3 Mon Sep 17 00:00:00 2001 From: Luan Taraschi <130802253+luantaraschi@users.noreply.github.com> Date: Fri, 7 Aug 2026 09:00:30 -0300 Subject: [PATCH] fix(junitReporter): stamp suites with their real start time junitReporter writes each `` from `suite.startedAt`, but nothing ever set that field. Mocha's Suite does not carry it, and `startedAt` was only assigned to individual tests, in lib/listener/steps.js. So `toIso()` always fell through to its `new Date()` fallback and every suite was stamped with the moment the XML was serialized, which is after the suite (and its AfterSuite) finished. The steps listener now stamps the suite on `event.suite.before`, mirroring what it already does for tests. Note this covers the in-process run. Under `run-workers` the parent only receives `{ title }` for a test's parent suite, so the timestamp cannot survive that boundary without changing the worker payload. Closes #5668 --- lib/listener/steps.js | 8 ++++ .../listener/steps_suite_started_at_test.js | 45 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 test/unit/listener/steps_suite_started_at_test.js diff --git a/lib/listener/steps.js b/lib/listener/steps.js index 174c5ef30..5935952d1 100644 --- a/lib/listener/steps.js +++ b/lib/listener/steps.js @@ -16,6 +16,14 @@ const EXCLUDED_SESSIONS = ['tryTo', 'hopeThat'] * Register steps inside tests */ export default function () { + // Mocha's Suite has no start timestamp of its own, and junitReporter reads + // `suite.startedAt` for each ``. Without this the + // reporter falls back to `new Date()` at write time, stamping every suite + // with the moment the XML was serialized. (#5668) + event.dispatcher.on(event.suite.before, suite => { + suite.startedAt = +new Date() + }) + event.dispatcher.on(event.test.before, test => { test.startedAt = +new Date() }) diff --git a/test/unit/listener/steps_suite_started_at_test.js b/test/unit/listener/steps_suite_started_at_test.js new file mode 100644 index 000000000..a8f28ad22 --- /dev/null +++ b/test/unit/listener/steps_suite_started_at_test.js @@ -0,0 +1,45 @@ +import { expect } from 'chai' +import event from '../../../lib/event.js' +import recorder from '../../../lib/recorder.js' + +import stepsListener from '../../../lib/listener/steps.js' + +// junitReporter reads `suite.startedAt` for each ``. +// Mocha never sets it, so before this listener existed the reporter fell back +// to `new Date()` at write time. (#5668) +describe('Steps Listener - suite.startedAt', () => { + beforeEach(() => { + recorder.reset() + recorder.start() + event.cleanDispatcher() + stepsListener() + }) + + afterEach(() => { + event.cleanDispatcher() + recorder.reset() + }) + + it('stamps the suite when it starts', () => { + const suite = { title: 'Login' } + const before = Date.now() + + event.emit(event.suite.before, suite) + + expect(suite.startedAt).to.be.a('number') + expect(suite.startedAt).to.be.at.least(before) + expect(suite.startedAt).to.be.at.most(Date.now()) + }) + + it('stamps each suite independently', () => { + const first = { title: 'Login' } + const second = { title: 'Dashboard' } + + event.emit(event.suite.before, first) + event.emit(event.suite.before, second) + + expect(first.startedAt).to.be.a('number') + expect(second.startedAt).to.be.a('number') + expect(second.startedAt).to.be.at.least(first.startedAt) + }) +})