dd-trace 5.55.0 → 5.57.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 (150) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +44 -2
  3. package/init.js +4 -1
  4. package/package.json +24 -23
  5. package/packages/datadog-core/src/utils/src/set.js +8 -10
  6. package/packages/datadog-esbuild/index.js +22 -0
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +43 -60
  8. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +12 -12
  9. package/packages/datadog-instrumentations/src/cucumber.js +4 -6
  10. package/packages/datadog-instrumentations/src/elasticsearch.js +16 -19
  11. package/packages/datadog-instrumentations/src/fastify.js +91 -9
  12. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +20 -5
  13. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -2
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  15. package/packages/datadog-instrumentations/src/helpers/register.js +17 -5
  16. package/packages/datadog-instrumentations/src/ioredis.js +8 -13
  17. package/packages/datadog-instrumentations/src/iovalkey.js +10 -14
  18. package/packages/datadog-instrumentations/src/jest.js +423 -325
  19. package/packages/datadog-instrumentations/src/memcached.js +17 -24
  20. package/packages/datadog-instrumentations/src/mocha/main.js +7 -6
  21. package/packages/datadog-instrumentations/src/moleculer/client.js +9 -10
  22. package/packages/datadog-instrumentations/src/moleculer/server.js +12 -13
  23. package/packages/datadog-instrumentations/src/openai.js +30 -2
  24. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  25. package/packages/datadog-instrumentations/src/prisma.js +116 -0
  26. package/packages/datadog-instrumentations/src/redis.js +32 -43
  27. package/packages/datadog-instrumentations/src/router.js +1 -1
  28. package/packages/datadog-instrumentations/src/sharedb.js +10 -16
  29. package/packages/datadog-instrumentations/src/vitest.js +4 -4
  30. package/packages/datadog-plugin-aws-sdk/src/base.js +6 -1
  31. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -4
  32. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +3 -2
  33. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -1
  34. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  35. package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
  36. package/packages/datadog-plugin-bunyan/src/index.js +2 -2
  37. package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -2
  38. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -1
  39. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -1
  40. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  41. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -1
  42. package/packages/datadog-plugin-cucumber/src/index.js +4 -2
  43. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -5
  44. package/packages/datadog-plugin-elasticsearch/src/index.js +12 -4
  45. package/packages/datadog-plugin-http/src/client.js +1 -0
  46. package/packages/datadog-plugin-http/src/server.js +2 -1
  47. package/packages/datadog-plugin-http2/src/client.js +1 -0
  48. package/packages/datadog-plugin-http2/src/server.js +1 -0
  49. package/packages/datadog-plugin-jest/src/index.js +4 -3
  50. package/packages/datadog-plugin-memcached/src/index.js +6 -2
  51. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  52. package/packages/datadog-plugin-moleculer/src/client.js +15 -9
  53. package/packages/datadog-plugin-moleculer/src/server.js +9 -5
  54. package/packages/datadog-plugin-next/src/index.js +2 -1
  55. package/packages/datadog-plugin-openai/src/tracing.js +127 -80
  56. package/packages/datadog-plugin-oracledb/src/index.js +2 -1
  57. package/packages/datadog-plugin-pino/src/index.js +2 -2
  58. package/packages/datadog-plugin-prisma/src/client.js +62 -0
  59. package/packages/datadog-plugin-prisma/src/engine.js +81 -0
  60. package/packages/datadog-plugin-prisma/src/index.js +22 -0
  61. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  62. package/packages/datadog-plugin-redis/src/index.js +9 -3
  63. package/packages/datadog-plugin-router/src/index.js +1 -0
  64. package/packages/datadog-plugin-sharedb/src/index.js +13 -5
  65. package/packages/datadog-plugin-winston/src/index.js +2 -2
  66. package/packages/dd-trace/src/appsec/channels.js +26 -21
  67. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  68. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +13 -20
  69. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
  71. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
  72. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +7 -2
  73. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +0 -1
  74. package/packages/dd-trace/src/appsec/index.js +28 -2
  75. package/packages/dd-trace/src/appsec/rasp/utils.js +0 -5
  76. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  77. package/packages/dd-trace/src/baggage.js +2 -2
  78. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -3
  79. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  80. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  81. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  82. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  83. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -6
  84. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -3
  85. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -3
  86. package/packages/dd-trace/src/config.js +334 -312
  87. package/packages/dd-trace/src/constants.js +2 -1
  88. package/packages/dd-trace/src/crashtracking/crashtracker.js +12 -14
  89. package/packages/dd-trace/src/datastreams/context.js +1 -1
  90. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  91. package/packages/dd-trace/src/datastreams/writer.js +3 -3
  92. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -3
  93. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  94. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -3
  95. package/packages/dd-trace/src/debugger/devtools_client/send.js +5 -1
  96. package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -4
  97. package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
  98. package/packages/dd-trace/src/dogstatsd.js +3 -3
  99. package/packages/dd-trace/src/exporters/agent/index.js +10 -5
  100. package/packages/dd-trace/src/exporters/agent/writer.js +4 -2
  101. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +2 -2
  102. package/packages/dd-trace/src/exporters/log/index.js +1 -1
  103. package/packages/dd-trace/src/exporters/span-stats/writer.js +2 -2
  104. package/packages/dd-trace/src/guardrails/index.js +3 -1
  105. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  106. package/packages/dd-trace/src/llmobs/index.js +11 -5
  107. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  108. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  109. package/packages/dd-trace/src/llmobs/tagger.js +13 -13
  110. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  111. package/packages/dd-trace/src/llmobs/writers/spans.js +2 -2
  112. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  113. package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -28
  114. package/packages/dd-trace/src/opentracing/span.js +1 -0
  115. package/packages/dd-trace/src/plugin_manager.js +3 -3
  116. package/packages/dd-trace/src/plugins/cache.js +2 -2
  117. package/packages/dd-trace/src/plugins/ci_plugin.js +11 -7
  118. package/packages/dd-trace/src/plugins/database.js +3 -1
  119. package/packages/dd-trace/src/plugins/index.js +1 -0
  120. package/packages/dd-trace/src/plugins/log_plugin.js +5 -1
  121. package/packages/dd-trace/src/plugins/outbound.js +8 -6
  122. package/packages/dd-trace/src/plugins/structured_log_plugin.js +9 -0
  123. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  124. package/packages/dd-trace/src/plugins/util/ci.js +83 -30
  125. package/packages/dd-trace/src/plugins/util/git.js +1 -0
  126. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +3 -2
  127. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -0
  128. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  129. package/packages/dd-trace/src/plugins/util/test.js +80 -10
  130. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  131. package/packages/dd-trace/src/profiler.js +0 -2
  132. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -3
  133. package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
  134. package/packages/dd-trace/src/profiling/ssi-heuristics.js +18 -126
  135. package/packages/dd-trace/src/proxy.js +12 -27
  136. package/packages/dd-trace/src/runtime_metrics/index.js +1 -1
  137. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +14 -45
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +2 -2
  139. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +4 -0
  140. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +2 -2
  141. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  142. package/packages/dd-trace/src/supported-configurations.json +13 -3
  143. package/packages/dd-trace/src/telemetry/telemetry.js +11 -4
  144. package/packages/dd-trace/src/tracer.js +11 -0
  145. package/packages/dd-trace/src/tracer_metadata.js +25 -0
  146. package/packages/dd-trace/src/util.js +11 -4
  147. package/version.js +3 -1
  148. package/packages/datadog-core/src/utils/src/get.js +0 -11
  149. package/packages/datadog-core/src/utils/src/has.js +0 -14
  150. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +0 -30
@@ -3,6 +3,7 @@
3
3
  const { addHook, channel } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const log = require('../../dd-trace/src/log')
6
+ const path = require('path')
6
7
  const {
7
8
  getCoveredFilenamesFromCoverage,
8
9
  JEST_WORKER_TRACE_PAYLOAD_CODE,
@@ -89,6 +90,8 @@ const originalHookFns = new WeakMap()
89
90
  const retriedTestsToNumAttempts = new Map()
90
91
  const newTestsTestStatuses = new Map()
91
92
  const attemptToFixRetriedTestsStatuses = new Map()
93
+ const wrappedWorkers = new WeakSet()
94
+ const testSuiteMockedFiles = new Map()
92
95
 
93
96
  const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
94
97
 
@@ -136,6 +139,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
136
139
  this.nameToParams = {}
137
140
  this.global._ddtrace = global._ddtrace
138
141
  this.hasSnapshotTests = undefined
142
+ this.testSuiteAbsolutePath = context.testPath
139
143
 
140
144
  this.displayName = config.projectConfig?.displayName?.name
141
145
  this.testEnvironmentOptions = getTestEnvironmentOptions(config)
@@ -290,7 +294,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
290
294
  // We'll still detect new tests, but we won't retry them.
291
295
  // TODO: do not bail out of retrying tests for the whole test suite
292
296
  if (this.getHasSnapshotTests()) {
293
- log.warn(`${retryType} is disabled for suites with snapshots`)
297
+ log.warn('%s is disabled for suites with snapshots', retryType)
294
298
  return
295
299
  }
296
300
 
@@ -298,7 +302,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
298
302
  if (this.global.test) {
299
303
  this.global.test(addRetryStringToTestName(testName, retryIndex), event.fn, event.timeout)
300
304
  } else {
301
- log.error(`${retryType} could not retry test because global.test is undefined`)
305
+ log.error('%s could not retry test because global.test is undefined', retryType)
302
306
  }
303
307
  }
304
308
  }
@@ -425,6 +429,10 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
425
429
  if (event.name === 'add_test') {
426
430
  const originalTestName = this.getTestNameFromAddTestEvent(event, state)
427
431
 
432
+ if (event.failing) {
433
+ return
434
+ }
435
+
428
436
  const isSkipped = event.mode === 'todo' || event.mode === 'skip'
429
437
  if (this.isTestManagementTestsEnabled) {
430
438
  const isAttemptToFix = this.testManagementTestsForThisSuite?.attemptToFix?.includes(originalTestName)
@@ -592,6 +600,17 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
592
600
  })
593
601
  }
594
602
  }
603
+
604
+ teardown () {
605
+ if (this._globalProxy?.propertyToValue) {
606
+ for (const [key] of this._globalProxy.propertyToValue) {
607
+ if (typeof key === 'string' && key.startsWith('_dd')) {
608
+ this._globalProxy.propertyToValue.delete(key)
609
+ }
610
+ }
611
+ }
612
+ return super.teardown()
613
+ }
595
614
  }
596
615
  }
597
616
 
@@ -647,299 +666,305 @@ function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
647
666
  }
648
667
  }
649
668
 
650
- addHook({
651
- name: '@jest/core',
652
- file: 'build/TestScheduler.js',
653
- versions: ['>=27.0.0']
654
- }, (testSchedulerPackage, frameworkVersion) => {
655
- const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
656
- const newCreateTestScheduler = async function () {
657
- if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
658
- return oldCreateTestScheduler.apply(this, arguments)
659
- }
660
- // If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
661
- const scheduler = await oldCreateTestScheduler.apply(this, arguments)
662
- shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
663
- return scheduler
664
- }
665
- testSchedulerPackage.createTestScheduler = newCreateTestScheduler
666
- return testSchedulerPackage
667
- })
669
+ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
670
+ const SearchSource = searchSourcePackage.default ?? searchSourcePackage
668
671
 
669
- addHook({
670
- name: '@jest/core',
671
- file: 'build/TestScheduler.js',
672
- versions: ['>=24.8.0 <27.0.0']
673
- }, (testSchedulerPackage, frameworkVersion) => {
674
- shimmer.wrap(
675
- testSchedulerPackage.default.prototype,
676
- 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
677
- )
678
- return testSchedulerPackage
679
- })
672
+ shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
673
+ const testPaths = await getTestPaths.apply(this, arguments)
674
+ const [{ rootDir, shard }] = arguments
680
675
 
681
- addHook({
682
- name: '@jest/test-sequencer',
683
- versions: ['>=28']
684
- }, (sequencerPackage, frameworkVersion) => {
685
- shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
686
- const shardedTests = shard.apply(this, arguments)
676
+ if (isKnownTestsEnabled) {
677
+ const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
678
+ const isFaulty =
679
+ getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
680
+ if (isFaulty) {
681
+ log.error('Early flake detection is disabled because the number of new suites is too high.')
682
+ isEarlyFlakeDetectionEnabled = false
683
+ isKnownTestsEnabled = false
684
+ const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
685
+ // Project config is shared among all tests, so we can modify it here
686
+ if (testEnvironmentOptions) {
687
+ testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
688
+ testEnvironmentOptions._ddIsKnownTestsEnabled = false
689
+ }
690
+ isEarlyFlakeDetectionFaulty = true
691
+ }
692
+ }
687
693
 
688
- if (!shardedTests.length || !isSuitesSkippingEnabled || !skippableSuites.length) {
689
- return shardedTests
694
+ if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
695
+ // If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
696
+ // The reason for this is the following:
697
+ // The tests for different shards are likely being run in different CI jobs so
698
+ // the requests to the skippable endpoint might be done at different times and their responses might be different.
699
+ // If the skippable endpoint is returning different suites and we filter the list of tests here,
700
+ // the base list of tests that is used for sharding might be different,
701
+ // causing the shards to potentially run the same suite.
702
+ return testPaths
690
703
  }
691
- const [test] = shardedTests
692
- const rootDir = test?.context?.config?.rootDir
704
+ const { tests } = testPaths
693
705
 
694
- return applySuiteSkipping(shardedTests, rootDir, frameworkVersion)
706
+ const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
707
+ return { ...testPaths, tests: suitesToRun }
695
708
  })
696
- return sequencerPackage
697
- })
698
709
 
699
- function cliWrapper (cli, jestVersion) {
700
- shimmer.wrap(cli, 'runCLI', runCLI => async function () {
701
- let onDone
702
- const configurationPromise = new Promise((resolve) => {
703
- onDone = resolve
704
- })
705
- if (!libraryConfigurationCh.hasSubscribers) {
706
- return runCLI.apply(this, arguments)
707
- }
710
+ return searchSourcePackage
711
+ }
708
712
 
709
- libraryConfigurationCh.publish({ onDone })
710
-
711
- try {
712
- const { err, libraryConfig } = await configurationPromise
713
- if (!err) {
714
- isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
715
- isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
716
- isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
717
- earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
718
- earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
719
- isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
720
- isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
721
- testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
722
- isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
723
- }
724
- } catch (err) {
725
- log.error('Jest library configuration error', err)
713
+ function getCliWrapper (isNewJestVersion) {
714
+ return function cliWrapper (cli, jestVersion) {
715
+ if (isNewJestVersion) {
716
+ cli = shimmer.wrap(
717
+ cli,
718
+ 'SearchSource',
719
+ searchSource => searchSourceWrapper(searchSource, jestVersion),
720
+ { replaceGetter: true }
721
+ )
726
722
  }
727
-
728
- if (isKnownTestsEnabled) {
729
- const knownTestsPromise = new Promise((resolve) => {
723
+ return shimmer.wrap(cli, 'runCLI', runCLI => async function () {
724
+ let onDone
725
+ const configurationPromise = new Promise((resolve) => {
730
726
  onDone = resolve
731
727
  })
728
+ if (!libraryConfigurationCh.hasSubscribers) {
729
+ return runCLI.apply(this, arguments)
730
+ }
732
731
 
733
- knownTestsCh.publish({ onDone })
732
+ libraryConfigurationCh.publish({ onDone, frameworkVersion: jestVersion })
734
733
 
735
734
  try {
736
- const { err, knownTests: receivedKnownTests } = await knownTestsPromise
737
- if (err) {
738
- // We disable EFD if there has been an error in the known tests request
739
- isEarlyFlakeDetectionEnabled = false
740
- isKnownTestsEnabled = false
741
- } else {
742
- knownTests = receivedKnownTests
735
+ const { err, libraryConfig } = await configurationPromise
736
+ if (!err) {
737
+ isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
738
+ isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
739
+ isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
740
+ earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
741
+ earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
742
+ isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
743
+ isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
744
+ testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
745
+ isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
743
746
  }
744
747
  } catch (err) {
745
- log.error('Jest known tests error', err)
748
+ log.error('Jest library configuration error', err)
746
749
  }
747
- }
748
750
 
749
- if (isSuitesSkippingEnabled) {
750
- const skippableSuitesPromise = new Promise((resolve) => {
751
- onDone = resolve
752
- })
751
+ if (isKnownTestsEnabled) {
752
+ const knownTestsPromise = new Promise((resolve) => {
753
+ onDone = resolve
754
+ })
753
755
 
754
- skippableSuitesCh.publish({ onDone })
756
+ knownTestsCh.publish({ onDone })
755
757
 
756
- try {
757
- const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
758
- if (!err) {
759
- skippableSuites = receivedSkippableSuites
758
+ try {
759
+ const { err, knownTests: receivedKnownTests } = await knownTestsPromise
760
+ if (err) {
761
+ // We disable EFD if there has been an error in the known tests request
762
+ isEarlyFlakeDetectionEnabled = false
763
+ isKnownTestsEnabled = false
764
+ } else {
765
+ knownTests = receivedKnownTests
766
+ }
767
+ } catch (err) {
768
+ log.error('Jest known tests error', err)
760
769
  }
761
- } catch (err) {
762
- log.error('Jest test-suite skippable error', err)
763
770
  }
764
- }
765
771
 
766
- if (isTestManagementTestsEnabled) {
767
- const testManagementTestsPromise = new Promise((resolve) => {
768
- onDone = resolve
769
- })
772
+ if (isSuitesSkippingEnabled) {
773
+ const skippableSuitesPromise = new Promise((resolve) => {
774
+ onDone = resolve
775
+ })
770
776
 
771
- testManagementTestsCh.publish({ onDone })
777
+ skippableSuitesCh.publish({ onDone })
772
778
 
773
- try {
774
- const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
775
- if (!err) {
776
- testManagementTests = receivedTestManagementTests
779
+ try {
780
+ const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
781
+ if (!err) {
782
+ skippableSuites = receivedSkippableSuites
783
+ }
784
+ } catch (err) {
785
+ log.error('Jest test-suite skippable error', err)
777
786
  }
778
- } catch (err) {
779
- log.error('Jest test management tests error', err)
780
787
  }
781
- }
782
788
 
783
- if (isImpactedTestsEnabled) {
784
- const impactedTestsPromise = new Promise((resolve) => {
785
- onDone = resolve
786
- })
789
+ if (isTestManagementTestsEnabled) {
790
+ const testManagementTestsPromise = new Promise((resolve) => {
791
+ onDone = resolve
792
+ })
787
793
 
788
- impactedTestsCh.publish({ onDone })
794
+ testManagementTestsCh.publish({ onDone })
789
795
 
790
- try {
791
- const { err, modifiedTests: receivedModifiedTests } = await impactedTestsPromise
792
- if (!err) {
793
- modifiedTests = receivedModifiedTests
796
+ try {
797
+ const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
798
+ if (!err) {
799
+ testManagementTests = receivedTestManagementTests
800
+ }
801
+ } catch (err) {
802
+ log.error('Jest test management tests error', err)
794
803
  }
795
- } catch (err) {
796
- log.error('Jest impacted tests error', err)
797
804
  }
798
- }
799
805
 
800
- const processArgv = process.argv.slice(2).join(' ')
801
- testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
806
+ if (isImpactedTestsEnabled) {
807
+ const impactedTestsPromise = new Promise((resolve) => {
808
+ onDone = resolve
809
+ })
802
810
 
803
- const result = await runCLI.apply(this, arguments)
811
+ impactedTestsCh.publish({ onDone })
804
812
 
805
- const {
806
- results: {
807
- success,
808
- coverageMap,
809
- numFailedTestSuites,
810
- numFailedTests,
811
- numTotalTests,
812
- numTotalTestSuites
813
+ try {
814
+ const { err, modifiedTests: receivedModifiedTests } = await impactedTestsPromise
815
+ if (!err) {
816
+ modifiedTests = receivedModifiedTests
817
+ }
818
+ } catch (err) {
819
+ log.error('Jest impacted tests error', err)
820
+ }
813
821
  }
814
- } = result
815
822
 
816
- let testCodeCoverageLinesTotal
823
+ const processArgv = process.argv.slice(2).join(' ')
824
+ testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
817
825
 
818
- if (isUserCodeCoverageEnabled) {
819
- try {
820
- const { pct, total } = coverageMap.getCoverageSummary().lines
821
- testCodeCoverageLinesTotal = total === 0 ? 0 : pct
822
- } catch {
823
- // ignore errors
824
- }
825
- }
826
- let status, error
826
+ const result = await runCLI.apply(this, arguments)
827
827
 
828
- if (success) {
829
- status = numTotalTests === 0 && numTotalTestSuites === 0 ? 'skip' : 'pass'
830
- } else {
831
- status = 'fail'
832
- error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
833
- }
834
- let timeoutId
828
+ const {
829
+ results: {
830
+ success,
831
+ coverageMap,
832
+ numFailedTestSuites,
833
+ numFailedTests,
834
+ numTotalTests,
835
+ numTotalTestSuites
836
+ }
837
+ } = result
835
838
 
836
- // Pass the resolve callback to defer it to DC listener
837
- const flushPromise = new Promise((resolve) => {
838
- onDone = () => {
839
- clearTimeout(timeoutId)
840
- resolve()
839
+ let testCodeCoverageLinesTotal
840
+
841
+ if (isUserCodeCoverageEnabled) {
842
+ try {
843
+ const { pct, total } = coverageMap.getCoverageSummary().lines
844
+ testCodeCoverageLinesTotal = total === 0 ? 0 : pct
845
+ } catch {
846
+ // ignore errors
847
+ }
841
848
  }
842
- })
849
+ let status, error
843
850
 
844
- const timeoutPromise = new Promise((resolve) => {
845
- timeoutId = setTimeout(() => {
846
- resolve('timeout')
847
- }, FLUSH_TIMEOUT).unref()
848
- })
851
+ if (success) {
852
+ status = numTotalTests === 0 && numTotalTestSuites === 0 ? 'skip' : 'pass'
853
+ } else {
854
+ status = 'fail'
855
+ error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
856
+ }
857
+ let timeoutId
849
858
 
850
- testSessionFinishCh.publish({
851
- status,
852
- isSuitesSkipped,
853
- isSuitesSkippingEnabled,
854
- isCodeCoverageEnabled,
855
- testCodeCoverageLinesTotal,
856
- numSkippedSuites,
857
- hasUnskippableSuites,
858
- hasForcedToRunSuites,
859
- error,
860
- isEarlyFlakeDetectionEnabled,
861
- isEarlyFlakeDetectionFaulty,
862
- isTestManagementTestsEnabled,
863
- onDone
864
- })
859
+ // Pass the resolve callback to defer it to DC listener
860
+ const flushPromise = new Promise((resolve) => {
861
+ onDone = () => {
862
+ clearTimeout(timeoutId)
863
+ resolve()
864
+ }
865
+ })
865
866
 
866
- const waitingResult = await Promise.race([flushPromise, timeoutPromise])
867
+ const timeoutPromise = new Promise((resolve) => {
868
+ timeoutId = setTimeout(() => {
869
+ resolve('timeout')
870
+ }, FLUSH_TIMEOUT).unref()
871
+ })
867
872
 
868
- if (waitingResult === 'timeout') {
869
- log.error('Timeout waiting for the tracer to flush')
870
- }
873
+ testSessionFinishCh.publish({
874
+ status,
875
+ isSuitesSkipped,
876
+ isSuitesSkippingEnabled,
877
+ isCodeCoverageEnabled,
878
+ testCodeCoverageLinesTotal,
879
+ numSkippedSuites,
880
+ hasUnskippableSuites,
881
+ hasForcedToRunSuites,
882
+ error,
883
+ isEarlyFlakeDetectionEnabled,
884
+ isEarlyFlakeDetectionFaulty,
885
+ isTestManagementTestsEnabled,
886
+ onDone
887
+ })
871
888
 
872
- numSkippedSuites = 0
873
-
874
- /**
875
- * If Early Flake Detection (EFD) is enabled the logic is as follows:
876
- * - If all attempts for a test are failing, the test has failed and we will let the test process fail.
877
- * - If just a single attempt passes, we will prevent the test process from failing.
878
- * The rationale behind is the following: you may still be able to block your CI pipeline by gating
879
- * on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
880
- */
881
-
882
- if (isEarlyFlakeDetectionEnabled) {
883
- let numFailedTestsToIgnore = 0
884
- for (const testStatuses of newTestsTestStatuses.values()) {
885
- const { pass, fail } = getTestStats(testStatuses)
886
- if (pass > 0) { // as long as one passes, we'll consider the test passed
887
- numFailedTestsToIgnore += fail
888
- }
889
+ const waitingResult = await Promise.race([flushPromise, timeoutPromise])
890
+
891
+ if (waitingResult === 'timeout') {
892
+ log.error('Timeout waiting for the tracer to flush')
889
893
  }
890
- // If every test that failed was an EFD retry, we'll consider the suite passed
891
- if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
892
- result.results.success = true
894
+
895
+ numSkippedSuites = 0
896
+
897
+ /**
898
+ * If Early Flake Detection (EFD) is enabled the logic is as follows:
899
+ * - If all attempts for a test are failing, the test has failed and we will let the test process fail.
900
+ * - If just a single attempt passes, we will prevent the test process from failing.
901
+ * The rationale behind is the following: you may still be able to block your CI pipeline by gating
902
+ * on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
903
+ */
904
+
905
+ if (isEarlyFlakeDetectionEnabled) {
906
+ let numFailedTestsToIgnore = 0
907
+ for (const testStatuses of newTestsTestStatuses.values()) {
908
+ const { pass, fail } = getTestStats(testStatuses)
909
+ if (pass > 0) { // as long as one passes, we'll consider the test passed
910
+ numFailedTestsToIgnore += fail
911
+ }
912
+ }
913
+ // If every test that failed was an EFD retry, we'll consider the suite passed
914
+ if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
915
+ result.results.success = true
916
+ }
893
917
  }
894
- }
895
918
 
896
- if (isTestManagementTestsEnabled) {
897
- const failedTests = result
898
- .results
899
- .testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
900
- testResults.map(({ fullName: testName, status }) => (
901
- { testName, testSuiteAbsolutePath, status }
919
+ if (isTestManagementTestsEnabled) {
920
+ const failedTests = result
921
+ .results
922
+ .testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
923
+ testResults.map(({ fullName: testName, status }) => (
924
+ { testName, testSuiteAbsolutePath, status }
925
+ ))
902
926
  ))
903
- ))
904
- .filter(({ status }) => status === 'failed')
905
-
906
- let numFailedQuarantinedTests = 0
907
- let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
908
-
909
- for (const { testName, testSuiteAbsolutePath } of failedTests) {
910
- const testSuite = getTestSuitePath(testSuiteAbsolutePath, result.globalConfig.rootDir)
911
- const originalName = removeAttemptToFixStringFromTestName(testName)
912
- const testManagementTest = testManagementTests
913
- ?.jest
914
- ?.suites
915
- ?.[testSuite]
916
- ?.tests
917
- ?.[originalName]
918
- ?.properties
919
- // This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
920
- if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
921
- numFailedQuarantinedOrDisabledAttemptedToFixTests++
922
- } else if (testManagementTest?.quarantined) {
923
- numFailedQuarantinedTests++
927
+ .filter(({ status }) => status === 'failed')
928
+
929
+ let numFailedQuarantinedTests = 0
930
+ let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
931
+
932
+ for (const { testName, testSuiteAbsolutePath } of failedTests) {
933
+ const testSuite = getTestSuitePath(testSuiteAbsolutePath, result.globalConfig.rootDir)
934
+ const originalName = removeAttemptToFixStringFromTestName(testName)
935
+ const testManagementTest = testManagementTests
936
+ ?.jest
937
+ ?.suites
938
+ ?.[testSuite]
939
+ ?.tests
940
+ ?.[originalName]
941
+ ?.properties
942
+ // This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
943
+ if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
944
+ numFailedQuarantinedOrDisabledAttemptedToFixTests++
945
+ } else if (testManagementTest?.quarantined) {
946
+ numFailedQuarantinedTests++
947
+ }
924
948
  }
925
- }
926
949
 
927
- // If every test that failed was quarantined, we'll consider the suite passed
928
- // Note that if a test is attempted to fix,
929
- // it's considered quarantined both if it's disabled and if it's quarantined (it'll run but its status is ignored)
930
- if (
931
- (numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
932
- result.results.numFailedTests ===
933
- numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
934
- ) {
935
- result.results.success = true
950
+ // If every test that failed was quarantined, we'll consider the suite passed
951
+ // Note that if a test is attempted to fix,
952
+ // it's considered quarantined both if it's disabled and if it's quarantined
953
+ // (it'll run but its status is ignored)
954
+ if (
955
+ (numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
956
+ result.results.numFailedTests ===
957
+ numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
958
+ ) {
959
+ result.results.success = true
960
+ }
936
961
  }
937
- }
938
962
 
939
- return result
940
- })
941
-
942
- return cli
963
+ return result
964
+ }, {
965
+ replaceGetter: true
966
+ })
967
+ }
943
968
  }
944
969
 
945
970
  function coverageReporterWrapper (coverageReporter) {
@@ -963,6 +988,55 @@ function coverageReporterWrapper (coverageReporter) {
963
988
  return coverageReporter
964
989
  }
965
990
 
991
+ addHook({
992
+ name: '@jest/core',
993
+ file: 'build/TestScheduler.js',
994
+ versions: ['>=27.0.0']
995
+ }, (testSchedulerPackage, frameworkVersion) => {
996
+ const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
997
+ const newCreateTestScheduler = async function () {
998
+ if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
999
+ return oldCreateTestScheduler.apply(this, arguments)
1000
+ }
1001
+ // If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
1002
+ const scheduler = await oldCreateTestScheduler.apply(this, arguments)
1003
+ shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
1004
+ return scheduler
1005
+ }
1006
+ testSchedulerPackage.createTestScheduler = newCreateTestScheduler
1007
+ return testSchedulerPackage
1008
+ })
1009
+
1010
+ addHook({
1011
+ name: '@jest/core',
1012
+ file: 'build/TestScheduler.js',
1013
+ versions: ['>=24.8.0 <27.0.0']
1014
+ }, (testSchedulerPackage, frameworkVersion) => {
1015
+ shimmer.wrap(
1016
+ testSchedulerPackage.default.prototype,
1017
+ 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
1018
+ )
1019
+ return testSchedulerPackage
1020
+ })
1021
+
1022
+ addHook({
1023
+ name: '@jest/test-sequencer',
1024
+ versions: ['>=28']
1025
+ }, (sequencerPackage, frameworkVersion) => {
1026
+ shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
1027
+ const shardedTests = shard.apply(this, arguments)
1028
+
1029
+ if (!shardedTests.length || !isSuitesSkippingEnabled || !skippableSuites.length) {
1030
+ return shardedTests
1031
+ }
1032
+ const [test] = shardedTests
1033
+ const rootDir = test?.context?.config?.rootDir
1034
+
1035
+ return applySuiteSkipping(shardedTests, rootDir, frameworkVersion)
1036
+ })
1037
+ return sequencerPackage
1038
+ })
1039
+
966
1040
  addHook({
967
1041
  name: '@jest/reporters',
968
1042
  file: 'build/coverage_reporter.js',
@@ -975,11 +1049,23 @@ addHook({
975
1049
  versions: ['>=26.6.2']
976
1050
  }, coverageReporterWrapper)
977
1051
 
1052
+ addHook({
1053
+ name: '@jest/reporters',
1054
+ versions: ['>=30.0.0']
1055
+ }, (reporters) => {
1056
+ return shimmer.wrap(reporters, 'CoverageReporter', coverageReporterWrapper, { replaceGetter: true })
1057
+ })
1058
+
978
1059
  addHook({
979
1060
  name: '@jest/core',
980
1061
  file: 'build/cli/index.js',
981
- versions: ['>=24.8.0']
982
- }, cliWrapper)
1062
+ versions: ['>=24.8.0 <30.0.0']
1063
+ }, getCliWrapper(false))
1064
+
1065
+ addHook({
1066
+ name: '@jest/core',
1067
+ versions: ['>=30.0.0']
1068
+ }, getCliWrapper(true))
983
1069
 
984
1070
  function jestAdapterWrapper (jestAdapter, jestVersion) {
985
1071
  const adapter = jestAdapter.default ?? jestAdapter
@@ -1012,10 +1098,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1012
1098
  if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
1013
1099
  const root = environment.repositoryRoot || environment.rootDir
1014
1100
 
1015
- const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
1016
- .map(filename => getTestSuitePath(filename, root))
1101
+ const getFilesWithPath = (files) => files.map(file => getTestSuitePath(file, root))
1102
+
1103
+ const coverageFiles = getFilesWithPath(getCoveredFilenamesFromCoverage(environment.global.__coverage__))
1104
+ const mockedFiles = getFilesWithPath(testSuiteMockedFiles.get(environment.testSuiteAbsolutePath) || [])
1017
1105
 
1018
- testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
1106
+ testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile, mockedFiles })
1019
1107
  }
1020
1108
  testSuiteFinishCh.publish({ status, errorMessage })
1021
1109
  return suiteResults
@@ -1033,6 +1121,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1033
1121
  return jestAdapter
1034
1122
  }
1035
1123
 
1124
+ addHook({
1125
+ name: 'jest-circus',
1126
+ file: 'build/runner.js',
1127
+ versions: ['>=30.0.0']
1128
+ }, jestAdapterWrapper)
1129
+
1036
1130
  addHook({
1037
1131
  name: 'jest-circus',
1038
1132
  file: 'build/legacy-code-todo-rewrite/jestAdapter.js',
@@ -1077,21 +1171,19 @@ function configureTestEnvironment (readConfigsResult) {
1077
1171
  }
1078
1172
 
1079
1173
  function jestConfigAsyncWrapper (jestConfig) {
1080
- shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
1174
+ return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
1081
1175
  const readConfigsResult = await readConfigs.apply(this, arguments)
1082
1176
  configureTestEnvironment(readConfigsResult)
1083
1177
  return readConfigsResult
1084
1178
  })
1085
- return jestConfig
1086
1179
  }
1087
1180
 
1088
1181
  function jestConfigSyncWrapper (jestConfig) {
1089
- shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
1182
+ return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
1090
1183
  const readConfigsResult = readConfigs.apply(this, arguments)
1091
1184
  configureTestEnvironment(readConfigsResult)
1092
1185
  return readConfigsResult
1093
1186
  })
1094
- return jestConfig
1095
1187
  }
1096
1188
 
1097
1189
  addHook({
@@ -1142,51 +1234,9 @@ addHook({
1142
1234
  */
1143
1235
  addHook({
1144
1236
  name: '@jest/core',
1145
- versions: ['>=24.8.0'],
1237
+ versions: ['>=24.8.0 <30.0.0'],
1146
1238
  file: 'build/SearchSource.js'
1147
- }, (searchSourcePackage, frameworkVersion) => {
1148
- const SearchSource = searchSourcePackage.default ?? searchSourcePackage
1149
-
1150
- shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
1151
- const testPaths = await getTestPaths.apply(this, arguments)
1152
- const [{ rootDir, shard }] = arguments
1153
-
1154
- if (isKnownTestsEnabled) {
1155
- const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
1156
- const isFaulty =
1157
- getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
1158
- if (isFaulty) {
1159
- log.error('Early flake detection is disabled because the number of new suites is too high.')
1160
- isEarlyFlakeDetectionEnabled = false
1161
- isKnownTestsEnabled = false
1162
- const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
1163
- // Project config is shared among all tests, so we can modify it here
1164
- if (testEnvironmentOptions) {
1165
- testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
1166
- testEnvironmentOptions._ddIsKnownTestsEnabled = false
1167
- }
1168
- isEarlyFlakeDetectionFaulty = true
1169
- }
1170
- }
1171
-
1172
- if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
1173
- // If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
1174
- // The reason for this is the following:
1175
- // The tests for different shards are likely being run in different CI jobs so
1176
- // the requests to the skippable endpoint might be done at different times and their responses might be different.
1177
- // If the skippable endpoint is returning different suites and we filter the list of tests here,
1178
- // the base list of tests that is used for sharding might be different,
1179
- // causing the shards to potentially run the same suite.
1180
- return testPaths
1181
- }
1182
- const { tests } = testPaths
1183
-
1184
- const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
1185
- return { ...testPaths, tests: suitesToRun }
1186
- })
1187
-
1188
- return searchSourcePackage
1189
- })
1239
+ }, searchSourceWrapper)
1190
1240
 
1191
1241
  // from 25.1.0 on, readConfigs becomes async
1192
1242
  addHook({
@@ -1222,6 +1272,23 @@ addHook({
1222
1272
  }, (runtimePackage) => {
1223
1273
  const Runtime = runtimePackage.default ?? runtimePackage
1224
1274
 
1275
+ shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
1276
+ const result = _createJestObjectFor.apply(this, arguments)
1277
+ const suiteFilePath = this._testPath
1278
+
1279
+ shimmer.wrap(result, 'mock', mock => function (moduleName) {
1280
+ if (suiteFilePath) {
1281
+ const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
1282
+ const suiteDir = path.dirname(suiteFilePath)
1283
+ const mockPath = path.resolve(suiteDir, moduleName)
1284
+ existingMockedFiles.push(mockPath)
1285
+ testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
1286
+ }
1287
+ return mock.apply(this, arguments)
1288
+ })
1289
+ return result
1290
+ })
1291
+
1225
1292
  shimmer.wrap(Runtime.prototype, 'requireModuleOrMock', requireModuleOrMock => function (from, moduleName) {
1226
1293
  // TODO: do this for every library that we instrument
1227
1294
  if (shouldBypassJestRequireEngine(moduleName)) {
@@ -1234,19 +1301,27 @@ addHook({
1234
1301
  return runtimePackage
1235
1302
  })
1236
1303
 
1237
- /*
1238
- * This hook does three things:
1239
- * - Pass known tests to the workers.
1240
- * - Pass test management tests to the workers.
1241
- * - Receive trace, coverage and logs payloads from the workers.
1242
- */
1243
- addHook({
1244
- name: 'jest-worker',
1245
- versions: ['>=24.9.0'],
1246
- file: 'build/workers/ChildProcessWorker.js'
1247
- }, (childProcessWorker) => {
1248
- const ChildProcessWorker = childProcessWorker.default
1249
- shimmer.wrap(ChildProcessWorker.prototype, 'send', send => function (request) {
1304
+ function onMessageWrapper (onMessage) {
1305
+ return function () {
1306
+ const [code, data] = arguments[0]
1307
+ if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
1308
+ workerReportTraceCh.publish(data)
1309
+ return
1310
+ }
1311
+ if (code === JEST_WORKER_COVERAGE_PAYLOAD_CODE) { // datadog coverage payload
1312
+ workerReportCoverageCh.publish(data)
1313
+ return
1314
+ }
1315
+ if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
1316
+ workerReportLogsCh.publish(data)
1317
+ return
1318
+ }
1319
+ return onMessage.apply(this, arguments)
1320
+ }
1321
+ }
1322
+
1323
+ function sendWrapper (send) {
1324
+ return function (request) {
1250
1325
  if (!isKnownTestsEnabled && !isTestManagementTestsEnabled && !isImpactedTestsEnabled) {
1251
1326
  return send.apply(this, arguments)
1252
1327
  }
@@ -1284,24 +1359,47 @@ addHook({
1284
1359
  }
1285
1360
  }
1286
1361
  }
1287
-
1288
1362
  return send.apply(this, arguments)
1289
- })
1290
- shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', _onMessage => function () {
1291
- const [code, data] = arguments[0]
1292
- if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
1293
- workerReportTraceCh.publish(data)
1294
- return
1295
- }
1296
- if (code === JEST_WORKER_COVERAGE_PAYLOAD_CODE) { // datadog coverage payload
1297
- workerReportCoverageCh.publish(data)
1298
- return
1299
- }
1300
- if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
1301
- workerReportLogsCh.publish(data)
1302
- return
1303
- }
1304
- return _onMessage.apply(this, arguments)
1305
- })
1363
+ }
1364
+ }
1365
+
1366
+ function enqueueWrapper (enqueue) {
1367
+ return function () {
1368
+ shimmer.wrap(arguments[0], 'onStart', onStart => function (worker) {
1369
+ if (worker && !wrappedWorkers.has(worker)) {
1370
+ shimmer.wrap(worker._child, 'send', sendWrapper)
1371
+ shimmer.wrap(worker, '_onMessage', onMessageWrapper)
1372
+ worker._child.on('message', worker._onMessage.bind(worker))
1373
+ wrappedWorkers.add(worker)
1374
+ }
1375
+ return onStart.apply(this, arguments)
1376
+ })
1377
+ return enqueue.apply(this, arguments)
1378
+ }
1379
+ }
1380
+
1381
+ /*
1382
+ * This hook does three things:
1383
+ * - Pass known tests to the workers.
1384
+ * - Pass test management tests to the workers.
1385
+ * - Receive trace, coverage and logs payloads from the workers.
1386
+ */
1387
+ addHook({
1388
+ name: 'jest-worker',
1389
+ versions: ['>=24.9.0 <30.0.0'],
1390
+ file: 'build/workers/ChildProcessWorker.js'
1391
+ }, (childProcessWorker) => {
1392
+ const ChildProcessWorker = childProcessWorker.default
1393
+ shimmer.wrap(ChildProcessWorker.prototype, 'send', sendWrapper)
1394
+ shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', onMessageWrapper)
1306
1395
  return childProcessWorker
1307
1396
  })
1397
+
1398
+ addHook({
1399
+ name: 'jest-worker',
1400
+ versions: ['>=30.0.0']
1401
+ }, (jestWorkerPackage) => {
1402
+ shimmer.wrap(jestWorkerPackage.FifoQueue.prototype, 'enqueue', enqueueWrapper)
1403
+ shimmer.wrap(jestWorkerPackage.PriorityQueue.prototype, 'enqueue', enqueueWrapper)
1404
+ return jestWorkerPackage
1405
+ })