dd-trace 5.104.0 → 5.106.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 (159) hide show
  1. package/LICENSE-3rdparty.csv +90 -102
  2. package/index.d.ts +82 -3
  3. package/package.json +15 -15
  4. package/packages/datadog-core/src/storage.js +1 -1
  5. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  6. package/packages/datadog-instrumentations/src/ai.js +8 -7
  7. package/packages/datadog-instrumentations/src/aws-sdk.js +16 -2
  8. package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
  9. package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
  10. package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +19 -0
  11. package/packages/datadog-instrumentations/src/cucumber.js +390 -157
  12. package/packages/datadog-instrumentations/src/dns.js +54 -18
  13. package/packages/datadog-instrumentations/src/fastify.js +142 -82
  14. package/packages/datadog-instrumentations/src/graphql.js +188 -62
  15. package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
  16. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  17. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
  18. package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
  19. package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
  20. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  21. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
  22. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
  23. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  24. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
  25. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
  26. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
  27. package/packages/datadog-instrumentations/src/hono.js +54 -3
  28. package/packages/datadog-instrumentations/src/http/server.js +9 -4
  29. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
  30. package/packages/datadog-instrumentations/src/jest.js +360 -150
  31. package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
  32. package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
  33. package/packages/datadog-instrumentations/src/nats.js +182 -0
  34. package/packages/datadog-instrumentations/src/nyc.js +38 -1
  35. package/packages/datadog-instrumentations/src/openai.js +33 -18
  36. package/packages/datadog-instrumentations/src/oracledb.js +6 -1
  37. package/packages/datadog-instrumentations/src/pino.js +17 -5
  38. package/packages/datadog-instrumentations/src/playwright.js +515 -292
  39. package/packages/datadog-instrumentations/src/router.js +76 -32
  40. package/packages/datadog-instrumentations/src/stripe.js +1 -1
  41. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  42. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
  43. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
  44. package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
  45. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
  46. package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
  47. package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
  48. package/packages/datadog-plugin-bunyan/src/index.js +28 -0
  49. package/packages/datadog-plugin-cucumber/src/index.js +17 -3
  50. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
  51. package/packages/datadog-plugin-cypress/src/support.js +69 -1
  52. package/packages/datadog-plugin-dns/src/lookup.js +8 -6
  53. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
  54. package/packages/datadog-plugin-graphql/src/execute.js +2 -0
  55. package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
  56. package/packages/datadog-plugin-http/src/server.js +40 -15
  57. package/packages/datadog-plugin-jest/src/index.js +11 -3
  58. package/packages/datadog-plugin-jest/src/util.js +15 -8
  59. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  60. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
  61. package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
  62. package/packages/datadog-plugin-mocha/src/index.js +19 -4
  63. package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
  64. package/packages/datadog-plugin-nats/src/consumer.js +43 -0
  65. package/packages/datadog-plugin-nats/src/index.js +20 -0
  66. package/packages/datadog-plugin-nats/src/producer.js +62 -0
  67. package/packages/datadog-plugin-nats/src/util.js +33 -0
  68. package/packages/datadog-plugin-next/src/index.js +5 -3
  69. package/packages/datadog-plugin-openai/src/tracing.js +15 -2
  70. package/packages/datadog-plugin-oracledb/src/index.js +13 -2
  71. package/packages/datadog-plugin-pino/src/index.js +42 -0
  72. package/packages/datadog-plugin-playwright/src/index.js +4 -4
  73. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  74. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  75. package/packages/datadog-plugin-router/src/index.js +33 -44
  76. package/packages/datadog-plugin-selenium/src/index.js +1 -1
  77. package/packages/datadog-plugin-vitest/src/index.js +5 -13
  78. package/packages/datadog-plugin-winston/src/index.js +30 -0
  79. package/packages/datadog-shimmer/src/shimmer.js +33 -40
  80. package/packages/dd-trace/src/aiguard/index.js +1 -1
  81. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  82. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  83. package/packages/dd-trace/src/appsec/index.js +1 -1
  84. package/packages/dd-trace/src/appsec/reporter.js +5 -6
  85. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  86. package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
  87. package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
  88. package/packages/dd-trace/src/baggage.js +7 -1
  89. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
  90. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
  91. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
  92. package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
  93. package/packages/dd-trace/src/config/supported-configurations.json +27 -8
  94. package/packages/dd-trace/src/datastreams/writer.js +2 -4
  95. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
  96. package/packages/dd-trace/src/encode/0.4.js +124 -108
  97. package/packages/dd-trace/src/encode/0.5.js +114 -26
  98. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
  99. package/packages/dd-trace/src/encode/agentless-json.js +4 -2
  100. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
  101. package/packages/dd-trace/src/encode/span-stats.js +16 -16
  102. package/packages/dd-trace/src/encode/tags-processors.js +16 -0
  103. package/packages/dd-trace/src/id.js +15 -0
  104. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
  105. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
  106. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  107. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  108. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
  109. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  110. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
  111. package/packages/dd-trace/src/llmobs/sdk.js +0 -16
  112. package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
  113. package/packages/dd-trace/src/llmobs/tagger.js +9 -1
  114. package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
  115. package/packages/dd-trace/src/llmobs/util.js +66 -3
  116. package/packages/dd-trace/src/log/index.js +1 -1
  117. package/packages/dd-trace/src/msgpack/chunk.js +394 -10
  118. package/packages/dd-trace/src/msgpack/index.js +96 -2
  119. package/packages/dd-trace/src/openfeature/encoding.js +70 -0
  120. package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
  121. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
  122. package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
  123. package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
  124. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  125. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +22 -3
  126. package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
  127. package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
  128. package/packages/dd-trace/src/opentracing/span.js +59 -19
  129. package/packages/dd-trace/src/opentracing/span_context.js +50 -3
  130. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
  131. package/packages/dd-trace/src/plugins/database.js +7 -6
  132. package/packages/dd-trace/src/plugins/index.js +4 -0
  133. package/packages/dd-trace/src/plugins/log_injection.js +56 -0
  134. package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
  135. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  136. package/packages/dd-trace/src/plugins/plugin.js +15 -17
  137. package/packages/dd-trace/src/plugins/tracing.js +43 -5
  138. package/packages/dd-trace/src/plugins/util/test.js +236 -13
  139. package/packages/dd-trace/src/plugins/util/web.js +79 -65
  140. package/packages/dd-trace/src/priority_sampler.js +2 -2
  141. package/packages/dd-trace/src/profiling/config.js +10 -23
  142. package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
  143. package/packages/dd-trace/src/profiling/profiler.js +21 -11
  144. package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
  145. package/packages/dd-trace/src/sampling_rule.js +7 -7
  146. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
  147. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
  148. package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
  149. package/packages/dd-trace/src/span_format.js +190 -58
  150. package/packages/dd-trace/src/spanleak.js +1 -1
  151. package/packages/dd-trace/src/standalone/index.js +3 -3
  152. package/packages/dd-trace/src/tagger.js +0 -2
  153. package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
  154. package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
  155. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  156. package/vendor/dist/protobufjs/index.js +1 -1
  157. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  158. package/packages/dd-trace/src/msgpack/encoder.js +0 -308
  159. package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
@@ -4,7 +4,7 @@
4
4
  const realSetTimeout = setTimeout
5
5
 
6
6
  const { readFileSync } = require('node:fs')
7
- const { builtinModules } = require('node:module')
7
+ const { builtinModules, createRequire } = require('node:module')
8
8
  const path = require('path')
9
9
  const satisfies = require('../../../vendor/dist/semifies')
10
10
  const { DD_MAJOR } = require('../../../version')
@@ -12,7 +12,8 @@ const shimmer = require('../../datadog-shimmer')
12
12
  const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
13
13
  const log = require('../../dd-trace/src/log')
14
14
  const {
15
- getCoveredFilenamesFromCoverage,
15
+ getCoveredFilesFromCoverage,
16
+ getExecutableFilesFromCoverage,
16
17
  JEST_WORKER_TRACE_PAYLOAD_CODE,
17
18
  JEST_WORKER_COVERAGE_PAYLOAD_CODE,
18
19
  JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
@@ -30,14 +31,21 @@ const {
30
31
  logAttemptToFixTestExecution,
31
32
  logTestOptimizationSummary,
32
33
  getEfdRetryCount,
34
+ getTestCoverageLinesPercentage,
35
+ applySkippedCoverageToCoverage,
33
36
  getTestOptimizationRequestResults,
34
37
  } = require('../../dd-trace/src/plugins/util/test')
35
38
  const {
36
- SEED_SUFFIX_RE,
37
39
  getFormattedJestTestParameters,
38
40
  getJestTestName,
41
+ getRawJestTestName,
39
42
  getJestSuitesToRun,
43
+ removeSeedSuffixFromTestName,
40
44
  } = require('../../datadog-plugin-jest/src/util')
45
+ const {
46
+ addCoverageBackfillUntestedFiles,
47
+ getCoverageBackfillFiles,
48
+ } = require('./jest/coverage-backfill')
41
49
  const { addHook, channel } = require('./helpers/instrument')
42
50
 
43
51
  const testSessionStartCh = channel('ci:jest:session:start')
@@ -84,11 +92,13 @@ const isJestWorker = !!getEnvironmentVariable('JEST_WORKER_ID')
84
92
  const RETRY_TIMES = Symbol.for('RETRY_TIMES')
85
93
 
86
94
  let skippableSuites = []
95
+ let skippableSuitesCoverage = {}
96
+ let skippedSuitesCoverage = {}
87
97
  let knownTests = {}
88
98
  let isCodeCoverageEnabled = false
89
- let isCodeCoverageEnabledBecauseOfUs = false
99
+ let isCoverageReportUploadEnabled = false
100
+ let isItrEnabled = false
90
101
  let isSuitesSkippingEnabled = false
91
- let DD_TEST_TIA_KEEP_COV_CONFIG = false
92
102
  let isUserCodeCoverageEnabled = false
93
103
  let isSuitesSkipped = false
94
104
  let numSkippedSuites = 0
@@ -106,6 +116,13 @@ let testManagementTests = {}
106
116
  let testManagementAttemptToFixRetries = 0
107
117
  let isImpactedTestsEnabled = false
108
118
  let modifiedFiles = {}
119
+ let repositoryRoot
120
+ let lastCoverageMap
121
+ let lastCoverageMapRootDir
122
+ let coverageBackfillContexts
123
+ let coverageBackfillFiles
124
+ let coverageReporterClass
125
+ let coverageReporterRequire
109
126
  let activeTestSuiteAbsolutePath
110
127
  let isConsoleErrorWrapped = false
111
128
 
@@ -130,13 +147,13 @@ const efdSlowAbortedTests = new Set()
130
147
  const efdNewTestCandidates = new Set()
131
148
  // Tests that are genuinely new (not in known tests list).
132
149
  const newTests = new Set()
133
- const testSuiteAbsolutePathsWithFastCheck = new Set()
134
- const testSuiteFastCheckUsage = new Map()
135
150
  const testSuiteJestObjects = new Map()
136
151
  const wrappedJestGlobals = new WeakSet()
137
152
  const wrappedJestObjects = new WeakSet()
138
153
  const wrappedWorkerInitializers = new WeakSet()
139
154
  const publishedRuntimeReferenceErrors = new WeakMap()
155
+ const wrappedCoverageReporters = new WeakSet()
156
+ const coverageReporterRequires = new WeakMap()
140
157
 
141
158
  const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
142
159
  const ATR_RETRY_SUPPRESSION_FLAG = '_ddDisableAtrRetry'
@@ -145,12 +162,22 @@ const MINIMUM_JEST_VERSION_BEFORE_30 = DD_MAJOR >= 6 ? '>=28.0.0 <30.0.0' : '>=2
145
162
  const MINIMUM_JEST_WORKER_VERSION_BEFORE_30 = DD_MAJOR >= 6 ? '>=28.0.0 <30.0.0' : '>=24.9.0 <30.0.0'
146
163
  const MINIMUM_JEST_CONFIG_ASYNC_VERSION = DD_MAJOR >= 6 ? '>=28.0.0' : '>=25.1.0'
147
164
  const MINIMUM_JEST_TEST_SCHEDULER_VERSION = DD_MAJOR >= 6 ? '>=28.0.0' : '>=27.0.0'
165
+ const MINIMUM_JEST_COVERAGE_BACKFILL_VERSION = '>=28.0.0'
148
166
  const atrSuppressedErrors = new Map()
149
167
  let hasWarnedDeprecatedJestVersion = false
168
+ let isJestCoverageBackfillSupported = false
150
169
 
151
170
  // Track quarantined tests whose errors were suppressed, keyed by "suite › testName"
152
171
  const quarantinedFailingTests = new Set()
153
172
 
173
+ function getJestRepositoryRoot (readConfigsResult) {
174
+ const configuredRepositoryRoot = readConfigsResult.configs
175
+ ?.find(config => config.testEnvironmentOptions?._ddRepositoryRoot)
176
+ ?.testEnvironmentOptions._ddRepositoryRoot
177
+
178
+ return configuredRepositoryRoot || process.cwd()
179
+ }
180
+
154
181
  /**
155
182
  * Sends suppressed quarantine test names from a worker process to the main process.
156
183
  * Supports both child_process (process.send) and worker_threads (parentPort.postMessage).
@@ -293,9 +320,7 @@ function getAttemptToFixExecutionsFromJestResults (result) {
293
320
  if (!testManagementTestsForSuite) continue
294
321
 
295
322
  for (const { fullName, status } of testResults) {
296
- const testName = testSuiteAbsolutePathsWithFastCheck.has(testFilePath)
297
- ? fullName.replace(SEED_SUFFIX_RE, '')
298
- : fullName
323
+ const testName = removeSeedSuffixFromTestName(fullName)
299
324
  const testStatus = getTestStatusFromJestResult(status)
300
325
  if (!testStatus) continue
301
326
 
@@ -341,7 +366,6 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
341
366
  super(config, context)
342
367
  const rootDir = config.globalConfig ? config.globalConfig.rootDir : config.rootDir
343
368
  this.rootDir = rootDir
344
- this.testSuite = getTestSuitePath(context.testPath, rootDir)
345
369
  this.nameToParams = {}
346
370
  this.global._ddtrace = global._ddtrace
347
371
  this.hasSnapshotTests = undefined
@@ -354,6 +378,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
354
378
  this.testEnvironmentOptions = getTestEnvironmentOptions(config)
355
379
 
356
380
  const repositoryRoot = this.testEnvironmentOptions._ddRepositoryRoot
381
+ this.testSuite = getTestSuitePath(context.testPath, rootDir)
357
382
 
358
383
  // TODO: could we grab testPath from `this.getVmContext().expect.getState()` instead?
359
384
  // so we don't rely on context being passed (some custom test environment do not pass it)
@@ -542,14 +567,11 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
542
567
  }
543
568
  }
544
569
 
545
- getShouldStripSeedFromTestName () {
546
- return doesTestSuiteUseFastCheck(this.testSuiteAbsolutePath)
547
- }
548
-
549
570
  // At the `add_test` event we don't have the test object yet, so we can't use it
550
571
  getTestNameFromAddTestEvent (event, state) {
551
- const describeSuffix = getJestTestName(state.currentDescribeBlock, this.getShouldStripSeedFromTestName())
552
- return describeSuffix ? `${describeSuffix} ${event.testName}` : event.testName
572
+ const describeSuffix = getRawJestTestName(state.currentDescribeBlock)
573
+ const testName = describeSuffix ? `${describeSuffix} ${event.testName}` : event.testName
574
+ return removeSeedSuffixFromTestName(testName)
553
575
  }
554
576
 
555
577
  async handleTestEvent (event, state) {
@@ -571,7 +593,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
571
593
  })
572
594
  }
573
595
  if (event.name === 'test_start') {
574
- const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
596
+ const testName = getJestTestName(event.test)
575
597
  if (testsToBeRetried.has(testName)) {
576
598
  // This is needed because we're retrying tests with the same name
577
599
  this.resetSnapshotState()
@@ -775,7 +797,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
775
797
  let attemptToFixFailed = false
776
798
  let failedAllTests = false
777
799
  let isAttemptToFix = false
778
- const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
800
+ const testName = getJestTestName(event.test)
779
801
  if (this.isTestManagementTestsEnabled) {
780
802
  isAttemptToFix = this.testManagementTestsForThisSuite?.attemptToFix?.includes(testName)
781
803
  if (isAttemptToFix) {
@@ -955,7 +977,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
955
977
  // so Jest doesn't see the failure (prevents --bail from stopping the run).
956
978
  const ctx = testContexts.get(test)
957
979
  if (ctx?.isQuarantined && !ctx.isAttemptToFix) {
958
- const testName = getJestTestName(test, this.getShouldStripSeedFromTestName())
980
+ const testName = getJestTestName(test)
959
981
  quarantinedFailingTests.add(`${ctx.suite} › ${testName}`)
960
982
  } else {
961
983
  test.errors = errors
@@ -979,7 +1001,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
979
1001
  testsToBeRetried.clear()
980
1002
  }
981
1003
  if (event.name === 'test_skip' || event.name === 'test_todo') {
982
- const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
1004
+ const testName = getJestTestName(event.test)
983
1005
  testSkippedCh.publish({
984
1006
  test: {
985
1007
  name: testName,
@@ -1129,8 +1151,107 @@ function getTestEnvironment (pkg, jestVersion) {
1129
1151
  return getWrappedEnvironment(pkg, jestVersion)
1130
1152
  }
1131
1153
 
1154
+ function getRepositoryRootFromConfig (config, fallbackRootDir) {
1155
+ return config?.testEnvironmentOptions?._ddRepositoryRoot || repositoryRoot || fallbackRootDir || process.cwd()
1156
+ }
1157
+
1158
+ function getRepositoryRootFromContexts (contexts, fallbackRootDir) {
1159
+ const [firstContext] = contexts || []
1160
+ return getRepositoryRootFromConfig(firstContext?.config, fallbackRootDir)
1161
+ }
1162
+
1163
+ function getRepositoryRootFromTest (test, fallbackRootDir) {
1164
+ return getRepositoryRootFromConfig(test?.context?.config, fallbackRootDir)
1165
+ }
1166
+
1167
+ function hasSkippableSuitesCoverage () {
1168
+ return skippableSuitesCoverage &&
1169
+ typeof skippableSuitesCoverage === 'object' &&
1170
+ Object.keys(skippableSuitesCoverage).length > 0
1171
+ }
1172
+
1173
+ function shouldCollectJestCoverageForTia () {
1174
+ return shouldReportJestSuiteCoverageForTia() ||
1175
+ (isJestCoverageBackfillSupported && isItrEnabled && isCoverageReportUploadEnabled)
1176
+ }
1177
+
1178
+ function shouldReportJestSuiteCoverageForTia () {
1179
+ return isItrEnabled && isCodeCoverageEnabled
1180
+ }
1181
+
1182
+ function hasJestCoverageMap () {
1183
+ return isUserCodeCoverageEnabled || shouldCollectJestCoverageForTia()
1184
+ }
1185
+
1186
+ // TIA coverage backfill is part of Datadog Code Coverage, not the per-suite TIA coverage upload.
1187
+ function isTiaCoverageBackfillEnabled () {
1188
+ return isJestCoverageBackfillSupported && isItrEnabled && isCoverageReportUploadEnabled && hasJestCoverageMap()
1189
+ }
1190
+
1191
+ // Non-TIA Jest coverage keeps the legacy metric. TIA only reports it when Datadog Code Coverage is enabled and
1192
+ // either the run is complete locally or the skipped suites can be backfilled.
1193
+ function shouldReportCodeCoverageLinesPct () {
1194
+ if (!hasJestCoverageMap()) return false
1195
+ if (!isItrEnabled) return true
1196
+ if (!isCoverageReportUploadEnabled) return false
1197
+
1198
+ // If no suites were actually skipped, the local Jest coverage map is complete and does not need backfill.
1199
+ return !isSuitesSkipped || isTiaCoverageBackfillEnabled()
1200
+ }
1201
+
1202
+ function getHookRequire (hookMeta) {
1203
+ if (!hookMeta?.moduleBaseDir) return
1204
+
1205
+ return createRequire(path.join(hookMeta.moduleBaseDir, 'package.json'))
1206
+ }
1207
+
1208
+ function getCoverageBackfillRequire (CoverageReporter) {
1209
+ const hookedCoverageReporterRequire = CoverageReporter && coverageReporterRequires.get(CoverageReporter)
1210
+ if (hookedCoverageReporterRequire) return hookedCoverageReporterRequire
1211
+ if (coverageReporterRequire) return coverageReporterRequire
1212
+
1213
+ const coverageReporterFilename = CoverageReporter?.filename || coverageReporterClass?.filename
1214
+ if (coverageReporterFilename) {
1215
+ return createRequire(`${path.join(path.dirname(coverageReporterFilename), 'CoverageWorker')}.js`)
1216
+ }
1217
+
1218
+ return require
1219
+ }
1220
+
1221
+ function getTestContexts (tests) {
1222
+ if (!tests?.length) return
1223
+
1224
+ const contexts = new Set()
1225
+ for (const test of tests) {
1226
+ if (test.context) {
1227
+ contexts.add(test.context)
1228
+ }
1229
+ }
1230
+ return contexts.size ? contexts : undefined
1231
+ }
1232
+
1233
+ function getCoverageBackfillContexts (contexts) {
1234
+ return contexts?.size ? contexts : coverageBackfillContexts || contexts
1235
+ }
1236
+
1237
+ function resetSuiteSkippingRunState () {
1238
+ isSuitesSkipped = false
1239
+ numSkippedSuites = 0
1240
+ hasUnskippableSuites = false
1241
+ hasForcedToRunSuites = false
1242
+ hasFilteredSkippableSuites = false
1243
+ skippedSuitesCoverage = {}
1244
+ lastCoverageMap = undefined
1245
+ lastCoverageMapRootDir = undefined
1246
+ coverageBackfillContexts = undefined
1247
+ coverageBackfillFiles = undefined
1248
+ }
1249
+
1132
1250
  function applySuiteSkipping (originalTests, rootDir, frameworkVersion) {
1133
- const jestSuitesToRun = getJestSuitesToRun(skippableSuites, originalTests, rootDir || process.cwd())
1251
+ if (!isItrEnabled || !isSuitesSkippingEnabled) return originalTests
1252
+
1253
+ const suitePathRoot = getRepositoryRootFromTest(originalTests[0], rootDir)
1254
+ const jestSuitesToRun = getJestSuitesToRun(skippableSuites, originalTests, suitePathRoot)
1134
1255
  hasFilteredSkippableSuites = true
1135
1256
  log.debug('%d out of %d suites are going to run.', jestSuitesToRun.suitesToRun.length, originalTests.length)
1136
1257
  hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
@@ -1138,12 +1259,112 @@ function applySuiteSkipping (originalTests, rootDir, frameworkVersion) {
1138
1259
 
1139
1260
  isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== originalTests.length
1140
1261
  numSkippedSuites = jestSuitesToRun.skippedSuites.length
1262
+ skippedSuitesCoverage = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
1263
+ ? skippableSuitesCoverage
1264
+ : {}
1265
+ coverageBackfillContexts = isSuitesSkipped && isTiaCoverageBackfillEnabled()
1266
+ ? getTestContexts(originalTests)
1267
+ : undefined
1268
+ coverageBackfillFiles = isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
1269
+ ? getCoverageBackfillFiles(skippableSuitesCoverage, suitePathRoot, getTestSuitePath)
1270
+ : undefined
1141
1271
 
1142
1272
  itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
1143
1273
 
1144
1274
  return jestSuitesToRun.suitesToRun
1145
1275
  }
1146
1276
 
1277
+ function applySkippedCoverageToJestCoverageMap (coverageMap, rootDir) {
1278
+ if (!coverageMap || !isSuitesSkipped || !isTiaCoverageBackfillEnabled()) return
1279
+ applySkippedCoverageToCoverage(
1280
+ coverageMap,
1281
+ skippedSuitesCoverage,
1282
+ rootDir || process.cwd()
1283
+ )
1284
+ }
1285
+
1286
+ function reporterDispatcherWrapper (reporterDispatcherPackage) {
1287
+ const ReporterDispatcher = reporterDispatcherPackage.default ?? reporterDispatcherPackage
1288
+ if (ReporterDispatcher?.prototype?.onRunComplete) {
1289
+ shimmer.wrap(ReporterDispatcher.prototype, 'onRunComplete', onRunComplete => function (contexts, results) {
1290
+ if (isSuitesSkipped && isTiaCoverageBackfillEnabled()) {
1291
+ applySkippedCoverageToJestCoverageMap(results?.coverageMap, getRepositoryRootFromContexts(contexts))
1292
+ }
1293
+ return onRunComplete.apply(this, arguments)
1294
+ })
1295
+ }
1296
+
1297
+ return reporterDispatcherPackage
1298
+ }
1299
+
1300
+ function wrapCoverageReporter (CoverageReporter, hookMeta) {
1301
+ if (!CoverageReporter?.prototype?.onRunComplete || wrappedCoverageReporters.has(CoverageReporter)) {
1302
+ return
1303
+ }
1304
+
1305
+ coverageReporterRequire = getHookRequire(hookMeta) || coverageReporterRequire
1306
+ if (coverageReporterRequire) {
1307
+ coverageReporterRequires.set(CoverageReporter, coverageReporterRequire)
1308
+ }
1309
+ coverageReporterClass = CoverageReporter
1310
+ wrappedCoverageReporters.add(CoverageReporter)
1311
+ if (CoverageReporter.prototype._addUntestedFiles) {
1312
+ shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => function (...args) {
1313
+ const rootDir = repositoryRoot || this._globalConfig?.rootDir || process.cwd()
1314
+ args[0] = getCoverageBackfillContexts(args[0])
1315
+ const result = addUntestedFiles.apply(this, args)
1316
+ if (!isSuitesSkipped || !isTiaCoverageBackfillEnabled()) return result
1317
+
1318
+ const addBackfillAndApplyCoverage = () => {
1319
+ return addCoverageBackfillUntestedFiles({
1320
+ coverageMap: this._coverageMap,
1321
+ testContexts: args[0],
1322
+ rootDir,
1323
+ CoverageReporter,
1324
+ coverageBackfillFiles,
1325
+ getCoverageBackfillRequire,
1326
+ }).then(() => {
1327
+ applySkippedCoverageToJestCoverageMap(this._coverageMap, rootDir)
1328
+ })
1329
+ }
1330
+
1331
+ return Promise.resolve(result).then(value => {
1332
+ return addBackfillAndApplyCoverage().then(() => value)
1333
+ })
1334
+ })
1335
+ }
1336
+
1337
+ shimmer.wrap(CoverageReporter.prototype, 'onRunComplete', onRunComplete => async function (contexts, results) {
1338
+ const coverageContexts = getCoverageBackfillContexts(contexts)
1339
+ const rootDir = getRepositoryRootFromContexts(coverageContexts, this._globalConfig?.rootDir)
1340
+ const coverageMap = results?.coverageMap || this._coverageMap
1341
+ if (isSuitesSkipped && isTiaCoverageBackfillEnabled()) {
1342
+ await addCoverageBackfillUntestedFiles({
1343
+ coverageMap,
1344
+ testContexts: coverageContexts,
1345
+ rootDir,
1346
+ CoverageReporter,
1347
+ coverageBackfillFiles,
1348
+ getCoverageBackfillRequire,
1349
+ })
1350
+ applySkippedCoverageToJestCoverageMap(coverageMap, rootDir)
1351
+ }
1352
+ lastCoverageMap = coverageMap
1353
+ lastCoverageMapRootDir = rootDir
1354
+ return onRunComplete.call(this, coverageContexts, results)
1355
+ })
1356
+ }
1357
+
1358
+ function reportersWrapper (reportersPackage, _version, _isIitm, hookMeta) {
1359
+ wrapCoverageReporter(reportersPackage.CoverageReporter, hookMeta)
1360
+ return reportersPackage
1361
+ }
1362
+
1363
+ function coverageReporterWrapper (coverageReporterPackage, _version, _isIitm, hookMeta) {
1364
+ wrapCoverageReporter(coverageReporterPackage.default ?? coverageReporterPackage, hookMeta)
1365
+ return coverageReporterPackage
1366
+ }
1367
+
1147
1368
  addHook({
1148
1369
  name: 'jest-environment-node',
1149
1370
  versions: [MINIMUM_JEST_VERSION],
@@ -1188,7 +1409,9 @@ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
1188
1409
  const [{ rootDir, shard }] = arguments
1189
1410
 
1190
1411
  if (isKnownTestsEnabled) {
1191
- const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
1412
+ const projectSuites = testPaths.tests.map(test => {
1413
+ return getTestSuitePath(test.path, getRepositoryRootFromTest(test, test.context.config.rootDir))
1414
+ })
1192
1415
 
1193
1416
  // If the `jest` key does not exist in the known tests response, we consider the Early Flake detection faulty.
1194
1417
  const isFaulty = !knownTests?.jest ||
@@ -1208,14 +1431,11 @@ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
1208
1431
  }
1209
1432
  }
1210
1433
 
1434
+ // When Jest sharding is enabled, filter after Jest picks this process's shard. Different shards usually run in
1435
+ // different CI jobs, so their skippable requests can happen at different times and receive different responses.
1436
+ // Filtering before Jest shards would make each job shard a different base test list, which can cause duplicate
1437
+ // suite execution across shards.
1211
1438
  if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
1212
- // If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
1213
- // The reason for this is the following:
1214
- // The tests for different shards are likely being run in different CI jobs so
1215
- // the requests to the skippable endpoint might be done at different times and their responses might be different.
1216
- // If the skippable endpoint is returning different suites and we filter the list of tests here,
1217
- // the base list of tests that is used for sharding might be different,
1218
- // causing the shards to potentially run the same suite.
1219
1439
  return testPaths
1220
1440
  }
1221
1441
  const { tests } = testPaths
@@ -1230,6 +1450,8 @@ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
1230
1450
  function getCliWrapper (isNewJestVersion) {
1231
1451
  return function cliWrapper (cli, jestVersion) {
1232
1452
  warnDeprecatedJestVersion(jestVersion)
1453
+ isJestCoverageBackfillSupported = !!jestVersion &&
1454
+ satisfies(jestVersion, MINIMUM_JEST_COVERAGE_BACKFILL_VERSION)
1233
1455
 
1234
1456
  if (isNewJestVersion) {
1235
1457
  cli = shimmer.wrap(
@@ -1245,15 +1467,17 @@ function getCliWrapper (isNewJestVersion) {
1245
1467
  return runCLI.apply(this, arguments)
1246
1468
  }
1247
1469
 
1470
+ resetSuiteSkippingRunState()
1471
+
1248
1472
  try {
1249
1473
  const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh, {
1250
1474
  frameworkVersion: jestVersion,
1251
1475
  })
1252
1476
  if (!err) {
1253
1477
  isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
1254
- isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
1255
- DD_TEST_TIA_KEEP_COV_CONFIG =
1256
- libraryConfig.DD_TEST_TIA_KEEP_COV_CONFIG ?? DD_TEST_TIA_KEEP_COV_CONFIG
1478
+ isCoverageReportUploadEnabled = libraryConfig.isCoverageReportUploadEnabled
1479
+ isItrEnabled = libraryConfig.isItrEnabled
1480
+ isSuitesSkippingEnabled = isItrEnabled && libraryConfig.isSuitesSkippingEnabled
1257
1481
  isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
1258
1482
  earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
1259
1483
  earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
@@ -1297,10 +1521,18 @@ function getCliWrapper (isNewJestVersion) {
1297
1521
 
1298
1522
  if (isSuitesSkippingEnabled) {
1299
1523
  try {
1300
- const { err, skippableSuites: receivedSkippableSuites } =
1301
- skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1302
- if (!err) {
1524
+ const {
1525
+ err,
1526
+ skippableSuites: receivedSkippableSuites,
1527
+ skippableSuitesCoverage: receivedSkippableSuitesCoverage,
1528
+ } = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1529
+ if (err) {
1530
+ skippableSuitesCoverage = {}
1531
+ skippedSuitesCoverage = {}
1532
+ } else {
1303
1533
  skippableSuites = receivedSkippableSuites
1534
+ skippableSuitesCoverage = receivedSkippableSuitesCoverage || {}
1535
+ skippedSuitesCoverage = {}
1304
1536
  }
1305
1537
  } catch (err) {
1306
1538
  log.error('Jest test-suite skippable error', err)
@@ -1335,13 +1567,16 @@ function getCliWrapper (isNewJestVersion) {
1335
1567
  }
1336
1568
 
1337
1569
  const processArgv = process.argv.slice(2).join(' ')
1338
- testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
1570
+ testSessionStartCh.publish({
1571
+ command: `jest ${processArgv}`,
1572
+ frameworkVersion: jestVersion,
1573
+ })
1339
1574
 
1340
1575
  const result = await runCLI.apply(this, arguments)
1341
1576
 
1342
1577
  const {
1343
1578
  results: {
1344
- coverageMap,
1579
+ coverageMap: resultCoverageMap,
1345
1580
  numFailedTestSuites,
1346
1581
  numFailedTests,
1347
1582
  numRuntimeErrorTestSuites = 0,
@@ -1357,11 +1592,30 @@ function getCliWrapper (isNewJestVersion) {
1357
1592
  const mustNotFlipSuccess = hasSuiteLevelFailures || hasRunLevelFailure
1358
1593
 
1359
1594
  let testCodeCoverageLinesTotal
1595
+ let testSessionCoverageFiles
1596
+ const shouldReportTestSessionCoverage = isTiaCoverageBackfillEnabled()
1360
1597
 
1361
- if (isUserCodeCoverageEnabled) {
1598
+ if (shouldReportCodeCoverageLinesPct()) {
1362
1599
  try {
1363
- const { pct, total } = coverageMap.getCoverageSummary().lines
1364
- testCodeCoverageLinesTotal = total === 0 ? 0 : pct
1600
+ const coverageMap = resultCoverageMap || lastCoverageMap
1601
+ const coverageRootDir = lastCoverageMapRootDir ||
1602
+ repositoryRoot ||
1603
+ result.globalConfig?.rootDir ||
1604
+ process.cwd()
1605
+ if (isSuitesSkipped) {
1606
+ applySkippedCoverageToJestCoverageMap(coverageMap, coverageRootDir)
1607
+ }
1608
+ testCodeCoverageLinesTotal = getTestCoverageLinesPercentage(
1609
+ coverageMap,
1610
+ undefined,
1611
+ coverageRootDir
1612
+ )
1613
+ if (shouldReportTestSessionCoverage) {
1614
+ testSessionCoverageFiles = getExecutableFilesFromCoverage(coverageMap).map(({ filename, bitmap }) => ({
1615
+ filename: getTestSuitePath(filename, coverageRootDir),
1616
+ bitmap,
1617
+ }))
1618
+ }
1365
1619
  } catch {
1366
1620
  // ignore errors
1367
1621
  }
@@ -1383,9 +1637,7 @@ function getCliWrapper (isNewJestVersion) {
1383
1637
  for (const { testResults, testFilePath } of result.results.testResults) {
1384
1638
  const suite = getTestSuitePath(testFilePath, result.globalConfig.rootDir)
1385
1639
  for (const { fullName } of testResults) {
1386
- const name = testSuiteAbsolutePathsWithFastCheck.has(testFilePath)
1387
- ? fullName.replace(SEED_SUFFIX_RE, '')
1388
- : fullName
1640
+ const name = removeSeedSuffixFromTestName(fullName)
1389
1641
  fullNameToSuite.set(name, suite)
1390
1642
  }
1391
1643
  }
@@ -1424,10 +1676,8 @@ function getCliWrapper (isNewJestVersion) {
1424
1676
  .testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
1425
1677
  testResults.map(({ fullName: testName, status }) => (
1426
1678
  {
1427
- // Strip @fast-check/jest seed suffix so the name matches what was reported via TEST_NAME
1428
- testName: testSuiteAbsolutePathsWithFastCheck.has(testSuiteAbsolutePath)
1429
- ? testName.replace(SEED_SUFFIX_RE, '')
1430
- : testName,
1679
+ // Strip seed suffix so the name matches what was reported via TEST_NAME.
1680
+ testName: removeSeedSuffixFromTestName(testName),
1431
1681
  testSuiteAbsolutePath,
1432
1682
  status,
1433
1683
  }
@@ -1546,7 +1796,9 @@ function getCliWrapper (isNewJestVersion) {
1546
1796
  isSuitesSkipped,
1547
1797
  isSuitesSkippingEnabled,
1548
1798
  isCodeCoverageEnabled,
1799
+ isCoverageReportUploadEnabled,
1549
1800
  testCodeCoverageLinesTotal,
1801
+ testSessionCoverageFiles,
1550
1802
  numSkippedSuites,
1551
1803
  hasUnskippableSuites,
1552
1804
  hasForcedToRunSuites,
@@ -1572,7 +1824,7 @@ function getCliWrapper (isNewJestVersion) {
1572
1824
 
1573
1825
  logSessionSummary(ignoredFailuresSummary, getAttemptToFixExecutionsFromJestResults(result))
1574
1826
 
1575
- numSkippedSuites = 0
1827
+ resetSuiteSkippingRunState()
1576
1828
 
1577
1829
  return result
1578
1830
  }, {
@@ -1581,28 +1833,6 @@ function getCliWrapper (isNewJestVersion) {
1581
1833
  }
1582
1834
  }
1583
1835
 
1584
- function coverageReporterWrapper (coverageReporter) {
1585
- const CoverageReporter = coverageReporter.default ?? coverageReporter
1586
-
1587
- /**
1588
- * If ITR is active, we're running fewer tests, so of course the total code coverage is reduced.
1589
- * This calculation adds no value, so we'll skip it, as long as the user has not manually opted in to code coverage,
1590
- * in which case we'll leave it.
1591
- */
1592
- // `_addUntestedFiles` is an async function
1593
- shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => function (...args) {
1594
- if (DD_TEST_TIA_KEEP_COV_CONFIG) {
1595
- return addUntestedFiles.apply(this, args)
1596
- }
1597
- if (isCodeCoverageEnabledBecauseOfUs) {
1598
- return Promise.resolve()
1599
- }
1600
- return addUntestedFiles.apply(this, args)
1601
- })
1602
-
1603
- return coverageReporter
1604
- }
1605
-
1606
1836
  function shouldWaitForTestSuiteFinish (environment) {
1607
1837
  return isJestWorker && environment.globalConfig?.workerIdleMemoryLimit !== undefined
1608
1838
  }
@@ -1626,7 +1856,6 @@ function publishTestSuiteFinish (payload, waitForFinish) {
1626
1856
 
1627
1857
  function cleanupTestSuiteState (testSuiteAbsolutePath) {
1628
1858
  testSuiteMockedFiles.delete(testSuiteAbsolutePath)
1629
- testSuiteFastCheckUsage.delete(testSuiteAbsolutePath)
1630
1859
  testSuiteJestObjects.delete(testSuiteAbsolutePath)
1631
1860
  }
1632
1861
 
@@ -1681,6 +1910,23 @@ addHook({
1681
1910
  return sequencerPackage
1682
1911
  })
1683
1912
 
1913
+ addHook({
1914
+ name: '@jest/core',
1915
+ file: 'build/cli/index.js',
1916
+ versions: [MINIMUM_JEST_VERSION_BEFORE_30],
1917
+ }, getCliWrapper(false))
1918
+
1919
+ addHook({
1920
+ name: '@jest/core',
1921
+ versions: ['>=30.0.0'],
1922
+ }, getCliWrapper(true))
1923
+
1924
+ addHook({
1925
+ name: '@jest/core',
1926
+ file: 'build/ReporterDispatcher.js',
1927
+ versions: [MINIMUM_JEST_VERSION],
1928
+ }, reporterDispatcherWrapper)
1929
+
1684
1930
  if (DD_MAJOR < 6) {
1685
1931
  addHook({
1686
1932
  name: '@jest/reporters',
@@ -1689,29 +1935,16 @@ if (DD_MAJOR < 6) {
1689
1935
  }, coverageReporterWrapper)
1690
1936
  }
1691
1937
 
1692
- addHook({
1693
- name: '@jest/reporters',
1694
- file: 'build/CoverageReporter.js',
1695
- versions: [DD_MAJOR >= 6 ? '>=28.0.0' : '>=26.6.2'],
1696
- }, coverageReporterWrapper)
1697
-
1698
1938
  addHook({
1699
1939
  name: '@jest/reporters',
1700
1940
  versions: ['>=30.0.0'],
1701
- }, (reporters) => {
1702
- return shimmer.wrap(reporters, 'CoverageReporter', coverageReporterWrapper, { replaceGetter: true })
1703
- })
1704
-
1705
- addHook({
1706
- name: '@jest/core',
1707
- file: 'build/cli/index.js',
1708
- versions: [MINIMUM_JEST_VERSION_BEFORE_30],
1709
- }, getCliWrapper(false))
1941
+ }, reportersWrapper)
1710
1942
 
1711
1943
  addHook({
1712
- name: '@jest/core',
1713
- versions: ['>=30.0.0'],
1714
- }, getCliWrapper(true))
1944
+ name: '@jest/reporters',
1945
+ file: 'build/CoverageReporter.js',
1946
+ versions: [DD_MAJOR >= 6 ? '>=28.0.0' : '>=26.6.2'],
1947
+ }, coverageReporterWrapper)
1715
1948
 
1716
1949
  function jestAdapterWrapper (jestAdapter, jestVersion) {
1717
1950
  const adapter = jestAdapter.default ?? jestAdapter
@@ -1745,10 +1978,13 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1745
1978
  if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
1746
1979
  const root = environment.repositoryRoot || environment.rootDir
1747
1980
 
1748
- const getFilesWithPath = (files) => files.map(file => getTestSuitePath(file, root))
1749
-
1750
- const coverageFiles = getFilesWithPath(getCoveredFilenamesFromCoverage(environment.global.__coverage__))
1751
- const mockedFiles = getFilesWithPath(getMockedFiles(environment.testSuiteAbsolutePath))
1981
+ const coverageFiles = getCoveredFilesFromCoverage(environment.global.__coverage__)
1982
+ .map(file => ({
1983
+ ...file,
1984
+ filename: getTestSuitePath(file.filename, root),
1985
+ }))
1986
+ const mockedFiles = getMockedFiles(environment.testSuiteAbsolutePath)
1987
+ .map(file => getTestSuitePath(file, root))
1752
1988
 
1753
1989
  testSuiteCodeCoverageCh.publish({
1754
1990
  coverageFiles,
@@ -1828,41 +2064,48 @@ addHook({
1828
2064
  }, jestAdapterWrapper)
1829
2065
 
1830
2066
  function configureTestEnvironment (readConfigsResult) {
1831
- const { configs } = readConfigsResult
1832
- testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
1833
- // We can't directly use isCodeCoverageEnabled when reporting coverage in `jestAdapterWrapper`
1834
- // because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
1835
- for (const config of configs) {
1836
- config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
1837
- }
1838
-
2067
+ repositoryRoot = getJestRepositoryRoot(readConfigsResult)
1839
2068
  isUserCodeCoverageEnabled = !!readConfigsResult.globalConfig.collectCoverage
1840
- isCodeCoverageEnabledBecauseOfUs = isCodeCoverageEnabled && !isUserCodeCoverageEnabled
1841
-
1842
- if (readConfigsResult.globalConfig.forceExit) {
1843
- log.warn("Jest's '--forceExit' flag has been passed. This may cause loss of data.")
1844
- }
2069
+ const isCodeCoverageEnabledBecauseOfUs = shouldCollectJestCoverageForTia() && !isUserCodeCoverageEnabled
1845
2070
 
1846
2071
  if (isCodeCoverageEnabledBecauseOfUs) {
1847
- const globalConfig = {
2072
+ readConfigsResult.globalConfig = {
1848
2073
  ...readConfigsResult.globalConfig,
1849
2074
  collectCoverage: true,
2075
+ coverageReporters: ['none'],
1850
2076
  }
1851
- readConfigsResult.globalConfig = globalConfig
2077
+ readConfigsResult.configs = readConfigsResult.configs.map(config => ({
2078
+ ...config,
2079
+ coverageReporters: ['none'],
2080
+ }))
1852
2081
  }
2082
+
2083
+ // We can't directly use the parent process flags when reporting suite coverage in `jestAdapterWrapper`
2084
+ // because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`.
2085
+ const configs = readConfigsResult.configs.map(config => {
2086
+ const testEnvironmentOptions = config.testEnvironmentOptions || {}
2087
+ testEnvironmentOptions._ddRepositoryRoot = repositoryRoot
2088
+ testEnvironmentOptions._ddTestCodeCoverageEnabled = shouldReportJestSuiteCoverageForTia()
2089
+
2090
+ return {
2091
+ ...config,
2092
+ testEnvironmentOptions,
2093
+ }
2094
+ })
2095
+ readConfigsResult.configs = configs
2096
+ testSessionConfigurationCh.publish(readConfigsResult.configs.map(config => config.testEnvironmentOptions))
2097
+ repositoryRoot = getJestRepositoryRoot(readConfigsResult)
2098
+
2099
+ if (readConfigsResult.globalConfig.forceExit) {
2100
+ log.warn("Jest's '--forceExit' flag has been passed. This may cause loss of data.")
2101
+ }
2102
+
1853
2103
  if (isSuitesSkippingEnabled) {
1854
2104
  // If suite skipping is enabled, we pass `passWithNoTests` in case every test gets skipped.
1855
2105
  const globalConfig = {
1856
2106
  ...readConfigsResult.globalConfig,
1857
2107
  passWithNoTests: true,
1858
2108
  }
1859
- if (isCodeCoverageEnabledBecauseOfUs && !DD_TEST_TIA_KEEP_COV_CONFIG) {
1860
- globalConfig.coverageReporters = ['none']
1861
- readConfigsResult.configs = configs.map(config => ({
1862
- ...config,
1863
- coverageReporters: ['none'],
1864
- }))
1865
- }
1866
2109
  readConfigsResult.globalConfig = globalConfig
1867
2110
  }
1868
2111
 
@@ -1897,6 +2140,7 @@ const DD_TEST_ENVIRONMENT_OPTION_KEYS = [
1897
2140
  '_ddIsEarlyFlakeDetectionEnabled',
1898
2141
  '_ddEarlyFlakeDetectionSlowTestRetries',
1899
2142
  '_ddRepositoryRoot',
2143
+ '_ddTestCodeCoverageEnabled',
1900
2144
  '_ddIsFlakyTestRetriesEnabled',
1901
2145
  '_ddFlakyTestRetriesCount',
1902
2146
  '_ddItrSkippingEnabledTags',
@@ -2080,38 +2324,6 @@ function wrapJestGlobalsForRuntime (runtime) {
2080
2324
  })
2081
2325
  }
2082
2326
 
2083
- function recordFastCheckUsage (runtime, from, moduleName) {
2084
- if (moduleName !== '@fast-check/jest') return
2085
-
2086
- if (from) {
2087
- testSuiteAbsolutePathsWithFastCheck.add(from)
2088
- testSuiteFastCheckUsage.set(from, true)
2089
- }
2090
- if (runtime?._testPath) {
2091
- testSuiteAbsolutePathsWithFastCheck.add(runtime._testPath)
2092
- testSuiteFastCheckUsage.set(runtime._testPath, true)
2093
- }
2094
- }
2095
-
2096
- function doesTestSuiteUseFastCheck (testSuiteAbsolutePath) {
2097
- if (!testSuiteAbsolutePath) return false
2098
- if (testSuiteFastCheckUsage.has(testSuiteAbsolutePath)) {
2099
- return testSuiteFastCheckUsage.get(testSuiteAbsolutePath)
2100
- }
2101
-
2102
- try {
2103
- const usesFastCheck = readFileSync(testSuiteAbsolutePath, 'utf8').includes('@fast-check/jest')
2104
- testSuiteFastCheckUsage.set(testSuiteAbsolutePath, usesFastCheck)
2105
- if (usesFastCheck) {
2106
- testSuiteAbsolutePathsWithFastCheck.add(testSuiteAbsolutePath)
2107
- }
2108
- return usesFastCheck
2109
- } catch {
2110
- testSuiteFastCheckUsage.set(testSuiteAbsolutePath, false)
2111
- return false
2112
- }
2113
- }
2114
-
2115
2327
  function getLastLoggedReferenceError (runtime) {
2116
2328
  const loggedReferenceErrors = runtime?.loggedReferenceErrors
2117
2329
  if (!loggedReferenceErrors?.size) return
@@ -2220,8 +2432,6 @@ addHook({
2220
2432
  // To bypass jest's own require engine
2221
2433
  return requireOutsideJestRequireEngine(this, moduleName)
2222
2434
  }
2223
- // This means that `@fast-check/jest` is used in the test file.
2224
- recordFastCheckUsage(this, from, moduleName)
2225
2435
  let returnedValue
2226
2436
  try {
2227
2437
  returnedValue = requireModuleOrMock.apply(this, arguments)