dd-trace 5.54.0 → 5.56.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 (191) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/ci/cypress/plugin.js +8 -0
  3. package/ci/cypress/polyfills.js +23 -0
  4. package/ci/init.js +8 -7
  5. package/initialize.mjs +2 -2
  6. package/package.json +10 -9
  7. package/packages/datadog-code-origin/index.js +22 -4
  8. package/packages/datadog-core/src/utils/src/kebabcase.js +3 -3
  9. package/packages/datadog-core/src/utils/src/set.js +8 -10
  10. package/packages/datadog-instrumentations/src/cassandra-driver.js +5 -6
  11. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +2 -3
  12. package/packages/datadog-instrumentations/src/cookie-parser.js +1 -1
  13. package/packages/datadog-instrumentations/src/couchbase.js +3 -6
  14. package/packages/datadog-instrumentations/src/cucumber.js +21 -28
  15. package/packages/datadog-instrumentations/src/dns.js +4 -4
  16. package/packages/datadog-instrumentations/src/elasticsearch.js +9 -10
  17. package/packages/datadog-instrumentations/src/fastify.js +7 -9
  18. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +14 -16
  19. package/packages/datadog-instrumentations/src/hapi.js +10 -11
  20. package/packages/datadog-instrumentations/src/helpers/fetch.js +4 -5
  21. package/packages/datadog-instrumentations/src/helpers/hook.js +1 -2
  22. package/packages/datadog-instrumentations/src/helpers/register.js +6 -5
  23. package/packages/datadog-instrumentations/src/jest.js +421 -376
  24. package/packages/datadog-instrumentations/src/koa.js +2 -3
  25. package/packages/datadog-instrumentations/src/mariadb.js +11 -4
  26. package/packages/datadog-instrumentations/src/mocha/main.js +79 -75
  27. package/packages/datadog-instrumentations/src/mocha.js +3 -1
  28. package/packages/datadog-instrumentations/src/mysql.js +11 -2
  29. package/packages/datadog-instrumentations/src/nyc.js +2 -1
  30. package/packages/datadog-instrumentations/src/openai.js +2 -2
  31. package/packages/datadog-instrumentations/src/otel-sdk-trace.js +4 -3
  32. package/packages/datadog-instrumentations/src/pg.js +2 -3
  33. package/packages/datadog-instrumentations/src/playwright.js +19 -22
  34. package/packages/datadog-instrumentations/src/protobufjs.js +3 -4
  35. package/packages/datadog-instrumentations/src/redis.js +1 -1
  36. package/packages/datadog-instrumentations/src/restify.js +9 -13
  37. package/packages/datadog-instrumentations/src/router.js +12 -11
  38. package/packages/datadog-instrumentations/src/tedious.js +1 -2
  39. package/packages/datadog-instrumentations/src/vitest.js +15 -29
  40. package/packages/datadog-plugin-avsc/src/schema_iterator.js +12 -12
  41. package/packages/datadog-plugin-aws-sdk/src/base.js +12 -8
  42. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +3 -5
  43. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +12 -20
  44. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -5
  45. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +3 -5
  46. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +3 -5
  47. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +3 -5
  48. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  49. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -10
  50. package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
  51. package/packages/datadog-plugin-cucumber/src/index.js +3 -2
  52. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -1
  53. package/packages/datadog-plugin-dd-trace-api/src/index.js +2 -1
  54. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  55. package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +1 -1
  56. package/packages/datadog-plugin-graphql/src/index.js +3 -2
  57. package/packages/datadog-plugin-graphql/src/resolve.js +17 -10
  58. package/packages/datadog-plugin-http/src/client.js +5 -6
  59. package/packages/datadog-plugin-http2/src/client.js +7 -8
  60. package/packages/datadog-plugin-jest/src/index.js +3 -2
  61. package/packages/datadog-plugin-mocha/src/index.js +6 -1
  62. package/packages/datadog-plugin-mongodb-core/src/index.js +2 -1
  63. package/packages/datadog-plugin-mysql/src/index.js +11 -0
  64. package/packages/datadog-plugin-next/src/index.js +1 -1
  65. package/packages/datadog-plugin-openai/src/tracing.js +2 -4
  66. package/packages/datadog-plugin-oracledb/src/index.js +2 -1
  67. package/packages/datadog-plugin-playwright/src/index.js +3 -2
  68. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +8 -9
  69. package/packages/datadog-plugin-redis/src/index.js +1 -3
  70. package/packages/datadog-plugin-vitest/src/index.js +5 -4
  71. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +0 -1
  72. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +0 -1
  73. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +0 -1
  74. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -1
  75. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +1 -2
  76. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  77. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +12 -13
  78. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
  79. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
  80. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -3
  81. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -1
  82. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +1 -1
  83. package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +1 -2
  84. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +10 -11
  85. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +0 -4
  86. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +0 -1
  87. package/packages/dd-trace/src/appsec/index.js +16 -5
  88. package/packages/dd-trace/src/appsec/reporter.js +11 -11
  89. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  90. package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -3
  91. package/packages/dd-trace/src/appsec/telemetry/index.js +31 -1
  92. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +6 -2
  93. package/packages/dd-trace/src/azure_metadata.js +8 -3
  94. package/packages/dd-trace/src/baggage.js +2 -2
  95. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +8 -7
  96. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -1
  97. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -1
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -1
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +4 -3
  101. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +7 -6
  102. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
  103. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -3
  104. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -3
  105. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -1
  106. package/packages/dd-trace/src/config-helper.js +89 -0
  107. package/packages/dd-trace/src/config.js +120 -115
  108. package/packages/dd-trace/src/config_stable.js +7 -4
  109. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  110. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +6 -6
  111. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +1 -2
  112. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -2
  113. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -1
  114. package/packages/dd-trace/src/debugger/devtools_client/send.js +8 -3
  115. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -2
  116. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +3 -4
  117. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +1 -1
  118. package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
  119. package/packages/dd-trace/src/debugger/index.js +1 -0
  120. package/packages/dd-trace/src/dogstatsd.js +2 -2
  121. package/packages/dd-trace/src/encode/0.4.js +5 -2
  122. package/packages/dd-trace/src/encode/0.5.js +3 -5
  123. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +5 -5
  124. package/packages/dd-trace/src/exporter.js +2 -1
  125. package/packages/dd-trace/src/exporters/agent/writer.js +3 -1
  126. package/packages/dd-trace/src/exporters/common/docker.js +3 -2
  127. package/packages/dd-trace/src/exporters/common/request.js +4 -1
  128. package/packages/dd-trace/src/exporters/common/util.js +3 -1
  129. package/packages/dd-trace/src/id.js +3 -3
  130. package/packages/dd-trace/src/index.js +4 -3
  131. package/packages/dd-trace/src/lambda/handler.js +2 -1
  132. package/packages/dd-trace/src/lambda/index.js +2 -1
  133. package/packages/dd-trace/src/lambda/runtime/patch.js +3 -2
  134. package/packages/dd-trace/src/lambda/runtime/ritm.js +3 -2
  135. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  136. package/packages/dd-trace/src/llmobs/index.js +21 -5
  137. package/packages/dd-trace/src/llmobs/noop.js +18 -20
  138. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +11 -13
  139. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -2
  140. package/packages/dd-trace/src/llmobs/sdk.js +2 -1
  141. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  142. package/packages/dd-trace/src/llmobs/tagger.js +19 -6
  143. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  144. package/packages/dd-trace/src/log/index.js +5 -4
  145. package/packages/dd-trace/src/log/writer.js +1 -2
  146. package/packages/dd-trace/src/msgpack/encoder.js +3 -3
  147. package/packages/dd-trace/src/noop/span.js +1 -1
  148. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  149. package/packages/dd-trace/src/opentracing/propagation/log.js +4 -5
  150. package/packages/dd-trace/src/opentracing/propagation/text_map.js +35 -42
  151. package/packages/dd-trace/src/opentracing/span.js +7 -6
  152. package/packages/dd-trace/src/payload-tagging/config/index.js +17 -21
  153. package/packages/dd-trace/src/plugin_manager.js +4 -3
  154. package/packages/dd-trace/src/plugins/ci_plugin.js +25 -1
  155. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  156. package/packages/dd-trace/src/plugins/util/ci.js +7 -7
  157. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  158. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  159. package/packages/dd-trace/src/plugins/util/stacktrace.js +8 -1
  160. package/packages/dd-trace/src/plugins/util/test.js +4 -3
  161. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -1
  162. package/packages/dd-trace/src/plugins/util/web.js +3 -4
  163. package/packages/dd-trace/src/priority_sampler.js +46 -35
  164. package/packages/dd-trace/src/profiling/config.js +12 -32
  165. package/packages/dd-trace/src/profiling/exporter_cli.js +20 -20
  166. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
  167. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +2 -1
  168. package/packages/dd-trace/src/profiling/index.js +2 -1
  169. package/packages/dd-trace/src/profiling/profiler.js +7 -4
  170. package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
  171. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +3 -1
  172. package/packages/dd-trace/src/profiling/tagger.js +22 -12
  173. package/packages/dd-trace/src/proxy.js +2 -1
  174. package/packages/dd-trace/src/ritm.js +4 -4
  175. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -2
  176. package/packages/dd-trace/src/sampler.js +10 -2
  177. package/packages/dd-trace/src/serverless.js +11 -4
  178. package/packages/dd-trace/src/span_processor.js +2 -1
  179. package/packages/dd-trace/src/standalone/tracesource.js +1 -2
  180. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +1 -2
  181. package/packages/dd-trace/src/startup-log.js +5 -17
  182. package/packages/dd-trace/src/supported-configurations.json +440 -0
  183. package/packages/dd-trace/src/telemetry/dependencies.js +62 -57
  184. package/packages/dd-trace/src/telemetry/send-data.js +7 -6
  185. package/packages/dd-trace/src/telemetry/telemetry.js +16 -26
  186. package/packages/dd-trace/src/tracer.js +3 -7
  187. package/packages/dd-trace/src/util.js +0 -5
  188. package/packages/datadog-core/src/utils/src/get.js +0 -11
  189. package/packages/datadog-core/src/utils/src/has.js +0 -14
  190. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +0 -120
  191. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +0 -20
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { addHook, channel, AsyncResource } = require('./helpers/instrument')
3
+ const { addHook, channel } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
  const log = require('../../dd-trace/src/log')
6
6
  const {
@@ -83,14 +83,13 @@ let testManagementAttemptToFixRetries = 0
83
83
  let isImpactedTestsEnabled = false
84
84
  let modifiedTests = {}
85
85
 
86
- const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
87
-
88
86
  const testContexts = new WeakMap()
89
87
  const originalTestFns = new WeakMap()
90
88
  const originalHookFns = new WeakMap()
91
89
  const retriedTestsToNumAttempts = new Map()
92
90
  const newTestsTestStatuses = new Map()
93
91
  const attemptToFixRetriedTestsStatuses = new Map()
92
+ const wrappedWorkers = new WeakSet()
94
93
 
95
94
  const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
96
95
 
@@ -427,6 +426,10 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
427
426
  if (event.name === 'add_test') {
428
427
  const originalTestName = this.getTestNameFromAddTestEvent(event, state)
429
428
 
429
+ if (event.failing) {
430
+ return
431
+ }
432
+
430
433
  const isSkipped = event.mode === 'todo' || event.mode === 'skip'
431
434
  if (this.isTestManagementTestsEnabled) {
432
435
  const isAttemptToFix = this.testManagementTestsForThisSuite?.attemptToFix?.includes(originalTestName)
@@ -581,22 +584,30 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
581
584
  }
582
585
  }
583
586
  if (event.name === 'test_skip' || event.name === 'test_todo') {
584
- const asyncResource = new AsyncResource('bound-anonymous-fn')
585
- asyncResource.runInAsyncScope(() => {
586
- testSkippedCh.publish({
587
- test: {
588
- name: getJestTestName(event.test),
589
- suite: this.testSuite,
590
- testSourceFile: this.testSourceFile,
591
- displayName: this.displayName,
592
- frameworkVersion: jestVersion,
593
- testStartLine: getTestLineStart(event.test.asyncError, this.testSuite)
594
- },
595
- isDisabled: this.testManagementTestsForThisSuite?.disabled?.includes(getJestTestName(event.test))
596
- })
587
+ testSkippedCh.publish({
588
+ test: {
589
+ name: getJestTestName(event.test),
590
+ suite: this.testSuite,
591
+ testSourceFile: this.testSourceFile,
592
+ displayName: this.displayName,
593
+ frameworkVersion: jestVersion,
594
+ testStartLine: getTestLineStart(event.test.asyncError, this.testSuite)
595
+ },
596
+ isDisabled: this.testManagementTestsForThisSuite?.disabled?.includes(getJestTestName(event.test))
597
597
  })
598
598
  }
599
599
  }
600
+
601
+ teardown () {
602
+ if (this._globalProxy?.propertyToValue) {
603
+ for (const [key] of this._globalProxy.propertyToValue) {
604
+ if (typeof key === 'string' && key.startsWith('_dd')) {
605
+ this._globalProxy.propertyToValue.delete(key)
606
+ }
607
+ }
608
+ }
609
+ return super.teardown()
610
+ }
600
611
  }
601
612
  }
602
613
 
@@ -652,219 +663,210 @@ function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
652
663
  }
653
664
  }
654
665
 
655
- addHook({
656
- name: '@jest/core',
657
- file: 'build/TestScheduler.js',
658
- versions: ['>=27.0.0']
659
- }, (testSchedulerPackage, frameworkVersion) => {
660
- const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
661
- const newCreateTestScheduler = async function () {
662
- if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
663
- return oldCreateTestScheduler.apply(this, arguments)
664
- }
665
- // If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
666
- const scheduler = await oldCreateTestScheduler.apply(this, arguments)
667
- shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
668
- return scheduler
669
- }
670
- testSchedulerPackage.createTestScheduler = newCreateTestScheduler
671
- return testSchedulerPackage
672
- })
666
+ function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
667
+ const SearchSource = searchSourcePackage.default ?? searchSourcePackage
673
668
 
674
- addHook({
675
- name: '@jest/core',
676
- file: 'build/TestScheduler.js',
677
- versions: ['>=24.8.0 <27.0.0']
678
- }, (testSchedulerPackage, frameworkVersion) => {
679
- shimmer.wrap(
680
- testSchedulerPackage.default.prototype,
681
- 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
682
- )
683
- return testSchedulerPackage
684
- })
669
+ shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
670
+ const testPaths = await getTestPaths.apply(this, arguments)
671
+ const [{ rootDir, shard }] = arguments
685
672
 
686
- addHook({
687
- name: '@jest/test-sequencer',
688
- versions: ['>=28']
689
- }, (sequencerPackage, frameworkVersion) => {
690
- shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
691
- const shardedTests = shard.apply(this, arguments)
673
+ if (isKnownTestsEnabled) {
674
+ const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
675
+ const isFaulty =
676
+ getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
677
+ if (isFaulty) {
678
+ log.error('Early flake detection is disabled because the number of new suites is too high.')
679
+ isEarlyFlakeDetectionEnabled = false
680
+ isKnownTestsEnabled = false
681
+ const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
682
+ // Project config is shared among all tests, so we can modify it here
683
+ if (testEnvironmentOptions) {
684
+ testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
685
+ testEnvironmentOptions._ddIsKnownTestsEnabled = false
686
+ }
687
+ isEarlyFlakeDetectionFaulty = true
688
+ }
689
+ }
692
690
 
693
- if (!shardedTests.length || !isSuitesSkippingEnabled || !skippableSuites.length) {
694
- return shardedTests
691
+ if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
692
+ // If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
693
+ // The reason for this is the following:
694
+ // The tests for different shards are likely being run in different CI jobs so
695
+ // the requests to the skippable endpoint might be done at different times and their responses might be different.
696
+ // If the skippable endpoint is returning different suites and we filter the list of tests here,
697
+ // the base list of tests that is used for sharding might be different,
698
+ // causing the shards to potentially run the same suite.
699
+ return testPaths
695
700
  }
696
- const [test] = shardedTests
697
- const rootDir = test?.context?.config?.rootDir
701
+ const { tests } = testPaths
698
702
 
699
- return applySuiteSkipping(shardedTests, rootDir, frameworkVersion)
703
+ const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
704
+ return { ...testPaths, tests: suitesToRun }
700
705
  })
701
- return sequencerPackage
702
- })
703
706
 
704
- function cliWrapper (cli, jestVersion) {
705
- shimmer.wrap(cli, 'runCLI', runCLI => async function () {
706
- let onDone
707
- const configurationPromise = new Promise((resolve) => {
708
- onDone = resolve
709
- })
710
- if (!libraryConfigurationCh.hasSubscribers) {
711
- return runCLI.apply(this, arguments)
707
+ return searchSourcePackage
708
+ }
709
+
710
+ function getCliWrapper (isNewJestVersion) {
711
+ return function cliWrapper (cli, jestVersion) {
712
+ if (isNewJestVersion) {
713
+ cli = shimmer.wrap(
714
+ cli,
715
+ 'SearchSource',
716
+ searchSource => searchSourceWrapper(searchSource, jestVersion),
717
+ { replaceGetter: true }
718
+ )
712
719
  }
720
+ return shimmer.wrap(cli, 'runCLI', runCLI => async function () {
721
+ let onDone
722
+ const configurationPromise = new Promise((resolve) => {
723
+ onDone = resolve
724
+ })
725
+ if (!libraryConfigurationCh.hasSubscribers) {
726
+ return runCLI.apply(this, arguments)
727
+ }
713
728
 
714
- sessionAsyncResource.runInAsyncScope(() => {
715
729
  libraryConfigurationCh.publish({ onDone })
716
- })
717
730
 
718
- try {
719
- const { err, libraryConfig } = await configurationPromise
720
- if (!err) {
721
- isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
722
- isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
723
- isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
724
- earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
725
- earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
726
- isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
727
- isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
728
- testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
729
- isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
731
+ try {
732
+ const { err, libraryConfig } = await configurationPromise
733
+ if (!err) {
734
+ isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
735
+ isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
736
+ isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
737
+ earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
738
+ earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
739
+ isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
740
+ isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
741
+ testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
742
+ isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
743
+ }
744
+ } catch (err) {
745
+ log.error('Jest library configuration error', err)
730
746
  }
731
- } catch (err) {
732
- log.error('Jest library configuration error', err)
733
- }
734
747
 
735
- if (isKnownTestsEnabled) {
736
- const knownTestsPromise = new Promise((resolve) => {
737
- onDone = resolve
738
- })
748
+ if (isKnownTestsEnabled) {
749
+ const knownTestsPromise = new Promise((resolve) => {
750
+ onDone = resolve
751
+ })
739
752
 
740
- sessionAsyncResource.runInAsyncScope(() => {
741
753
  knownTestsCh.publish({ onDone })
742
- })
743
754
 
744
- try {
745
- const { err, knownTests: receivedKnownTests } = await knownTestsPromise
746
- if (err) {
747
- // We disable EFD if there has been an error in the known tests request
748
- isEarlyFlakeDetectionEnabled = false
749
- isKnownTestsEnabled = false
750
- } else {
751
- knownTests = receivedKnownTests
755
+ try {
756
+ const { err, knownTests: receivedKnownTests } = await knownTestsPromise
757
+ if (err) {
758
+ // We disable EFD if there has been an error in the known tests request
759
+ isEarlyFlakeDetectionEnabled = false
760
+ isKnownTestsEnabled = false
761
+ } else {
762
+ knownTests = receivedKnownTests
763
+ }
764
+ } catch (err) {
765
+ log.error('Jest known tests error', err)
752
766
  }
753
- } catch (err) {
754
- log.error('Jest known tests error', err)
755
767
  }
756
- }
757
768
 
758
- if (isSuitesSkippingEnabled) {
759
- const skippableSuitesPromise = new Promise((resolve) => {
760
- onDone = resolve
761
- })
769
+ if (isSuitesSkippingEnabled) {
770
+ const skippableSuitesPromise = new Promise((resolve) => {
771
+ onDone = resolve
772
+ })
762
773
 
763
- sessionAsyncResource.runInAsyncScope(() => {
764
774
  skippableSuitesCh.publish({ onDone })
765
- })
766
775
 
767
- try {
768
- const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
769
- if (!err) {
770
- skippableSuites = receivedSkippableSuites
776
+ try {
777
+ const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
778
+ if (!err) {
779
+ skippableSuites = receivedSkippableSuites
780
+ }
781
+ } catch (err) {
782
+ log.error('Jest test-suite skippable error', err)
771
783
  }
772
- } catch (err) {
773
- log.error('Jest test-suite skippable error', err)
774
784
  }
775
- }
776
785
 
777
- if (isTestManagementTestsEnabled) {
778
- const testManagementTestsPromise = new Promise((resolve) => {
779
- onDone = resolve
780
- })
786
+ if (isTestManagementTestsEnabled) {
787
+ const testManagementTestsPromise = new Promise((resolve) => {
788
+ onDone = resolve
789
+ })
781
790
 
782
- sessionAsyncResource.runInAsyncScope(() => {
783
791
  testManagementTestsCh.publish({ onDone })
784
- })
785
792
 
786
- try {
787
- const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
788
- if (!err) {
789
- testManagementTests = receivedTestManagementTests
793
+ try {
794
+ const { err, testManagementTests: receivedTestManagementTests } = await testManagementTestsPromise
795
+ if (!err) {
796
+ testManagementTests = receivedTestManagementTests
797
+ }
798
+ } catch (err) {
799
+ log.error('Jest test management tests error', err)
790
800
  }
791
- } catch (err) {
792
- log.error('Jest test management tests error', err)
793
801
  }
794
- }
795
802
 
796
- if (isImpactedTestsEnabled) {
797
- const impactedTestsPromise = new Promise((resolve) => {
798
- onDone = resolve
799
- })
803
+ if (isImpactedTestsEnabled) {
804
+ const impactedTestsPromise = new Promise((resolve) => {
805
+ onDone = resolve
806
+ })
800
807
 
801
- sessionAsyncResource.runInAsyncScope(() => {
802
808
  impactedTestsCh.publish({ onDone })
803
- })
804
809
 
805
- try {
806
- const { err, modifiedTests: receivedModifiedTests } = await impactedTestsPromise
807
- if (!err) {
808
- modifiedTests = receivedModifiedTests
810
+ try {
811
+ const { err, modifiedTests: receivedModifiedTests } = await impactedTestsPromise
812
+ if (!err) {
813
+ modifiedTests = receivedModifiedTests
814
+ }
815
+ } catch (err) {
816
+ log.error('Jest impacted tests error', err)
809
817
  }
810
- } catch (err) {
811
- log.error('Jest impacted tests error', err)
812
818
  }
813
- }
814
819
 
815
- const processArgv = process.argv.slice(2).join(' ')
816
- sessionAsyncResource.runInAsyncScope(() => {
820
+ const processArgv = process.argv.slice(2).join(' ')
817
821
  testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
818
- })
819
822
 
820
- const result = await runCLI.apply(this, arguments)
823
+ const result = await runCLI.apply(this, arguments)
821
824
 
822
- const {
823
- results: {
824
- success,
825
- coverageMap,
826
- numFailedTestSuites,
827
- numFailedTests,
828
- numTotalTests,
829
- numTotalTestSuites
830
- }
831
- } = result
825
+ const {
826
+ results: {
827
+ success,
828
+ coverageMap,
829
+ numFailedTestSuites,
830
+ numFailedTests,
831
+ numTotalTests,
832
+ numTotalTestSuites
833
+ }
834
+ } = result
832
835
 
833
- let testCodeCoverageLinesTotal
836
+ let testCodeCoverageLinesTotal
834
837
 
835
- if (isUserCodeCoverageEnabled) {
836
- try {
837
- const { pct, total } = coverageMap.getCoverageSummary().lines
838
- testCodeCoverageLinesTotal = total === 0 ? 0 : pct
839
- } catch {
840
- // ignore errors
838
+ if (isUserCodeCoverageEnabled) {
839
+ try {
840
+ const { pct, total } = coverageMap.getCoverageSummary().lines
841
+ testCodeCoverageLinesTotal = total === 0 ? 0 : pct
842
+ } catch {
843
+ // ignore errors
844
+ }
841
845
  }
842
- }
843
- let status, error
846
+ let status, error
844
847
 
845
- if (success) {
846
- status = numTotalTests === 0 && numTotalTestSuites === 0 ? 'skip' : 'pass'
847
- } else {
848
- status = 'fail'
849
- error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
850
- }
851
- let timeoutId
852
-
853
- // Pass the resolve callback to defer it to DC listener
854
- const flushPromise = new Promise((resolve) => {
855
- onDone = () => {
856
- clearTimeout(timeoutId)
857
- resolve()
848
+ if (success) {
849
+ status = numTotalTests === 0 && numTotalTestSuites === 0 ? 'skip' : 'pass'
850
+ } else {
851
+ status = 'fail'
852
+ error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
858
853
  }
859
- })
854
+ let timeoutId
860
855
 
861
- const timeoutPromise = new Promise((resolve) => {
862
- timeoutId = setTimeout(() => {
863
- resolve('timeout')
864
- }, FLUSH_TIMEOUT).unref()
865
- })
856
+ // Pass the resolve callback to defer it to DC listener
857
+ const flushPromise = new Promise((resolve) => {
858
+ onDone = () => {
859
+ clearTimeout(timeoutId)
860
+ resolve()
861
+ }
862
+ })
863
+
864
+ const timeoutPromise = new Promise((resolve) => {
865
+ timeoutId = setTimeout(() => {
866
+ resolve('timeout')
867
+ }, FLUSH_TIMEOUT).unref()
868
+ })
866
869
 
867
- sessionAsyncResource.runInAsyncScope(() => {
868
870
  testSessionFinishCh.publish({
869
871
  status,
870
872
  isSuitesSkipped,
@@ -880,84 +882,86 @@ function cliWrapper (cli, jestVersion) {
880
882
  isTestManagementTestsEnabled,
881
883
  onDone
882
884
  })
883
- })
884
- const waitingResult = await Promise.race([flushPromise, timeoutPromise])
885
885
 
886
- if (waitingResult === 'timeout') {
887
- log.error('Timeout waiting for the tracer to flush')
888
- }
886
+ const waitingResult = await Promise.race([flushPromise, timeoutPromise])
889
887
 
890
- numSkippedSuites = 0
891
-
892
- /**
893
- * If Early Flake Detection (EFD) is enabled the logic is as follows:
894
- * - If all attempts for a test are failing, the test has failed and we will let the test process fail.
895
- * - If just a single attempt passes, we will prevent the test process from failing.
896
- * The rationale behind is the following: you may still be able to block your CI pipeline by gating
897
- * on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
898
- */
899
-
900
- if (isEarlyFlakeDetectionEnabled) {
901
- let numFailedTestsToIgnore = 0
902
- for (const testStatuses of newTestsTestStatuses.values()) {
903
- const { pass, fail } = getTestStats(testStatuses)
904
- if (pass > 0) { // as long as one passes, we'll consider the test passed
905
- numFailedTestsToIgnore += fail
906
- }
888
+ if (waitingResult === 'timeout') {
889
+ log.error('Timeout waiting for the tracer to flush')
907
890
  }
908
- // If every test that failed was an EFD retry, we'll consider the suite passed
909
- if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
910
- result.results.success = true
891
+
892
+ numSkippedSuites = 0
893
+
894
+ /**
895
+ * If Early Flake Detection (EFD) is enabled the logic is as follows:
896
+ * - If all attempts for a test are failing, the test has failed and we will let the test process fail.
897
+ * - If just a single attempt passes, we will prevent the test process from failing.
898
+ * The rationale behind is the following: you may still be able to block your CI pipeline by gating
899
+ * on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
900
+ */
901
+
902
+ if (isEarlyFlakeDetectionEnabled) {
903
+ let numFailedTestsToIgnore = 0
904
+ for (const testStatuses of newTestsTestStatuses.values()) {
905
+ const { pass, fail } = getTestStats(testStatuses)
906
+ if (pass > 0) { // as long as one passes, we'll consider the test passed
907
+ numFailedTestsToIgnore += fail
908
+ }
909
+ }
910
+ // If every test that failed was an EFD retry, we'll consider the suite passed
911
+ if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
912
+ result.results.success = true
913
+ }
911
914
  }
912
- }
913
915
 
914
- if (isTestManagementTestsEnabled) {
915
- const failedTests = result
916
- .results
917
- .testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
918
- testResults.map(({ fullName: testName, status }) => (
919
- { testName, testSuiteAbsolutePath, status }
916
+ if (isTestManagementTestsEnabled) {
917
+ const failedTests = result
918
+ .results
919
+ .testResults.flatMap(({ testResults, testFilePath: testSuiteAbsolutePath }) => (
920
+ testResults.map(({ fullName: testName, status }) => (
921
+ { testName, testSuiteAbsolutePath, status }
922
+ ))
920
923
  ))
921
- ))
922
- .filter(({ status }) => status === 'failed')
923
-
924
- let numFailedQuarantinedTests = 0
925
- let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
926
-
927
- for (const { testName, testSuiteAbsolutePath } of failedTests) {
928
- const testSuite = getTestSuitePath(testSuiteAbsolutePath, result.globalConfig.rootDir)
929
- const originalName = removeAttemptToFixStringFromTestName(testName)
930
- const testManagementTest = testManagementTests
931
- ?.jest
932
- ?.suites
933
- ?.[testSuite]
934
- ?.tests
935
- ?.[originalName]
936
- ?.properties
937
- // This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
938
- if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
939
- numFailedQuarantinedOrDisabledAttemptedToFixTests++
940
- } else if (testManagementTest?.quarantined) {
941
- numFailedQuarantinedTests++
924
+ .filter(({ status }) => status === 'failed')
925
+
926
+ let numFailedQuarantinedTests = 0
927
+ let numFailedQuarantinedOrDisabledAttemptedToFixTests = 0
928
+
929
+ for (const { testName, testSuiteAbsolutePath } of failedTests) {
930
+ const testSuite = getTestSuitePath(testSuiteAbsolutePath, result.globalConfig.rootDir)
931
+ const originalName = removeAttemptToFixStringFromTestName(testName)
932
+ const testManagementTest = testManagementTests
933
+ ?.jest
934
+ ?.suites
935
+ ?.[testSuite]
936
+ ?.tests
937
+ ?.[originalName]
938
+ ?.properties
939
+ // This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
940
+ if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
941
+ numFailedQuarantinedOrDisabledAttemptedToFixTests++
942
+ } else if (testManagementTest?.quarantined) {
943
+ numFailedQuarantinedTests++
944
+ }
942
945
  }
943
- }
944
946
 
945
- // If every test that failed was quarantined, we'll consider the suite passed
946
- // Note that if a test is attempted to fix,
947
- // it's considered quarantined both if it's disabled and if it's quarantined (it'll run but its status is ignored)
948
- if (
949
- (numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
950
- result.results.numFailedTests ===
951
- numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
952
- ) {
953
- result.results.success = true
947
+ // If every test that failed was quarantined, we'll consider the suite passed
948
+ // Note that if a test is attempted to fix,
949
+ // it's considered quarantined both if it's disabled and if it's quarantined
950
+ // (it'll run but its status is ignored)
951
+ if (
952
+ (numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
953
+ result.results.numFailedTests ===
954
+ numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
955
+ ) {
956
+ result.results.success = true
957
+ }
954
958
  }
955
- }
956
-
957
- return result
958
- })
959
959
 
960
- return cli
960
+ return result
961
+ }, {
962
+ replaceGetter: true
963
+ })
964
+ }
961
965
  }
962
966
 
963
967
  function coverageReporterWrapper (coverageReporter) {
@@ -981,6 +985,55 @@ function coverageReporterWrapper (coverageReporter) {
981
985
  return coverageReporter
982
986
  }
983
987
 
988
+ addHook({
989
+ name: '@jest/core',
990
+ file: 'build/TestScheduler.js',
991
+ versions: ['>=27.0.0']
992
+ }, (testSchedulerPackage, frameworkVersion) => {
993
+ const oldCreateTestScheduler = testSchedulerPackage.createTestScheduler
994
+ const newCreateTestScheduler = async function () {
995
+ if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
996
+ return oldCreateTestScheduler.apply(this, arguments)
997
+ }
998
+ // If suite skipping is enabled and has not filtered skippable suites yet, we'll attempt to do it
999
+ const scheduler = await oldCreateTestScheduler.apply(this, arguments)
1000
+ shimmer.wrap(scheduler, 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion))
1001
+ return scheduler
1002
+ }
1003
+ testSchedulerPackage.createTestScheduler = newCreateTestScheduler
1004
+ return testSchedulerPackage
1005
+ })
1006
+
1007
+ addHook({
1008
+ name: '@jest/core',
1009
+ file: 'build/TestScheduler.js',
1010
+ versions: ['>=24.8.0 <27.0.0']
1011
+ }, (testSchedulerPackage, frameworkVersion) => {
1012
+ shimmer.wrap(
1013
+ testSchedulerPackage.default.prototype,
1014
+ 'scheduleTests', scheduleTests => getWrappedScheduleTests(scheduleTests, frameworkVersion)
1015
+ )
1016
+ return testSchedulerPackage
1017
+ })
1018
+
1019
+ addHook({
1020
+ name: '@jest/test-sequencer',
1021
+ versions: ['>=28']
1022
+ }, (sequencerPackage, frameworkVersion) => {
1023
+ shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
1024
+ const shardedTests = shard.apply(this, arguments)
1025
+
1026
+ if (!shardedTests.length || !isSuitesSkippingEnabled || !skippableSuites.length) {
1027
+ return shardedTests
1028
+ }
1029
+ const [test] = shardedTests
1030
+ const rootDir = test?.context?.config?.rootDir
1031
+
1032
+ return applySuiteSkipping(shardedTests, rootDir, frameworkVersion)
1033
+ })
1034
+ return sequencerPackage
1035
+ })
1036
+
984
1037
  addHook({
985
1038
  name: '@jest/reporters',
986
1039
  file: 'build/coverage_reporter.js',
@@ -993,11 +1046,23 @@ addHook({
993
1046
  versions: ['>=26.6.2']
994
1047
  }, coverageReporterWrapper)
995
1048
 
1049
+ addHook({
1050
+ name: '@jest/reporters',
1051
+ versions: ['>=30.0.0']
1052
+ }, (reporters) => {
1053
+ return shimmer.wrap(reporters, 'CoverageReporter', coverageReporterWrapper, { replaceGetter: true })
1054
+ })
1055
+
996
1056
  addHook({
997
1057
  name: '@jest/core',
998
1058
  file: 'build/cli/index.js',
999
- versions: ['>=24.8.0']
1000
- }, cliWrapper)
1059
+ versions: ['>=24.8.0 <30.0.0']
1060
+ }, getCliWrapper(false))
1061
+
1062
+ addHook({
1063
+ name: '@jest/core',
1064
+ versions: ['>=30.0.0']
1065
+ }, getCliWrapper(true))
1001
1066
 
1002
1067
  function jestAdapterWrapper (jestAdapter, jestVersion) {
1003
1068
  const adapter = jestAdapter.default ?? jestAdapter
@@ -1006,45 +1071,40 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1006
1071
  if (!environment) {
1007
1072
  return adapter.apply(this, arguments)
1008
1073
  }
1009
- const asyncResource = new AsyncResource('bound-anonymous-fn')
1010
- return asyncResource.runInAsyncScope(() => {
1011
- testSuiteStartCh.publish({
1012
- testSuite: environment.testSuite,
1013
- testEnvironmentOptions: environment.testEnvironmentOptions,
1014
- testSourceFile: environment.testSourceFile,
1015
- displayName: environment.displayName,
1016
- frameworkVersion: jestVersion
1017
- })
1018
- return adapter.apply(this, arguments).then(suiteResults => {
1019
- const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
1020
- let status = 'pass'
1021
- if (skipped) {
1022
- status = 'skipped'
1023
- } else if (numFailingTests !== 0) {
1024
- status = 'fail'
1025
- }
1074
+ testSuiteStartCh.publish({
1075
+ testSuite: environment.testSuite,
1076
+ testEnvironmentOptions: environment.testEnvironmentOptions,
1077
+ testSourceFile: environment.testSourceFile,
1078
+ displayName: environment.displayName,
1079
+ frameworkVersion: jestVersion
1080
+ })
1081
+ return adapter.apply(this, arguments).then(suiteResults => {
1082
+ const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
1083
+ let status = 'pass'
1084
+ if (skipped) {
1085
+ status = 'skipped'
1086
+ } else if (numFailingTests !== 0) {
1087
+ status = 'fail'
1088
+ }
1026
1089
 
1027
- /**
1028
- * Child processes do not each request ITR configuration, so the jest's parent process
1029
- * needs to pass them the configuration. This is done via _ddTestCodeCoverageEnabled, which
1030
- * controls whether coverage is reported.
1031
- */
1032
- if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
1033
- const root = environment.repositoryRoot || environment.rootDir
1090
+ /**
1091
+ * Child processes do not each request ITR configuration, so the jest's parent process
1092
+ * needs to pass them the configuration. This is done via _ddTestCodeCoverageEnabled, which
1093
+ * controls whether coverage is reported.
1094
+ */
1095
+ if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
1096
+ const root = environment.repositoryRoot || environment.rootDir
1034
1097
 
1035
- const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
1036
- .map(filename => getTestSuitePath(filename, root))
1098
+ const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
1099
+ .map(filename => getTestSuitePath(filename, root))
1037
1100
 
1038
- asyncResource.runInAsyncScope(() => {
1039
- testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
1040
- })
1041
- }
1042
- testSuiteFinishCh.publish({ status, errorMessage })
1043
- return suiteResults
1044
- }).catch(error => {
1045
- testSuiteFinishCh.publish({ status: 'fail', error })
1046
- throw error
1047
- })
1101
+ testSuiteCodeCoverageCh.publish({ coverageFiles, testSuite: environment.testSourceFile })
1102
+ }
1103
+ testSuiteFinishCh.publish({ status, errorMessage })
1104
+ return suiteResults
1105
+ }).catch(error => {
1106
+ testSuiteFinishCh.publish({ status: 'fail', error })
1107
+ throw error
1048
1108
  })
1049
1109
  })
1050
1110
  if (jestAdapter.default) {
@@ -1056,6 +1116,12 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
1056
1116
  return jestAdapter
1057
1117
  }
1058
1118
 
1119
+ addHook({
1120
+ name: 'jest-circus',
1121
+ file: 'build/runner.js',
1122
+ versions: ['>=30.0.0']
1123
+ }, jestAdapterWrapper)
1124
+
1059
1125
  addHook({
1060
1126
  name: 'jest-circus',
1061
1127
  file: 'build/legacy-code-todo-rewrite/jestAdapter.js',
@@ -1064,9 +1130,7 @@ addHook({
1064
1130
 
1065
1131
  function configureTestEnvironment (readConfigsResult) {
1066
1132
  const { configs } = readConfigsResult
1067
- sessionAsyncResource.runInAsyncScope(() => {
1068
- testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
1069
- })
1133
+ testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
1070
1134
  // We can't directly use isCodeCoverageEnabled when reporting coverage in `jestAdapterWrapper`
1071
1135
  // because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
1072
1136
  configs.forEach(config => {
@@ -1102,21 +1166,19 @@ function configureTestEnvironment (readConfigsResult) {
1102
1166
  }
1103
1167
 
1104
1168
  function jestConfigAsyncWrapper (jestConfig) {
1105
- shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
1169
+ return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => async function () {
1106
1170
  const readConfigsResult = await readConfigs.apply(this, arguments)
1107
1171
  configureTestEnvironment(readConfigsResult)
1108
1172
  return readConfigsResult
1109
1173
  })
1110
- return jestConfig
1111
1174
  }
1112
1175
 
1113
1176
  function jestConfigSyncWrapper (jestConfig) {
1114
- shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
1177
+ return shimmer.wrap(jestConfig, 'readConfigs', readConfigs => function () {
1115
1178
  const readConfigsResult = readConfigs.apply(this, arguments)
1116
1179
  configureTestEnvironment(readConfigsResult)
1117
1180
  return readConfigsResult
1118
1181
  })
1119
- return jestConfig
1120
1182
  }
1121
1183
 
1122
1184
  addHook({
@@ -1167,51 +1229,9 @@ addHook({
1167
1229
  */
1168
1230
  addHook({
1169
1231
  name: '@jest/core',
1170
- versions: ['>=24.8.0'],
1232
+ versions: ['>=24.8.0 <30.0.0'],
1171
1233
  file: 'build/SearchSource.js'
1172
- }, (searchSourcePackage, frameworkVersion) => {
1173
- const SearchSource = searchSourcePackage.default ?? searchSourcePackage
1174
-
1175
- shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
1176
- const testPaths = await getTestPaths.apply(this, arguments)
1177
- const [{ rootDir, shard }] = arguments
1178
-
1179
- if (isKnownTestsEnabled) {
1180
- const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
1181
- const isFaulty =
1182
- getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
1183
- if (isFaulty) {
1184
- log.error('Early flake detection is disabled because the number of new suites is too high.')
1185
- isEarlyFlakeDetectionEnabled = false
1186
- isKnownTestsEnabled = false
1187
- const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
1188
- // Project config is shared among all tests, so we can modify it here
1189
- if (testEnvironmentOptions) {
1190
- testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
1191
- testEnvironmentOptions._ddIsKnownTestsEnabled = false
1192
- }
1193
- isEarlyFlakeDetectionFaulty = true
1194
- }
1195
- }
1196
-
1197
- if (shard?.shardCount > 1 || !isSuitesSkippingEnabled || !skippableSuites.length) {
1198
- // If the user is using jest sharding, we want to apply the filtering of tests in the shard process.
1199
- // The reason for this is the following:
1200
- // The tests for different shards are likely being run in different CI jobs so
1201
- // the requests to the skippable endpoint might be done at different times and their responses might be different.
1202
- // If the skippable endpoint is returning different suites and we filter the list of tests here,
1203
- // the base list of tests that is used for sharding might be different,
1204
- // causing the shards to potentially run the same suite.
1205
- return testPaths
1206
- }
1207
- const { tests } = testPaths
1208
-
1209
- const suitesToRun = applySuiteSkipping(tests, rootDir, frameworkVersion)
1210
- return { ...testPaths, tests: suitesToRun }
1211
- })
1212
-
1213
- return searchSourcePackage
1214
- })
1234
+ }, searchSourceWrapper)
1215
1235
 
1216
1236
  // from 25.1.0 on, readConfigs becomes async
1217
1237
  addHook({
@@ -1259,19 +1279,27 @@ addHook({
1259
1279
  return runtimePackage
1260
1280
  })
1261
1281
 
1262
- /*
1263
- * This hook does three things:
1264
- * - Pass known tests to the workers.
1265
- * - Pass test management tests to the workers.
1266
- * - Receive trace, coverage and logs payloads from the workers.
1267
- */
1268
- addHook({
1269
- name: 'jest-worker',
1270
- versions: ['>=24.9.0'],
1271
- file: 'build/workers/ChildProcessWorker.js'
1272
- }, (childProcessWorker) => {
1273
- const ChildProcessWorker = childProcessWorker.default
1274
- shimmer.wrap(ChildProcessWorker.prototype, 'send', send => function (request) {
1282
+ function onMessageWrapper (onMessage) {
1283
+ return function () {
1284
+ const [code, data] = arguments[0]
1285
+ if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
1286
+ workerReportTraceCh.publish(data)
1287
+ return
1288
+ }
1289
+ if (code === JEST_WORKER_COVERAGE_PAYLOAD_CODE) { // datadog coverage payload
1290
+ workerReportCoverageCh.publish(data)
1291
+ return
1292
+ }
1293
+ if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
1294
+ workerReportLogsCh.publish(data)
1295
+ return
1296
+ }
1297
+ return onMessage.apply(this, arguments)
1298
+ }
1299
+ }
1300
+
1301
+ function sendWrapper (send) {
1302
+ return function (request) {
1275
1303
  if (!isKnownTestsEnabled && !isTestManagementTestsEnabled && !isImpactedTestsEnabled) {
1276
1304
  return send.apply(this, arguments)
1277
1305
  }
@@ -1309,30 +1337,47 @@ addHook({
1309
1337
  }
1310
1338
  }
1311
1339
  }
1312
-
1313
1340
  return send.apply(this, arguments)
1314
- })
1315
- shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', _onMessage => function () {
1316
- const [code, data] = arguments[0]
1317
- if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
1318
- sessionAsyncResource.runInAsyncScope(() => {
1319
- workerReportTraceCh.publish(data)
1320
- })
1321
- return
1322
- }
1323
- if (code === JEST_WORKER_COVERAGE_PAYLOAD_CODE) { // datadog coverage payload
1324
- sessionAsyncResource.runInAsyncScope(() => {
1325
- workerReportCoverageCh.publish(data)
1326
- })
1327
- return
1328
- }
1329
- if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
1330
- sessionAsyncResource.runInAsyncScope(() => {
1331
- workerReportLogsCh.publish(data)
1332
- })
1333
- return
1334
- }
1335
- return _onMessage.apply(this, arguments)
1336
- })
1341
+ }
1342
+ }
1343
+
1344
+ function enqueueWrapper (enqueue) {
1345
+ return function () {
1346
+ shimmer.wrap(arguments[0], 'onStart', onStart => function (worker) {
1347
+ if (worker && !wrappedWorkers.has(worker)) {
1348
+ shimmer.wrap(worker._child, 'send', sendWrapper)
1349
+ shimmer.wrap(worker, '_onMessage', onMessageWrapper)
1350
+ worker._child.on('message', worker._onMessage.bind(worker))
1351
+ wrappedWorkers.add(worker)
1352
+ }
1353
+ return onStart.apply(this, arguments)
1354
+ })
1355
+ return enqueue.apply(this, arguments)
1356
+ }
1357
+ }
1358
+
1359
+ /*
1360
+ * This hook does three things:
1361
+ * - Pass known tests to the workers.
1362
+ * - Pass test management tests to the workers.
1363
+ * - Receive trace, coverage and logs payloads from the workers.
1364
+ */
1365
+ addHook({
1366
+ name: 'jest-worker',
1367
+ versions: ['>=24.9.0 <30.0.0'],
1368
+ file: 'build/workers/ChildProcessWorker.js'
1369
+ }, (childProcessWorker) => {
1370
+ const ChildProcessWorker = childProcessWorker.default
1371
+ shimmer.wrap(ChildProcessWorker.prototype, 'send', sendWrapper)
1372
+ shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', onMessageWrapper)
1337
1373
  return childProcessWorker
1338
1374
  })
1375
+
1376
+ addHook({
1377
+ name: 'jest-worker',
1378
+ versions: ['>=30.0.0']
1379
+ }, (jestWorkerPackage) => {
1380
+ shimmer.wrap(jestWorkerPackage.FifoQueue.prototype, 'enqueue', enqueueWrapper)
1381
+ shimmer.wrap(jestWorkerPackage.PriorityQueue.prototype, 'enqueue', enqueueWrapper)
1382
+ return jestWorkerPackage
1383
+ })