From 70f1068189f4bec35e0a35d173802b73e91249d3 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 13 Mar 2026 12:14:17 +0100 Subject: [PATCH 1/6] fix(mocha): report correct status for retried tests in parallel mode (#6078) The worker was missing the `retry` event handler, causing retried test attempts to be reported with wrong status (pass instead of fail) or silently dropped depending on afterEach hook presence. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../mocha-plugin-tests/retries-parallel-2.js | 12 ++++ .../mocha-plugin-tests/retries-parallel.js | 12 ++++ integration-tests/mocha/mocha.spec.js | 59 +++++++++++++++++++ .../src/mocha/worker.js | 3 + 4 files changed, 86 insertions(+) create mode 100644 integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel-2.js create mode 100644 integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel.js diff --git a/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel-2.js b/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel-2.js new file mode 100644 index 00000000000..9b4776b2d53 --- /dev/null +++ b/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel-2.js @@ -0,0 +1,12 @@ +'use strict' + +const assert = require('assert') +let attempt = 0 + +describe('mocha-test-retries-parallel-2', function () { + this.retries(2) + + it('will fail twice then pass', () => { + assert.strictEqual(attempt++, 2) + }) +}) diff --git a/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel.js b/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel.js new file mode 100644 index 00000000000..bd9ecad8262 --- /dev/null +++ b/integration-tests/ci-visibility/mocha-plugin-tests/retries-parallel.js @@ -0,0 +1,12 @@ +'use strict' + +const assert = require('assert') +let attempt = 0 + +describe('mocha-test-retries-parallel', function () { + this.retries(2) + + it('will fail twice then pass', () => { + assert.strictEqual(attempt++, 2) + }) +}) diff --git a/integration-tests/mocha/mocha.spec.js b/integration-tests/mocha/mocha.spec.js index de426b73353..9c36a410174 100644 --- a/integration-tests/mocha/mocha.spec.js +++ b/integration-tests/mocha/mocha.spec.js @@ -1353,6 +1353,65 @@ describe(`mocha@${MOCHA_VERSION}`, function () { }) }) + onlyLatestIt('correctly reports retries in parallel mode', async () => { + const eventsPromise = receiver + .gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => { + const events = payloads.flatMap(({ payload }) => payload.events) + const tests = events.filter(event => event.type === 'test').map(event => event.content) + + // Verify we are actually in parallel mode + const sessionEvent = events.find(event => event.type === 'test_session_end').content + assert.strictEqual(sessionEvent.meta[MOCHA_IS_PARALLEL], 'true') + + // Each file has 1 test that fails twice then passes on the 3rd attempt (3 events per file) + assert.strictEqual(tests.length, 6) + + // 2 failed attempts per file = 4 total + const failedTests = tests.filter(test => test.meta[TEST_STATUS] === 'fail') + assert.strictEqual(failedTests.length, 4) + + // The 3rd attempt passes in each file = 2 total + const passingTests = tests.filter(test => test.meta[TEST_STATUS] === 'pass') + assert.strictEqual(passingTests.length, 2) + + // First attempt of each test is not a retry, subsequent ones are (2 retries * 2 files = 4) + const retries = tests.filter(test => test.meta[TEST_IS_RETRY] === 'true') + assert.strictEqual(retries.length, 4) + + // Verify the two files ran in separate worker processes + const testsBySuite = {} + for (const test of tests) { + const suiteName = test.meta[TEST_SUITE] + if (!testsBySuite[suiteName]) { + testsBySuite[suiteName] = test + } + } + const testFromEachWorker = Object.values(testsBySuite) + assert.strictEqual(testFromEachWorker.length, 2) + const runtimeIds = testFromEachWorker.map(test => test.meta['runtime-id']) + assert.ok(runtimeIds[0]) + assert.ok(runtimeIds[1]) + assert.notStrictEqual(runtimeIds[0], runtimeIds[1], + 'Tests from different files should have different runtime-ids (separate worker processes)' + ) + }) + + childProcess = exec( + 'node node_modules/mocha/bin/mocha' + + ' --parallel --jobs 2 --retries 2' + + ' ./ci-visibility/mocha-plugin-tests/retries-parallel.js' + + ' ./ci-visibility/mocha-plugin-tests/retries-parallel-2.js', + { + cwd, + env: getCiVisAgentlessConfig(receiver.port), + } + ) + await Promise.all([ + eventsPromise, + once(childProcess, 'exit'), + ]) + }) + it('does not blow up when workerpool is used outside of a test', (done) => { childProcess = exec('node ./ci-visibility/run-workerpool.js', { cwd, diff --git a/packages/datadog-instrumentations/src/mocha/worker.js b/packages/datadog-instrumentations/src/mocha/worker.js index 6734f24d7b1..dd70b1d2dfe 100644 --- a/packages/datadog-instrumentations/src/mocha/worker.js +++ b/packages/datadog-instrumentations/src/mocha/worker.js @@ -10,6 +10,7 @@ const { getOnHookEndHandler, getOnFailHandler, getOnPendingHandler, + getOnTestRetryHandler, getRunTestsWrapper, } = require('./utils') require('./common') @@ -74,6 +75,8 @@ addHook({ this.on('test end', getOnTestEndHandler(config)) + this.on('retry', getOnTestRetryHandler(config)) + // If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted this.on('hook end', getOnHookEndHandler()) From db2ea3ec7bcad63b74e2f121c8eeea6c612e7c29 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 13 Mar 2026 12:35:10 +0100 Subject: [PATCH 2/6] feat(mocha): enable auto test retries in parallel mode Pass isFlakyTestRetriesEnabled and flakyTestRetriesCount config from the main process to parallel workers via Mocha options, following the same pattern used for EFD and Test Management. Also fix runnableWrapper in the worker to receive the config so this.retries() is called. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../eventually-passing-test-parallel-2.js | 10 +++ .../eventually-passing-test-parallel.js | 10 +++ integration-tests/mocha/mocha.spec.js | 68 +++++++++++++++++++ .../src/mocha/main.js | 14 ++-- .../src/mocha/worker.js | 9 ++- 5 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel-2.js create mode 100644 integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel.js diff --git a/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel-2.js b/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel-2.js new file mode 100644 index 00000000000..dca7d600795 --- /dev/null +++ b/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel-2.js @@ -0,0 +1,10 @@ +'use strict' + +const assert = require('assert') +let counter = 0 + +describe('test-flaky-test-retries-parallel-2', () => { + it('can retry failed tests', () => { + assert.strictEqual(++counter, 3) + }) +}) diff --git a/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel.js b/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel.js new file mode 100644 index 00000000000..6ce6f6df622 --- /dev/null +++ b/integration-tests/ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel.js @@ -0,0 +1,10 @@ +'use strict' + +const assert = require('assert') +let counter = 0 + +describe('test-flaky-test-retries-parallel', () => { + it('can retry failed tests', () => { + assert.strictEqual(++counter, 3) + }) +}) diff --git a/integration-tests/mocha/mocha.spec.js b/integration-tests/mocha/mocha.spec.js index 9c36a410174..89dc6fd6dec 100644 --- a/integration-tests/mocha/mocha.spec.js +++ b/integration-tests/mocha/mocha.spec.js @@ -3277,6 +3277,74 @@ describe(`mocha@${MOCHA_VERSION}`, function () { await Promise.all([once(childProcess, 'exit'), eventsPromise]) }) + + onlyLatestIt('retries failed tests automatically in parallel mode', async () => { + receiver.setSettings({ + flaky_test_retries_enabled: true, + early_flake_detection: { + enabled: false, + }, + }) + + const eventsPromise = receiver + .gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => { + const events = payloads.flatMap(({ payload }) => payload.events) + const tests = events.filter(event => event.type === 'test').map(event => event.content) + + // Verify we are in parallel mode + const sessionEvent = events.find(event => event.type === 'test_session_end').content + assert.strictEqual(sessionEvent.meta[MOCHA_IS_PARALLEL], 'true') + + // Each file has 1 test that fails twice then passes (3 events per file, 6 total) + assert.strictEqual(tests.length, 6) + + const failedAttempts = tests.filter(test => test.meta[TEST_STATUS] === 'fail') + assert.strictEqual(failedAttempts.length, 4) + + const passedAttempts = tests.filter(test => test.meta[TEST_STATUS] === 'pass') + assert.strictEqual(passedAttempts.length, 2) + + // Retries should be tagged with ATR reason + const atrRetries = tests.filter( + test => test.meta[TEST_RETRY_REASON] === TEST_RETRY_REASON_TYPES.atr + ) + assert.strictEqual(atrRetries.length, 4) + + passedAttempts.forEach(test => { + assert.strictEqual(test.meta[TEST_IS_RETRY], 'true') + assert.strictEqual(test.meta[TEST_RETRY_REASON], TEST_RETRY_REASON_TYPES.atr) + }) + + // Verify tests ran in separate worker processes + const testsBySuite = {} + for (const test of tests) { + const suiteName = test.meta[TEST_SUITE] + if (!testsBySuite[suiteName]) { + testsBySuite[suiteName] = test + } + } + const testFromEachWorker = Object.values(testsBySuite) + assert.strictEqual(testFromEachWorker.length, 2) + const runtimeIds = testFromEachWorker.map(test => test.meta['runtime-id']) + assert.ok(runtimeIds[0]) + assert.ok(runtimeIds[1]) + assert.notStrictEqual(runtimeIds[0], runtimeIds[1]) + }) + + childProcess = exec( + 'node node_modules/mocha/bin/mocha --parallel --jobs 2' + + ' ./ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel.js' + + ' ./ci-visibility/test-flaky-test-retries/eventually-passing-test-parallel-2.js', + { + cwd, + env: getCiVisAgentlessConfig(receiver.port), + } + ) + await Promise.all([ + eventsPromise, + once(childProcess, 'exit'), + ]) + }) }) it('takes into account untested files if "all" is passed to nyc', (done) => { diff --git a/packages/datadog-instrumentations/src/mocha/main.js b/packages/datadog-instrumentations/src/mocha/main.js index 7cc7529f0f1..c6ba716def1 100644 --- a/packages/datadog-instrumentations/src/mocha/main.js +++ b/packages/datadog-instrumentations/src/mocha/main.js @@ -315,10 +315,10 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini config.isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled config.testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries config.isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled - // ITR and auto test retries are not supported in parallel mode yet + // ITR is not supported in parallel mode yet config.isSuitesSkippingEnabled = !isParallel && libraryConfig.isSuitesSkippingEnabled - config.isFlakyTestRetriesEnabled = !isParallel && libraryConfig.isFlakyTestRetriesEnabled - config.flakyTestRetriesCount = !isParallel && libraryConfig.flakyTestRetriesCount + config.isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled + config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount if (config.isKnownTestsEnabled) { ctx.onDone = onReceivedKnownTests @@ -663,7 +663,8 @@ addHook({ if (!testFinishCh.hasSubscribers || (!config.isKnownTestsEnabled && !config.isTestManagementTestsEnabled && - !config.isImpactedTestsEnabled)) { + !config.isImpactedTestsEnabled && + !config.isFlakyTestRetriesEnabled)) { return run.apply(this, arguments) } @@ -709,6 +710,11 @@ addHook({ newWorkerArgs._ddModifiedFiles = config.modifiedFiles || {} } + if (config.isFlakyTestRetriesEnabled) { + newWorkerArgs._ddIsFlakyTestRetriesEnabled = true + newWorkerArgs._ddFlakyTestRetriesCount = config.flakyTestRetriesCount + } + // We pass the known tests for the test file to the worker const testFileResult = await run.apply( this, diff --git a/packages/datadog-instrumentations/src/mocha/worker.js b/packages/datadog-instrumentations/src/mocha/worker.js index dd70b1d2dfe..224d5e32deb 100644 --- a/packages/datadog-instrumentations/src/mocha/worker.js +++ b/packages/datadog-instrumentations/src/mocha/worker.js @@ -49,6 +49,12 @@ addHook({ delete this.options._ddIsTestManagementTestsEnabled delete this.options._ddTestManagementTests } + if (this.options._ddIsFlakyTestRetriesEnabled) { + config.isFlakyTestRetriesEnabled = true + config.flakyTestRetriesCount = this.options._ddFlakyTestRetriesCount + delete this.options._ddIsFlakyTestRetriesEnabled + delete this.options._ddFlakyTestRetriesCount + } return run.apply(this, arguments) }) @@ -95,5 +101,4 @@ addHook({ name: 'mocha', versions: ['>=5.2.0'], file: 'lib/runnable.js', -}, runnableWrapper) -// TODO: parallel mode does not support flaky test retries, so no library config is passed. +}, (runnablePackage) => runnableWrapper(runnablePackage, config)) From 25d1ff6d82d76668875e0ca6855fa4154cc40b4b Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 13 Mar 2026 15:56:07 +0100 Subject: [PATCH 3/6] test(mocha): assert retry_reason is external for native --retries Co-Authored-By: Claude Opus 4.6 (1M context) --- integration-tests/mocha/mocha.spec.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/integration-tests/mocha/mocha.spec.js b/integration-tests/mocha/mocha.spec.js index 89dc6fd6dec..260267ca7b1 100644 --- a/integration-tests/mocha/mocha.spec.js +++ b/integration-tests/mocha/mocha.spec.js @@ -1378,6 +1378,11 @@ describe(`mocha@${MOCHA_VERSION}`, function () { const retries = tests.filter(test => test.meta[TEST_IS_RETRY] === 'true') assert.strictEqual(retries.length, 4) + // Native --retries (not ATR), so retry reason should be 'external' + retries.forEach(test => { + assert.strictEqual(test.meta[TEST_RETRY_REASON], TEST_RETRY_REASON_TYPES.ext) + }) + // Verify the two files ran in separate worker processes const testsBySuite = {} for (const test of tests) { From 8b0798325765babb242eeb1fd6a274b311df22cd Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 13 Mar 2026 12:54:39 +0100 Subject: [PATCH 4/6] feat(mocha): enable attempt-to-fix in parallel mode Uncomment and wire up testManagementAttemptToFixRetries config flow from main process to workers. Also remove stale comment in utils.js about flaky test retries not working in parallel mode. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../test-attempt-to-fix-parallel-1.js | 9 +++ .../test-attempt-to-fix-parallel-2.js | 9 +++ integration-tests/mocha/mocha.spec.js | 80 +++++++++++++++++++ .../src/mocha/main.js | 3 +- .../src/mocha/utils.js | 1 - .../src/mocha/worker.js | 4 +- 6 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-1.js create mode 100644 integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-2.js diff --git a/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-1.js b/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-1.js new file mode 100644 index 00000000000..aa67382dd4e --- /dev/null +++ b/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-1.js @@ -0,0 +1,9 @@ +'use strict' + +const assert = require('assert') + +describe('attempt to fix parallel tests 1', () => { + it('can attempt to fix a test', () => { + assert.strictEqual(1 + 2, 4) + }) +}) diff --git a/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-2.js b/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-2.js new file mode 100644 index 00000000000..af3e88de361 --- /dev/null +++ b/integration-tests/ci-visibility/test-management/test-attempt-to-fix-parallel-2.js @@ -0,0 +1,9 @@ +'use strict' + +const assert = require('assert') + +describe('attempt to fix parallel tests 2', () => { + it('can attempt to fix a test', () => { + assert.strictEqual(1 + 2, 4) + }) +}) diff --git a/integration-tests/mocha/mocha.spec.js b/integration-tests/mocha/mocha.spec.js index 260267ca7b1..4b882ed8793 100644 --- a/integration-tests/mocha/mocha.spec.js +++ b/integration-tests/mocha/mocha.spec.js @@ -4012,6 +4012,86 @@ describe(`mocha@${MOCHA_VERSION}`, function () { runAttemptToFixTest(done, { isAttemptToFix: true, isDisabled: true }) }) + + onlyLatestIt('can attempt to fix in parallel mode', async () => { + const NUM_RETRIES = 3 + receiver.setSettings({ test_management: { enabled: true, attempt_to_fix_retries: NUM_RETRIES } }) + receiver.setTestManagementTests({ + mocha: { + suites: { + 'ci-visibility/test-management/test-attempt-to-fix-parallel-1.js': { + tests: { + 'attempt to fix parallel tests 1 can attempt to fix a test': { + properties: { attempt_to_fix: true }, + }, + }, + }, + 'ci-visibility/test-management/test-attempt-to-fix-parallel-2.js': { + tests: { + 'attempt to fix parallel tests 2 can attempt to fix a test': { + properties: { attempt_to_fix: true }, + }, + }, + }, + }, + }, + }) + + const eventsPromise = receiver + .gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => { + const events = payloads.flatMap(({ payload }) => payload.events) + const tests = events.filter(event => event.type === 'test').map(event => event.content) + + const sessionEvent = events.find(event => event.type === 'test_session_end').content + assert.strictEqual(sessionEvent.meta[MOCHA_IS_PARALLEL], 'true') + assert.strictEqual(sessionEvent.meta[TEST_MANAGEMENT_ENABLED], 'true') + + // Each file: 1 initial attempt + NUM_RETRIES retries = (NUM_RETRIES + 1) per file, 2 files + assert.strictEqual(tests.length, (NUM_RETRIES + 1) * 2) + + // All attempts fail (tests always throw) + tests.forEach(test => { + assert.strictEqual(test.meta[TEST_STATUS], 'fail') + assert.strictEqual(test.meta[TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX], 'true') + }) + + // Last attempt of each test should have failed-all-retries + const testsBySuite = {} + for (const test of tests) { + const suite = test.meta[TEST_SUITE] + if (!testsBySuite[suite]) testsBySuite[suite] = [] + testsBySuite[suite].push(test) + } + for (const suiteTests of Object.values(testsBySuite)) { + const lastAttempt = suiteTests[suiteTests.length - 1] + assert.strictEqual(lastAttempt.meta[TEST_HAS_FAILED_ALL_RETRIES], 'true') + assert.strictEqual(lastAttempt.meta[TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED], 'false') + } + + // Verify separate worker processes + const firstTestPerSuite = Object.values(testsBySuite).map(t => t[0]) + assert.strictEqual(firstTestPerSuite.length, 2) + const runtimeIds = firstTestPerSuite.map(t => t.meta['runtime-id']) + assert.ok(runtimeIds[0]) + assert.ok(runtimeIds[1]) + assert.notStrictEqual(runtimeIds[0], runtimeIds[1]) + }) + + childProcess = exec( + 'node node_modules/mocha/bin/mocha --parallel --jobs 2' + + ' ./ci-visibility/test-management/test-attempt-to-fix-parallel-1.js' + + ' ./ci-visibility/test-management/test-attempt-to-fix-parallel-2.js', + { + cwd, + env: getCiVisAgentlessConfig(receiver.port), + } + ) + + await Promise.all([ + eventsPromise, + once(childProcess, 'exit'), + ]) + }) }) context('disabled', () => { diff --git a/packages/datadog-instrumentations/src/mocha/main.js b/packages/datadog-instrumentations/src/mocha/main.js index c6ba716def1..69cd4512c38 100644 --- a/packages/datadog-instrumentations/src/mocha/main.js +++ b/packages/datadog-instrumentations/src/mocha/main.js @@ -694,8 +694,7 @@ addHook({ if (config.isTestManagementTestsEnabled) { const testSuiteTestManagementTests = config.testManagementTests?.mocha?.suites?.[testPath] || {} newWorkerArgs._ddIsTestManagementTestsEnabled = true - // TODO: attempt to fix does not work in parallel mode yet - // newWorkerArgs._ddTestManagementAttemptToFixRetries = config.testManagementAttemptToFixRetries + newWorkerArgs._ddTestManagementAttemptToFixRetries = config.testManagementAttemptToFixRetries newWorkerArgs._ddTestManagementTests = { mocha: { suites: { diff --git a/packages/datadog-instrumentations/src/mocha/utils.js b/packages/datadog-instrumentations/src/mocha/utils.js index 6ba5a287d73..54644660bc9 100644 --- a/packages/datadog-instrumentations/src/mocha/utils.js +++ b/packages/datadog-instrumentations/src/mocha/utils.js @@ -140,7 +140,6 @@ function runnableWrapper (RunnablePackage, libraryConfig) { if (!testFinishCh.hasSubscribers) { return run.apply(this, arguments) } - // Flaky test retries does not work in parallel mode if (libraryConfig?.isFlakyTestRetriesEnabled) { this.retries(libraryConfig?.flakyTestRetriesCount) } diff --git a/packages/datadog-instrumentations/src/mocha/worker.js b/packages/datadog-instrumentations/src/mocha/worker.js index 224d5e32deb..b7de0006172 100644 --- a/packages/datadog-instrumentations/src/mocha/worker.js +++ b/packages/datadog-instrumentations/src/mocha/worker.js @@ -43,10 +43,10 @@ addHook({ } if (this.options._ddIsTestManagementTestsEnabled) { config.isTestManagementTestsEnabled = true - // TODO: attempt to fix does not work in parallel mode yet - // config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries + config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries config.testManagementTests = this.options._ddTestManagementTests delete this.options._ddIsTestManagementTestsEnabled + delete this.options._ddTestManagementAttemptToFixRetries delete this.options._ddTestManagementTests } if (this.options._ddIsFlakyTestRetriesEnabled) { From 7d0fe0191e3ba1509842bf53eb51a5e8d64ef560 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 13 Mar 2026 13:42:15 +0100 Subject: [PATCH 5/6] fix(mocha): remove mocha from UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE Now that attempt-to-fix works in parallel mode, remove the capability gate so the backend knows Mocha supports ATF in parallel. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/dd-trace/src/plugins/util/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dd-trace/src/plugins/util/test.js b/packages/dd-trace/src/plugins/util/test.js index 23d940b1c41..ab5eca5c622 100644 --- a/packages/dd-trace/src/plugins/util/test.js +++ b/packages/dd-trace/src/plugins/util/test.js @@ -170,7 +170,7 @@ const MINIMUM_FRAMEWORK_VERSION_FOR_FAILED_TEST_REPLAY = { playwright: '>=1.38.0', } -const UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE = new Set(['mocha']) +const UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE = new Set([]) const NOT_SUPPORTED_GRANULARITY_IMPACTED_TESTS_FRAMEWORKS = new Set(['mocha', 'playwright', 'vitest']) const TEST_LEVEL_EVENT_TYPES = [ From b5565417ca1eeefde45aa29e4c6a5ee64f388ba2 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Mon, 16 Mar 2026 12:25:03 +0100 Subject: [PATCH 6/6] test(mocha): update capabilities test for ATF in parallel mode Remove UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE (now empty) and simplify isAttemptToFixSupported. Update parallel capabilities test to expect ATF capability '5'. Co-Authored-By: Claude Opus 4.6 (1M context) --- integration-tests/mocha/mocha.spec.js | 3 +-- packages/dd-trace/src/plugins/util/test.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/integration-tests/mocha/mocha.spec.js b/integration-tests/mocha/mocha.spec.js index 4b882ed8793..8614452e68c 100644 --- a/integration-tests/mocha/mocha.spec.js +++ b/integration-tests/mocha/mocha.spec.js @@ -4485,11 +4485,10 @@ describe(`mocha@${MOCHA_VERSION}`, function () { metadataDicts.forEach(metadata => { if (isParallel) { assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS], undefined) - assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_MANAGEMENT_ATTEMPT_TO_FIX], undefined) } else { assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS], '1') - assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_MANAGEMENT_ATTEMPT_TO_FIX], '5') } + assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_MANAGEMENT_ATTEMPT_TO_FIX], '5') assert.strictEqual(metadata.test[DD_CAPABILITIES_EARLY_FLAKE_DETECTION], '1') assert.strictEqual(metadata.test[DD_CAPABILITIES_AUTO_TEST_RETRIES], '1') assert.strictEqual(metadata.test[DD_CAPABILITIES_TEST_MANAGEMENT_QUARANTINE], '1') diff --git a/packages/dd-trace/src/plugins/util/test.js b/packages/dd-trace/src/plugins/util/test.js index ab5eca5c622..6478ebe550d 100644 --- a/packages/dd-trace/src/plugins/util/test.js +++ b/packages/dd-trace/src/plugins/util/test.js @@ -170,7 +170,6 @@ const MINIMUM_FRAMEWORK_VERSION_FOR_FAILED_TEST_REPLAY = { playwright: '>=1.38.0', } -const UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE = new Set([]) const NOT_SUPPORTED_GRANULARITY_IMPACTED_TESTS_FRAMEWORKS = new Set(['mocha', 'playwright', 'vitest']) const TEST_LEVEL_EVENT_TYPES = [ @@ -1021,7 +1020,7 @@ function isAttemptToFixSupported (testFramework, isParallel, frameworkVersion) { return satisfies(frameworkVersion, MINIMUM_FRAMEWORK_VERSION_FOR_ATTEMPT_TO_FIX[testFramework]) } - return !(isParallel && UNSUPPORTED_ATTEMPT_TO_FIX_FRAMEWORKS_PARALLEL_MODE.has(testFramework)) + return true } function isFailedTestReplaySupported (testFramework, frameworkVersion) {