dd-trace 6.6.0 → 6.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/ci/diagnose.js +162 -21
  2. package/ci/init.js +0 -1
  3. package/ci/runbook.md +187 -180
  4. package/ci/test-optimization-validation/approval-artifacts.js +3 -1
  5. package/ci/test-optimization-validation/approval.js +52 -15
  6. package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
  7. package/ci/test-optimization-validation/ci-discovery.js +1 -1
  8. package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
  9. package/ci/test-optimization-validation/ci-remediation.js +112 -39
  10. package/ci/test-optimization-validation/cli.js +516 -681
  11. package/ci/test-optimization-validation/command-blocker.js +188 -33
  12. package/ci/test-optimization-validation/command-output-policy.js +8 -31
  13. package/ci/test-optimization-validation/command-runner.js +189 -245
  14. package/ci/test-optimization-validation/environment.js +90 -0
  15. package/ci/test-optimization-validation/executable.js +159 -388
  16. package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
  17. package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
  18. package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
  19. package/ci/test-optimization-validation/generated-files.js +84 -22
  20. package/ci/test-optimization-validation/generated-test-contract.js +281 -0
  21. package/ci/test-optimization-validation/generated-verifier.js +49 -16
  22. package/ci/test-optimization-validation/literal-environment.js +57 -0
  23. package/ci/test-optimization-validation/manifest-loader.js +2 -22
  24. package/ci/test-optimization-validation/manifest-scaffold.js +815 -515
  25. package/ci/test-optimization-validation/manifest-schema.js +494 -702
  26. package/ci/test-optimization-validation/offline-fixtures.js +4 -1
  27. package/ci/test-optimization-validation/offline-output.js +6 -6
  28. package/ci/test-optimization-validation/plan-writer.js +243 -984
  29. package/ci/test-optimization-validation/preflight-runner.js +49 -55
  30. package/ci/test-optimization-validation/redaction.js +2 -1
  31. package/ci/test-optimization-validation/report-writer.js +391 -1357
  32. package/ci/test-optimization-validation/result-semantics.js +86 -0
  33. package/ci/test-optimization-validation/runner-command.js +249 -0
  34. package/ci/test-optimization-validation/runner-contract.js +664 -0
  35. package/ci/test-optimization-validation/safe-files.js +4 -4
  36. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
  39. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
  40. package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
  41. package/ci/test-optimization-validation/scenarios/test-management.js +6 -5
  42. package/ci/test-optimization-validation/source-text.js +87 -0
  43. package/ci/test-optimization-validation/test-output.js +12 -22
  44. package/ci/vitest-no-worker-init-setup.mjs +348 -51
  45. package/ext/tags.d.ts +1 -0
  46. package/index.d.ts +84 -13
  47. package/package.json +10 -4
  48. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  49. package/packages/datadog-esbuild/index.js +4 -2
  50. package/packages/datadog-esbuild/src/utils.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
  52. package/packages/datadog-instrumentations/src/cucumber.js +9 -6
  53. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  54. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  55. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  56. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  63. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  64. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  65. package/packages/datadog-instrumentations/src/jest.js +8 -14
  66. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  67. package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
  68. package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
  69. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
  70. package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
  71. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  72. package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
  73. package/packages/datadog-instrumentations/src/playwright.js +3 -2
  74. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  75. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
  76. package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
  77. package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
  78. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  79. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  80. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  81. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  83. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  84. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  85. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  86. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  87. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  89. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  90. package/packages/datadog-plugin-fs/src/index.js +0 -4
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  93. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  94. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  95. package/packages/datadog-plugin-http/src/client.js +2 -1
  96. package/packages/datadog-plugin-jest/src/index.js +2 -3
  97. package/packages/datadog-plugin-jest/src/util.js +2 -1
  98. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  99. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  100. package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
  103. package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
  104. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  105. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  106. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  107. package/packages/datadog-plugin-undici/src/index.js +2 -1
  108. package/packages/datadog-plugin-vitest/src/index.js +84 -11
  109. package/packages/datadog-webpack/index.js +2 -2
  110. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  111. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  112. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  113. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  116. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  117. package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
  118. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  119. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +50 -51
  121. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
  122. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  124. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  125. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
  126. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  127. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +7 -5
  128. package/packages/dd-trace/src/config/defaults.js +14 -6
  129. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  130. package/packages/dd-trace/src/config/index.js +15 -0
  131. package/packages/dd-trace/src/config/parsers.js +19 -1
  132. package/packages/dd-trace/src/config/supported-configurations.json +12 -6
  133. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  134. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  135. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  136. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  137. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  138. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  139. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  140. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  141. package/packages/dd-trace/src/exporter.js +16 -9
  142. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  143. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  144. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  145. package/packages/dd-trace/src/flare/index.js +2 -2
  146. package/packages/dd-trace/src/id.js +1 -1
  147. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  148. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  150. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  151. package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
  152. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  153. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  154. package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
  155. package/packages/dd-trace/src/llmobs/index.js +9 -1
  156. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
  157. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  158. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  159. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  161. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
  162. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
  163. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
  164. package/packages/dd-trace/src/llmobs/sdk.js +6 -12
  165. package/packages/dd-trace/src/llmobs/span_processor.js +14 -7
  166. package/packages/dd-trace/src/llmobs/tagger.js +24 -5
  167. package/packages/dd-trace/src/llmobs/util.js +56 -3
  168. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  169. package/packages/dd-trace/src/noop/proxy.js +2 -2
  170. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
  171. package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
  172. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
  173. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  174. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  175. package/packages/dd-trace/src/opentracing/span.js +1 -1
  176. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  177. package/packages/dd-trace/src/plugins/ci_plugin.js +114 -23
  178. package/packages/dd-trace/src/plugins/index.js +2 -0
  179. package/packages/dd-trace/src/plugins/outbound.js +4 -1
  180. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  181. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  182. package/packages/dd-trace/src/plugins/util/ci.js +7 -6
  183. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  184. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
  185. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  186. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  187. package/packages/dd-trace/src/plugins/util/test.js +38 -12
  188. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  189. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  190. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  191. package/packages/dd-trace/src/priority_sampler.js +6 -3
  192. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  193. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  194. package/packages/dd-trace/src/ritm.js +5 -20
  195. package/packages/dd-trace/src/span_processor.js +1 -1
  196. package/packages/dd-trace/src/span_stats.js +22 -4
  197. package/packages/dd-trace/src/startup-log.js +3 -0
  198. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  199. package/packages/dd-trace/src/util.js +16 -0
  200. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  201. package/vendor/dist/pprof-format/index.js +1 -1
  202. package/vendor/dist/source-map/index.js +1 -1
  203. package/ci/test-optimization-validation/command-suitability.js +0 -471
  204. package/ci/test-optimization-validation/init-probe-preload.js +0 -163
  205. package/ci/test-optimization-validation/init-probe.js +0 -246
  206. package/ci/test-optimization-validation/late-initialization.js +0 -63
  207. package/ci/test-optimization-validation/local-command.js +0 -163
  208. package/ci/test-optimization-validation/setup-runner.js +0 -97
  209. package/ci/test-optimization-validation-manifest.schema.json +0 -1
@@ -96,7 +96,7 @@ const DD_JEST_HANDLE_TEST_EVENT_WRAPPED = Symbol('dd-trace:jest:handle-test-even
96
96
  const DD_JEST_HANDLE_TEST_EVENT_DATADOG = Symbol('dd-trace:jest:handle-test-event-datadog')
97
97
  const DD_JEST_CONCURRENT_TEST_ORIGINAL = Symbol('dd-trace:jest:concurrent-test-original')
98
98
  const isJestWorker = !!getEnvironmentVariable('JEST_WORKER_ID')
99
- const jestSessionState = globalThis[JEST_SESSION_STATE] || (globalThis[JEST_SESSION_STATE] = {})
99
+ const jestSessionState = (globalThis[JEST_SESSION_STATE] ||= {})
100
100
 
101
101
  // https://github.com/jestjs/jest/blob/41f842a46bb2691f828c3a5f27fc1d6290495b82/packages/jest-circus/src/types.ts#L9C8-L9C54
102
102
  const RETRY_TIMES = Symbol.for('RETRY_TIMES')
@@ -1192,9 +1192,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1192
1192
  ctx.testParameters = testParameters
1193
1193
  ctx.frameworkVersion = jestVersion
1194
1194
  ctx.isNew = isNewTest
1195
- ctx.isEfdRetry = ctx.isEfdRetry || numEfdRetry > 0
1195
+ ctx.isEfdRetry ||= numEfdRetry > 0
1196
1196
  ctx.isAttemptToFix = isAttemptToFix
1197
- ctx.isAttemptToFixRetry = ctx.isAttemptToFixRetry || numOfAttemptsToFixRetries > 0
1197
+ ctx.isAttemptToFixRetry ||= numOfAttemptsToFixRetries > 0
1198
1198
  ctx.isJestRetry = isJestRetry
1199
1199
  ctx.isDisabled = isDisabled
1200
1200
  ctx.isQuarantined = isQuarantined
@@ -1361,8 +1361,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1361
1361
  }
1362
1362
  }
1363
1363
  }
1364
- }
1365
- if (event.name === 'test_done') {
1364
+ } else if (event.name === 'test_done') {
1366
1365
  const originalError = event.test?.errors?.[0]
1367
1366
  let status = 'pass'
1368
1367
  if (event.test.errors && event.test.errors.length) {
@@ -1565,8 +1564,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1565
1564
  if (ctx.concurrentTestState) {
1566
1565
  ctx.currentStore = undefined
1567
1566
  }
1568
- }
1569
- if (event.name === 'run_finish') {
1567
+ } else if (event.name === 'run_finish') {
1570
1568
  for (const [test, errors] of atrSuppressedErrors) {
1571
1569
  // Do not restore errors for non-ATF quarantined tests — they should stay suppressed
1572
1570
  // so Jest doesn't see the failure (prevents --bail from stopping the run).
@@ -1595,8 +1593,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1595
1593
  attemptToFixRetriedTestsStatuses.clear()
1596
1594
  testsToBeRetried.clear()
1597
1595
  testSuiteDatadogEnvironments.delete(this.testSuiteAbsolutePath)
1598
- }
1599
- if (event.name === 'test_skip' || event.name === 'test_todo') {
1596
+ } else if (event.name === 'test_skip' || event.name === 'test_todo') {
1600
1597
  const testName = getJestTestName(event.test)
1601
1598
  testSkippedCh.publish({
1602
1599
  test: {
@@ -2298,12 +2295,11 @@ function getCliWrapper (isNewJestVersion) {
2298
2295
  } = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
2299
2296
  if (err) {
2300
2297
  skippableSuitesCoverage = {}
2301
- skippedSuitesCoverage = {}
2302
2298
  } else {
2303
2299
  skippableSuites = receivedSkippableSuites
2304
2300
  skippableSuitesCoverage = receivedSkippableSuitesCoverage || {}
2305
- skippedSuitesCoverage = {}
2306
2301
  }
2302
+ skippedSuitesCoverage = {}
2307
2303
  } catch (err) {
2308
2304
  log.error('Jest test-suite skippable error', err)
2309
2305
  }
@@ -3037,9 +3033,7 @@ function wrapJestObject (jestObject, suiteFilePath) {
3037
3033
 
3038
3034
  shimmer.wrap(jestObject, 'mock', mock => function (moduleName) {
3039
3035
  // If the library is mocked with `jest.mock`, we don't want to bypass jest's own require engine
3040
- if (LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.has(moduleName)) {
3041
- LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.delete(moduleName)
3042
- }
3036
+ LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE.delete(moduleName)
3043
3037
  recordMockedFile(suiteFilePath, moduleName)
3044
3038
  return mock.apply(this, arguments)
3045
3039
  })
@@ -41,11 +41,9 @@ addHook({
41
41
  }, (Suite) => {
42
42
  shimmer.wrap(Suite.prototype, 'addTest', addTest => function (test) {
43
43
  const callSites = getCallSites()
44
- let startLine
45
44
  const testCallSite = callSites.find(site => site.getFileName() === test.file)
46
45
  if (testCallSite) {
47
- startLine = testCallSite.getLineNumber()
48
- testToStartLine.set(test, startLine)
46
+ testToStartLine.set(test, testCallSite.getLineNumber())
49
47
  }
50
48
  return addTest.apply(this, arguments)
51
49
  })
@@ -53,6 +53,7 @@ const {
53
53
  newTestsWithDynamicNames,
54
54
  attemptToFixExecutions,
55
55
  loggedAttemptToFixTests,
56
+ adjustRunnerFailuresForTestOptimization,
56
57
  } = require('./utils')
57
58
 
58
59
  require('./common')
@@ -114,17 +115,6 @@ function warnDeprecatedMochaVersion (frameworkVersion) {
114
115
  )
115
116
  }
116
117
 
117
- // Tests from workers do not come with `isFailed` method
118
- function isTestFailed (test) {
119
- if (test.isFailed) {
120
- return test.isFailed()
121
- }
122
- if (test.isPending) {
123
- return !test.isPending() && test.state === 'failed'
124
- }
125
- return false
126
- }
127
-
128
118
  function getRootSuiteStatus (rootTests) {
129
119
  let status = 'pass'
130
120
  if (rootTests.every(t => t.isPending())) {
@@ -309,37 +299,7 @@ function getOnEndHandler (isParallel, onDone) {
309
299
  status = 'fail'
310
300
  }
311
301
 
312
- if (config.isEarlyFlakeDetectionEnabled) {
313
- /**
314
- * If Early Flake Detection (EFD) is enabled the logic is as follows:
315
- * - If all attempts for a test are failing, the test has failed and we will let the test process fail.
316
- * - If just a single attempt passes, we will prevent the test process from failing.
317
- * The rationale behind is the following: you may still be able to block your CI pipeline by gating
318
- * on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
319
- */
320
- for (const tests of Object.values(efdTests)) {
321
- const failingEfdTests = tests.filter(test => isTestFailed(test))
322
- const areAllEfdTestsFailing = failingEfdTests.length === tests.length
323
- const nonQuarantinedFailingEfdTests = failingEfdTests.filter(test => !testsQuarantined.has(test))
324
- if (nonQuarantinedFailingEfdTests.length && !areAllEfdTestsFailing) {
325
- this.stats.failures -= nonQuarantinedFailingEfdTests.length
326
- this.failures -= nonQuarantinedFailingEfdTests.length
327
- }
328
- }
329
- }
330
-
331
- // We subtract the errors from quarantined tests from the total number of failures.
332
- // Attempt-to-fix tests ignore quarantine/disabled suppression and keep their framework result.
333
- if (config.isTestManagementTestsEnabled) {
334
- let numFailedQuarantinedTests = 0
335
- for (const test of testsQuarantined) {
336
- if (isTestFailed(test)) {
337
- numFailedQuarantinedTests++
338
- }
339
- }
340
- this.stats.failures -= numFailedQuarantinedTests
341
- this.failures -= numFailedQuarantinedTests
342
- }
302
+ adjustRunnerFailuresForTestOptimization(this, config)
343
303
 
344
304
  // Recompute status after EFD and quarantine adjustments have reduced failure counts
345
305
  if (status === 'fail') {
@@ -48,6 +48,59 @@ function waitForHitProbe () {
48
48
  }
49
49
  const loggedAttemptToFixTests = new Set()
50
50
 
51
+ /**
52
+ * Checks whether a Mocha test failed, including serialized tests from parallel workers.
53
+ *
54
+ * @param {object} test
55
+ * @returns {boolean}
56
+ */
57
+ function isTestFailed (test) {
58
+ if (test.isFailed) {
59
+ return test.isFailed()
60
+ }
61
+ if (test.isPending) {
62
+ return !test.isPending() && test.state === 'failed'
63
+ }
64
+ return false
65
+ }
66
+
67
+ /**
68
+ * Applies EFD and quarantine failure suppression to a completed Mocha runner.
69
+ *
70
+ * @param {object} runner
71
+ * @param {object} config
72
+ * @returns {void}
73
+ */
74
+ function adjustRunnerFailuresForTestOptimization (runner, config) {
75
+ if (config.isEarlyFlakeDetectionEnabled) {
76
+ for (const tests of Object.values(efdTests)) {
77
+ const executedEfdTests = tests.filter(test => !test.isPending())
78
+ const failingEfdTests = tests.filter(test => isTestFailed(test))
79
+ const areAllEfdTestsFailing = failingEfdTests.length === executedEfdTests.length
80
+ const nonQuarantinedFailingEfdTests = failingEfdTests.filter(test => !testsQuarantined.has(test))
81
+ if (nonQuarantinedFailingEfdTests.length && !areAllEfdTestsFailing) {
82
+ if (runner.stats) {
83
+ runner.stats.failures -= nonQuarantinedFailingEfdTests.length
84
+ }
85
+ runner.failures -= nonQuarantinedFailingEfdTests.length
86
+ }
87
+ }
88
+ }
89
+
90
+ if (config.isTestManagementTestsEnabled) {
91
+ let numFailedQuarantinedTests = 0
92
+ for (const test of testsQuarantined) {
93
+ if (isTestFailed(test)) {
94
+ numFailedQuarantinedTests++
95
+ }
96
+ }
97
+ if (runner.stats) {
98
+ runner.stats.failures -= numFailedQuarantinedTests
99
+ }
100
+ runner.failures -= numFailedQuarantinedTests
101
+ }
102
+ }
103
+
51
104
  function getAfterEachHooks (testOrHook) {
52
105
  const hooks = []
53
106
 
@@ -165,6 +218,7 @@ function isDatadogManagedRetryTest (test, config) {
165
218
  * Checks whether a runnable belongs to an Early Flake Detection execution.
166
219
  * @param {{
167
220
  * _ddIsAttemptToFix?: boolean,
221
+ * _ddIsDisabled?: boolean,
168
222
  * _ddIsEfdRetry?: boolean,
169
223
  * _ddIsModified?: boolean,
170
224
  * _ddIsNew?: boolean
@@ -174,6 +228,7 @@ function isDatadogManagedRetryTest (test, config) {
174
228
  */
175
229
  function isEarlyFlakeDetectionTest (test, config) {
176
230
  return !test._ddIsAttemptToFix &&
231
+ !test._ddIsDisabled &&
177
232
  config.isEarlyFlakeDetectionEnabled &&
178
233
  (test._ddIsEfdRetry || test._ddIsNew || test._ddIsModified)
179
234
  }
@@ -949,7 +1004,12 @@ function getRunTestsWrapper (runTests, config) {
949
1004
  onDone: (isModified) => {
950
1005
  if (isModified) {
951
1006
  test._ddIsModified = true
952
- if (!test.isPending() && !test._ddIsAttemptToFix && config.isEarlyFlakeDetectionEnabled) {
1007
+ if (
1008
+ !test.isPending() &&
1009
+ !test._ddIsDisabled &&
1010
+ !test._ddIsAttemptToFix &&
1011
+ config.isEarlyFlakeDetectionEnabled
1012
+ ) {
953
1013
  retryTest(
954
1014
  test,
955
1015
  getConfiguredEfdRetryCount(config),
@@ -968,7 +1028,12 @@ function getRunTestsWrapper (runTests, config) {
968
1028
  suite.tests.forEach((test) => {
969
1029
  if (!test.isPending() && isNewTest(test, config.knownTests)) {
970
1030
  test._ddIsNew = true
971
- if (config.isEarlyFlakeDetectionEnabled && !test._ddIsAttemptToFix && !test._ddIsModified) {
1031
+ if (
1032
+ config.isEarlyFlakeDetectionEnabled &&
1033
+ !test._ddIsDisabled &&
1034
+ !test._ddIsAttemptToFix &&
1035
+ !test._ddIsModified
1036
+ ) {
972
1037
  retryTest(
973
1038
  test,
974
1039
  getConfiguredEfdRetryCount(config),
@@ -1015,4 +1080,5 @@ module.exports = {
1015
1080
  testsStatuses,
1016
1081
  attemptToFixExecutions,
1017
1082
  loggedAttemptToFixTests,
1083
+ adjustRunnerFailuresForTestOptimization,
1018
1084
  }
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ createWebdriverioWorkerMessage,
5
+ WEBDRIVERIO_WORKER_ENV,
6
+ WEBDRIVERIO_WORKER_EVENT,
7
+ WEBDRIVERIO_WORKER_ORIGIN,
8
+ } = require('../../../dd-trace/src/ci-visibility/exporters/test-worker/webdriverio')
9
+
10
+ module.exports = {
11
+ CONFIGURATION_REQUEST: 'dd:test-optimization:webdriverio:configuration:request',
12
+ CONFIGURATION_RESPONSE: 'dd:test-optimization:webdriverio:configuration:response',
13
+ createWebdriverioWorkerMessage,
14
+ SUITE_FINISH: 'dd:test-optimization:webdriverio:test-suite:finish',
15
+ WORKER_READY: 'dd:test-optimization:webdriverio:worker:ready',
16
+ WEBDRIVERIO_WORKER_ENV,
17
+ WEBDRIVERIO_WORKER_EVENT,
18
+ WEBDRIVERIO_WORKER_ORIGIN,
19
+ }