dd-trace 5.132.0 → 5.134.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 (231) hide show
  1. package/ci/diagnose.js +9 -14
  2. package/ci/init.js +1 -2
  3. package/ci/test-optimization-validation/ci-discovery.js +9 -4
  4. package/ci/test-optimization-validation/executable.js +1 -5
  5. package/ci/test-optimization-validation/framework-adapters/cypress.js +1 -4
  6. package/ci/test-optimization-validation/framework-adapters/vitest.js +1 -1
  7. package/ci/test-optimization-validation/generated-files.js +6 -4
  8. package/ci/test-optimization-validation/generated-test-contract.js +7 -3
  9. package/ci/test-optimization-validation/manifest-scaffold.js +7 -2
  10. package/ci/test-optimization-validation/manifest-schema.js +6 -7
  11. package/ci/test-optimization-validation/report-writer.js +6 -2
  12. package/ci/test-optimization-validation/runner-command.js +2 -4
  13. package/ci/test-optimization-validation/runner-contract.js +1 -2
  14. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +1 -15
  15. package/ci/vitest-no-worker-init-runner-setup.mjs +27 -0
  16. package/ci/vitest-no-worker-init-setup.mjs +10 -7
  17. package/index.d.ts +41 -19
  18. package/initialize.mjs +1 -3
  19. package/openfeature/rules-based.d.ts +11 -0
  20. package/openfeature/rules-based.js +7 -0
  21. package/package.json +25 -22
  22. package/packages/datadog-core/src/storage.js +16 -0
  23. package/packages/datadog-esbuild/index.js +18 -12
  24. package/packages/datadog-instrumentations/index.js +2 -1
  25. package/packages/datadog-instrumentations/src/aerospike.js +3 -3
  26. package/packages/datadog-instrumentations/src/ai.js +3 -3
  27. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -6
  28. package/packages/datadog-instrumentations/src/aws-sdk.js +21 -13
  29. package/packages/datadog-instrumentations/src/cassandra-driver.js +25 -20
  30. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +9 -23
  31. package/packages/datadog-instrumentations/src/cucumber.js +65 -41
  32. package/packages/datadog-instrumentations/src/elasticsearch.js +1 -5
  33. package/packages/datadog-instrumentations/src/electron.js +6 -6
  34. package/packages/datadog-instrumentations/src/fastify.js +13 -4
  35. package/packages/datadog-instrumentations/src/fs.js +2 -2
  36. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +9 -5
  37. package/packages/datadog-instrumentations/src/grpc/client.js +2 -0
  38. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +28 -9
  39. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +1 -2
  40. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  41. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  42. package/packages/datadog-instrumentations/src/helpers/register.js +45 -1
  43. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -0
  44. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +89 -6
  45. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql-jit.js +5 -6
  46. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/jest.js +12 -0
  47. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +48 -31
  48. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/vitest.js +8 -0
  49. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +7 -7
  50. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +5 -0
  51. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +42 -4
  52. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +7 -10
  53. package/packages/datadog-instrumentations/src/ioredis.js +7 -5
  54. package/packages/datadog-instrumentations/src/iovalkey.js +7 -5
  55. package/packages/datadog-instrumentations/src/jest.js +72 -67
  56. package/packages/datadog-instrumentations/src/knex.js +9 -5
  57. package/packages/datadog-instrumentations/src/mariadb-bundle.js +3 -3
  58. package/packages/datadog-instrumentations/src/mocha/common.js +20 -8
  59. package/packages/datadog-instrumentations/src/mocha/main.js +140 -43
  60. package/packages/datadog-instrumentations/src/mocha/utils.js +38 -4
  61. package/packages/datadog-instrumentations/src/mocha/worker.js +1 -2
  62. package/packages/datadog-instrumentations/src/mongodb-core.js +3 -3
  63. package/packages/datadog-instrumentations/src/mongoose.js +3 -3
  64. package/packages/datadog-instrumentations/src/nova-sonic/audio.js +173 -0
  65. package/packages/datadog-instrumentations/src/nova-sonic/index.js +209 -0
  66. package/packages/datadog-instrumentations/src/nova-sonic/session.js +492 -0
  67. package/packages/datadog-instrumentations/src/openai-realtime/index.js +18 -6
  68. package/packages/datadog-instrumentations/src/openai-realtime/session.js +1 -1
  69. package/packages/datadog-instrumentations/src/openai.js +7 -0
  70. package/packages/datadog-instrumentations/src/pino.js +5 -6
  71. package/packages/datadog-instrumentations/src/playwright.js +2 -0
  72. package/packages/datadog-instrumentations/src/redis.js +27 -13
  73. package/packages/datadog-instrumentations/src/router.js +30 -0
  74. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +2 -6
  75. package/packages/datadog-instrumentations/src/stripe.js +23 -12
  76. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +8 -5
  77. package/packages/datadog-instrumentations/src/vitest-main.js +16 -18
  78. package/packages/datadog-instrumentations/src/vitest-util.js +7 -4
  79. package/packages/datadog-instrumentations/src/vitest-worker.js +1 -2
  80. package/packages/datadog-instrumentations/src/vitest.js +9 -1
  81. package/packages/datadog-instrumentations/src/webdriverio.js +5 -8
  82. package/packages/datadog-instrumentations/src/ws.js +1 -4
  83. package/packages/datadog-plugin-amqplib/src/client.js +1 -2
  84. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -5
  85. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +1 -2
  86. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -8
  87. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +18 -0
  88. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/sonic.js +45 -0
  89. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
  90. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -5
  91. package/packages/datadog-plugin-azure-durable-functions/src/index.js +5 -4
  92. package/packages/datadog-plugin-azure-functions/src/index.js +5 -3
  93. package/packages/datadog-plugin-claude-agent-sdk/src/index.js +0 -2
  94. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +4 -5
  95. package/packages/datadog-plugin-cypress/src/index.js +6 -6
  96. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -2
  97. package/packages/datadog-plugin-cypress/src/support.js +3 -4
  98. package/packages/datadog-plugin-express/src/code_origin.js +1 -2
  99. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
  100. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  101. package/packages/datadog-plugin-graphql/src/execute.js +5 -5
  102. package/packages/datadog-plugin-grpc/src/util.js +1 -2
  103. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -2
  104. package/packages/datadog-plugin-mocha/src/index.js +7 -10
  105. package/packages/datadog-plugin-mocha/src/webdriverio-video.js +8 -4
  106. package/packages/datadog-plugin-mongodb-core/src/query.js +8 -5
  107. package/packages/datadog-plugin-next/src/index.js +1 -2
  108. package/packages/datadog-plugin-openai/src/tracing.js +5 -2
  109. package/packages/datadog-plugin-openai-agents/src/integration.js +6 -2
  110. package/packages/datadog-plugin-openai-agents/src/processor.js +2 -4
  111. package/packages/datadog-plugin-postgres/src/index.js +24 -0
  112. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -5
  113. package/packages/datadog-plugin-rhea/src/consumer.js +1 -4
  114. package/packages/datadog-plugin-vitest/src/index.js +5 -2
  115. package/packages/datadog-shimmer/src/shimmer.js +5 -4
  116. package/packages/datadog-webpack/index.js +55 -43
  117. package/packages/datadog-webpack/src/loader.js +56 -8
  118. package/packages/dd-trace/src/aiguard/evaluation.js +143 -1
  119. package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +2 -4
  120. package/packages/dd-trace/src/aiguard/messages/utils.js +1 -2
  121. package/packages/dd-trace/src/aiguard/redaction.js +8 -2
  122. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +3 -2
  123. package/packages/dd-trace/src/appsec/api_security/sampler.js +2 -6
  124. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -9
  125. package/packages/dd-trace/src/appsec/handlers/http-request.js +3 -9
  126. package/packages/dd-trace/src/appsec/handlers/http-response.js +7 -2
  127. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +4 -3
  128. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +1 -4
  129. package/packages/dd-trace/src/appsec/iast/path-line.js +2 -1
  130. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +7 -1
  131. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -3
  132. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +1 -3
  133. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +1 -6
  134. package/packages/dd-trace/src/appsec/lambda.js +1 -3
  135. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +37 -27
  136. package/packages/dd-trace/src/appsec/rasp/lfi.js +9 -5
  137. package/packages/dd-trace/src/appsec/reporter.js +21 -1
  138. package/packages/dd-trace/src/appsec/stack_trace.js +4 -4
  139. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +3 -6
  140. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -2
  141. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +1 -1
  142. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -7
  143. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +1 -2
  144. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +2 -8
  145. package/packages/dd-trace/src/ci-visibility/resolve-runfile-path.js +54 -0
  146. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +5 -8
  147. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +2 -53
  148. package/packages/dd-trace/src/config/config-types.d.ts +2 -2
  149. package/packages/dd-trace/src/config/defaults.js +5 -5
  150. package/packages/dd-trace/src/config/generated-config-types.d.ts +10 -0
  151. package/packages/dd-trace/src/config/helper.js +34 -3
  152. package/packages/dd-trace/src/config/index.js +55 -9
  153. package/packages/dd-trace/src/config/normalize-service.js +1 -1
  154. package/packages/dd-trace/src/config/parsers.js +2 -2
  155. package/packages/dd-trace/src/config/supported-configurations.json +44 -0
  156. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  157. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +1 -4
  158. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -5
  159. package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -5
  160. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -0
  161. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +4 -6
  162. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -0
  163. package/packages/dd-trace/src/debugger/guardrail-metrics.js +2 -2
  164. package/packages/dd-trace/src/debugger/unsupported-runtime.js +16 -0
  165. package/packages/dd-trace/src/dogstatsd.js +1 -1
  166. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  167. package/packages/dd-trace/src/exporters/common/request.js +1 -5
  168. package/packages/dd-trace/src/id.js +14 -1
  169. package/packages/dd-trace/src/lambda/handler.js +179 -19
  170. package/packages/dd-trace/src/lambda/index.js +15 -1
  171. package/packages/dd-trace/src/lambda/runtime/patch.js +34 -7
  172. package/packages/dd-trace/src/llmobs/agent-manifest.js +19 -2
  173. package/packages/dd-trace/src/llmobs/audio-utils.js +3 -2
  174. package/packages/dd-trace/src/llmobs/constants/tags.js +15 -0
  175. package/packages/dd-trace/src/llmobs/experiments/experiment.js +1 -1
  176. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +15 -0
  177. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +1 -2
  178. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +1 -3
  179. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  180. package/packages/dd-trace/src/llmobs/plugins/nova-sonic.js +92 -0
  181. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +5 -0
  182. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +64 -2
  183. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +38 -0
  184. package/packages/dd-trace/src/llmobs/prompts/manager.js +5 -7
  185. package/packages/dd-trace/src/llmobs/prompts/prompt.js +1 -1
  186. package/packages/dd-trace/src/llmobs/sdk.js +15 -4
  187. package/packages/dd-trace/src/llmobs/span_processor.js +13 -2
  188. package/packages/dd-trace/src/llmobs/tagger.js +20 -10
  189. package/packages/dd-trace/src/llmobs/util.js +11 -6
  190. package/packages/dd-trace/src/llmobs/writers/base.js +4 -5
  191. package/packages/dd-trace/src/log/log.js +1 -5
  192. package/packages/dd-trace/src/openfeature/evaluation-telemetry-opt-out-hook.js +51 -0
  193. package/packages/dd-trace/src/openfeature/flagging_provider.js +48 -21
  194. package/packages/dd-trace/src/openfeature/index.js +6 -0
  195. package/packages/dd-trace/src/openfeature/writers/util.js +4 -4
  196. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +1 -1
  197. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  198. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -2
  199. package/packages/dd-trace/src/opentelemetry/otlp/common.proto +1 -1
  200. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +24 -24
  201. package/packages/dd-trace/src/opentracing/propagation/text_map.js +53 -13
  202. package/packages/dd-trace/src/otel-sampling.js +4 -5
  203. package/packages/dd-trace/src/otel-thread-ctx.js +79 -13
  204. package/packages/dd-trace/src/plugin_manager.js +1 -2
  205. package/packages/dd-trace/src/plugins/database.js +7 -16
  206. package/packages/dd-trace/src/plugins/tracing.js +0 -1
  207. package/packages/dd-trace/src/plugins/util/git.js +99 -59
  208. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -5
  209. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -1
  210. package/packages/dd-trace/src/plugins/util/test.js +50 -4
  211. package/packages/dd-trace/src/plugins/util/web.js +90 -20
  212. package/packages/dd-trace/src/priority_sampler.js +1 -2
  213. package/packages/dd-trace/src/profiling/profiler.js +4 -6
  214. package/packages/dd-trace/src/proxy.js +1 -2
  215. package/packages/dd-trace/src/ritm.js +4 -2
  216. package/packages/dd-trace/src/serverless.js +5 -0
  217. package/packages/dd-trace/src/span_processor.js +13 -17
  218. package/packages/dd-trace/src/span_stats.js +4 -1
  219. package/packages/dd-trace/src/telemetry/endpoints.js +1 -3
  220. package/packages/dd-trace/src/telemetry/logs/log-collector.js +1 -1
  221. package/packages/dd-trace/src/util.js +37 -4
  222. package/packages/dd-trace/src/web-tags-cache.js +6 -2
  223. package/vendor/dist/@apm-js-collab/code-transformer/index.js +8 -8
  224. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  225. package/vendor/dist/@datadog/openfeature-node-server/rules-based/LICENSE +201 -0
  226. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.d.ts +925 -0
  227. package/vendor/dist/@datadog/openfeature-node-server/rules-based/index.js +1 -0
  228. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  229. package/vendor/dist/protobufjs/index.js +1 -1
  230. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  231. package/vendor/dist/shell-quote/index.js +1 -1
@@ -64,7 +64,7 @@ const {
64
64
  getChannelPromise,
65
65
  publishWithCompletion,
66
66
  } = require('./helpers/channel')
67
- const { addHook, channel } = require('./helpers/instrument')
67
+ const { addHook, channel, getHooks, tracingChannel } = require('./helpers/instrument')
68
68
 
69
69
  const testSessionStartCh = channel('ci:jest:session:start')
70
70
  const testSessionFinishCh = channel('ci:jest:session:finish')
@@ -125,6 +125,7 @@ const jestSessionState = (globalThis[JEST_SESSION_STATE] ||= {})
125
125
 
126
126
  // https://github.com/jestjs/jest/blob/41f842a46bb2691f828c3a5f27fc1d6290495b82/packages/jest-circus/src/types.ts#L9C8-L9C54
127
127
  const RETRY_TIMES = Symbol.for('RETRY_TIMES')
128
+ const RETRY_TIMES_SETTER = Symbol.for('RETRY_TIMES_SETTER')
128
129
 
129
130
  let skippableSuites = []
130
131
  let skippableSuitesCoverage
@@ -195,6 +196,7 @@ const dynamicAtrResultHandlerRegistrations = new WeakMap()
195
196
  // Tests that are genuinely new (not in known tests list).
196
197
  const newTests = new Set()
197
198
  const testSuiteJestObjects = new Map()
199
+ const deferredTestSuiteFinishes = new Map()
198
200
  const testSuiteDatadogEnvironments = new Map()
199
201
  const wrappedJestGlobals = new WeakSet()
200
202
  const wrappedJestEsmLoaders = new WeakSet()
@@ -741,9 +743,11 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
741
743
  }
742
744
  }
743
745
 
746
+ this.hasAutomaticRetries = false
744
747
  if (this.isFlakyTestRetriesEnabled) {
745
748
  const currentNumRetries = this.global[RETRY_TIMES]
746
749
  if (!currentNumRetries) {
750
+ this.hasAutomaticRetries = true
747
751
  // When dynamic ATR is enabled, use the max bucket value as the initial count.
748
752
  // The actual duration-based count is computed per test after the first attempt.
749
753
  if (this.isDynamicAtrEnabled) {
@@ -891,8 +895,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
891
895
  */
892
896
  wrapConcurrentTestFunction (target, methodName, state) {
893
897
  let concurrentTest = target?.[methodName]
894
- if (typeof concurrentTest !== 'function') return
895
- if (this.wrappedConcurrentTestFunctions.has(concurrentTest)) return
898
+ if (typeof concurrentTest !== 'function' || this.wrappedConcurrentTestFunctions.has(concurrentTest)) return
896
899
 
897
900
  const originalConcurrentTest = getOriginalConcurrentTest(concurrentTest)
898
901
  if (originalConcurrentTest !== concurrentTest) {
@@ -2446,7 +2449,16 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2446
2449
  }
2447
2450
 
2448
2451
  let isAtrRetry = false
2449
- if (this.isFlakyTestRetriesEnabled && event.test?.invocations > 1 && !isAttemptToFix && !isEfdRetry) {
2452
+ let hasAutomaticRetries = this.hasAutomaticRetries || dynamicAtrRetryCountByTest.has(event.test)
2453
+ // Describe retries suppress per-test retries throughout the block, including nested describes.
2454
+ for (let block = event.test.parent; block; block = block.parent) {
2455
+ if (state.describeRetryOptions?.has(block)) {
2456
+ hasAutomaticRetries = false
2457
+ break
2458
+ }
2459
+ }
2460
+ if (this.isFlakyTestRetriesEnabled && hasAutomaticRetries &&
2461
+ event.test?.invocations > 1 && !isAttemptToFix && !isEfdRetry) {
2450
2462
  isAtrRetry = true
2451
2463
  }
2452
2464
 
@@ -2653,19 +2665,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2653
2665
  }
2654
2666
  }
2655
2667
  }
2656
- const clearActiveTestSuite = () => {
2657
- realSetTimeout(() => {
2658
- if (activeTestSuiteAbsolutePath === this.testSuiteAbsolutePath) {
2659
- activeTestSuiteAbsolutePath = undefined
2660
- }
2661
- }, 0)
2662
- }
2663
- const result = super.teardown()
2664
- if (result?.then) {
2665
- return result.finally(clearActiveTestSuite)
2666
- }
2667
- clearActiveTestSuite()
2668
- return result
2668
+ return super.teardown()
2669
2669
  }
2670
2670
  }
2671
2671
  }
@@ -2675,10 +2675,7 @@ function getTestEnvironment (pkg, jestVersion) {
2675
2675
  const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
2676
2676
  return new Proxy(pkg, {
2677
2677
  get (target, prop) {
2678
- if (prop === 'default') {
2679
- return wrappedTestEnvironment
2680
- }
2681
- if (prop === 'TestEnvironment') {
2678
+ if (prop === 'default' || prop === 'TestEnvironment') {
2682
2679
  return wrappedTestEnvironment
2683
2680
  }
2684
2681
  return target[prop]
@@ -3496,22 +3493,48 @@ function shouldWaitForTestSuiteFinish (environment) {
3496
3493
  return isJestWorker && environment.globalConfig?.workerIdleMemoryLimit !== undefined
3497
3494
  }
3498
3495
 
3496
+ /**
3497
+ * @param {string} testSuiteAbsolutePath
3498
+ */
3499
+ function finishTestSuiteAfterRun (testSuiteAbsolutePath) {
3500
+ const clearActiveTestSuite = () => {
3501
+ realSetTimeout(() => {
3502
+ if (activeTestSuiteAbsolutePath === testSuiteAbsolutePath) {
3503
+ activeTestSuiteAbsolutePath = undefined
3504
+ }
3505
+ }, 0)
3506
+ }
3507
+ const payload = deferredTestSuiteFinishes.get(testSuiteAbsolutePath)
3508
+ deferredTestSuiteFinishes.delete(testSuiteAbsolutePath)
3509
+ if (payload) {
3510
+ return getChannelPromise(testSuiteFinishCh, { ...payload, waitForFinish: true })
3511
+ .finally(clearActiveTestSuite)
3512
+ }
3513
+ return clearActiveTestSuite()
3514
+ }
3515
+
3516
+ tracingChannel('orchestrion:jest-runner:runTestInternal').end.subscribe((message) => {
3517
+ const ctx = /** @type {{ arguments: [string, ...unknown[]], result: Promise<unknown> }} */ (message)
3518
+ const [testSuiteAbsolutePath] = ctx.arguments
3519
+ // Jest's runner awaits the complete custom teardown before this promise settles.
3520
+ ctx.result = ctx.result.finally(() => finishTestSuiteAfterRun(testSuiteAbsolutePath))
3521
+ })
3522
+
3523
+ for (const hook of getHooks('jest-runner').values()) addHook(hook, moduleExports => moduleExports)
3524
+
3499
3525
  /**
3500
3526
  * @param {Record<string, unknown>} payload
3501
- * @param {boolean} waitForFinish
3527
+ * @param {InstanceType<ReturnType<typeof getWrappedEnvironment>>} environment
3502
3528
  */
3503
- function publishTestSuiteFinish (payload, waitForFinish) {
3529
+ function publishTestSuiteFinish (payload, environment) {
3504
3530
  if (!testSuiteFinishCh.hasSubscribers) return
3505
3531
 
3506
- if (!waitForFinish) {
3507
- testSuiteFinishCh.publish(payload)
3532
+ if (shouldWaitForTestSuiteFinish(environment)) {
3533
+ deferredTestSuiteFinishes.set(environment.testSuiteAbsolutePath, payload)
3508
3534
  return
3509
3535
  }
3510
3536
 
3511
- return getChannelPromise(testSuiteFinishCh, {
3512
- ...payload,
3513
- waitForFinish,
3514
- })
3537
+ testSuiteFinishCh.publish(payload)
3515
3538
  }
3516
3539
 
3517
3540
  function cleanupTestSuiteState (testSuiteAbsolutePath) {
@@ -3688,48 +3711,24 @@ function jestAdapterWrapper (jestAdapter, jestVersion, isIitm, hookMeta) {
3688
3711
  testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
3689
3712
  })
3690
3713
  }
3691
- const waitForFinish = shouldWaitForTestSuiteFinish(environment)
3692
3714
  const finishPayload = {
3693
3715
  status,
3694
3716
  errorMessage,
3695
3717
  testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
3696
3718
  }
3697
- if (waitForFinish) {
3698
- const finishPromise = publishTestSuiteFinish(finishPayload, waitForFinish)
3699
- if (finishPromise) {
3700
- return finishPromise.then(() => {
3701
- // Cleanup per-suite state to avoid memory leaks
3702
- cleanupTestSuiteState(environment.testSuiteAbsolutePath)
3703
-
3704
- return suiteResults
3705
- })
3706
- }
3707
- }
3708
- publishTestSuiteFinish(finishPayload, waitForFinish)
3719
+ publishTestSuiteFinish(finishPayload, environment)
3709
3720
 
3710
3721
  // Cleanup per-suite state to avoid memory leaks
3711
3722
  cleanupTestSuiteState(environment.testSuiteAbsolutePath)
3712
3723
 
3713
3724
  return suiteResults
3714
3725
  }).catch(error => {
3715
- const waitForFinish = shouldWaitForTestSuiteFinish(environment)
3716
3726
  const finishPayload = {
3717
3727
  status: 'fail',
3718
3728
  error,
3719
3729
  testSuiteAbsolutePath: environment.testSuiteAbsolutePath,
3720
3730
  }
3721
- if (waitForFinish) {
3722
- const finishPromise = publishTestSuiteFinish(finishPayload, waitForFinish)
3723
- if (finishPromise) {
3724
- return finishPromise.then(() => {
3725
- // Cleanup per-suite state to avoid memory leaks
3726
- cleanupTestSuiteState(environment.testSuiteAbsolutePath)
3727
-
3728
- throw error
3729
- })
3730
- }
3731
- }
3732
- publishTestSuiteFinish(finishPayload, waitForFinish)
3731
+ publishTestSuiteFinish(finishPayload, environment)
3733
3732
 
3734
3733
  // Cleanup per-suite state to avoid memory leaks
3735
3734
  cleanupTestSuiteState(environment.testSuiteAbsolutePath)
@@ -3982,12 +3981,11 @@ const LIBRARIES_BYPASSING_JEST_REQUIRE_ENGINE = new Set([
3982
3981
  'selenium-webdriver/chromium',
3983
3982
  ])
3984
3983
 
3985
- function recordMockedFile (suiteFilePath, moduleName) {
3984
+ function recordMockedFile (suiteFilePath, moduleName, from = suiteFilePath) {
3986
3985
  if (!suiteFilePath || typeof moduleName !== 'string') return
3987
3986
 
3988
3987
  const existingMockedFiles = testSuiteMockedFiles.get(suiteFilePath) || []
3989
- const suiteDir = path.dirname(suiteFilePath)
3990
- const mockPath = path.resolve(suiteDir, moduleName)
3988
+ const mockPath = path.resolve(path.dirname(from), moduleName)
3991
3989
  existingMockedFiles.push(mockPath)
3992
3990
  testSuiteMockedFiles.set(suiteFilePath, existingMockedFiles)
3993
3991
  }
@@ -4022,14 +4020,24 @@ function getMockedFiles (suiteFilePath) {
4022
4020
  return staticMockedFiles
4023
4021
  }
4024
4022
 
4025
- function wrapJestObject (jestObject, suiteFilePath) {
4023
+ function wrapJestObject (jestObject, suiteFilePath, from = suiteFilePath) {
4026
4024
  if (!jestObject || !suiteFilePath || wrappedJestObjects.has(jestObject)) return
4027
4025
 
4028
4026
  testSuiteJestObjects.set(suiteFilePath, jestObject)
4029
4027
  wrappedJestObjects.add(jestObject)
4030
4028
 
4029
+ // retryTimes is created per runtime, so wrap the returned public API object.
4030
+ shimmer.wrap(jestObject, 'retryTimes', retryTimes => function () {
4031
+ const environment = testSuiteDatadogEnvironments.get(suiteFilePath)
4032
+ // Older Jest versions ignore entireDescribe and still replace the global budget.
4033
+ if (environment && !(arguments[1]?.entireDescribe && environment.global[RETRY_TIMES_SETTER])) {
4034
+ environment.hasAutomaticRetries = false
4035
+ }
4036
+ return retryTimes.apply(this, arguments)
4037
+ })
4038
+
4031
4039
  shimmer.wrap(jestObject, 'mock', mock => function (moduleName) {
4032
- recordMockedFile(suiteFilePath, moduleName)
4040
+ recordMockedFile(suiteFilePath, moduleName, from)
4033
4041
  return mock.apply(this, arguments)
4034
4042
  })
4035
4043
  }
@@ -4043,7 +4051,7 @@ function wrapJestGlobalsForRuntime (runtime) {
4043
4051
  wrappedJestGlobals.add(jestGlobals)
4044
4052
  shimmer.wrap(jestGlobals, 'jestObjectFor', jestObjectFor => function (from) {
4045
4053
  const jestObject = jestObjectFor.apply(this, arguments)
4046
- wrapJestObject(jestObject, from)
4054
+ wrapJestObject(jestObject, runtime._testPath || from, from)
4047
4055
  return jestObject
4048
4056
  })
4049
4057
  }
@@ -4338,9 +4346,9 @@ addHook({
4338
4346
  if (typeof Runtime.prototype._createJestObjectFor === 'function') {
4339
4347
  shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
4340
4348
  const result = _createJestObjectFor.apply(this, arguments)
4341
- const suiteFilePath = this._testPath || from
4349
+ const suiteFilePath = this._testPath || this._environment?.testSuiteAbsolutePath || from
4342
4350
 
4343
- wrapJestObject(result, suiteFilePath)
4351
+ wrapJestObject(result, suiteFilePath, from)
4344
4352
  return result
4345
4353
  })
4346
4354
  }
@@ -4495,10 +4503,7 @@ function sendWrapper (send) {
4495
4503
  // In here we modify the `config.testEnvironmentOptions` to include the known tests for the suite.
4496
4504
  // This way the suite only knows about the tests that are part of it.
4497
4505
  const args = request.at(-1)
4498
- if (args.length > 1) {
4499
- return send.apply(this, arguments)
4500
- }
4501
- if (!args[0]?.config) {
4506
+ if (args.length > 1 || !args[0]?.config) {
4502
4507
  return send.apply(this, arguments)
4503
4508
  }
4504
4509
  const [{ globalConfig, config, path: testSuiteAbsolutePath }] = args
@@ -62,13 +62,13 @@ addHook({
62
62
  const rawResult = raw.apply(this, args)
63
63
  shimmer.wrap(rawResult, 'then', originalThen => function (...args) {
64
64
  return rawQuerySubscribes.runStores(context, () => {
65
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
66
- if (args[1]) args[1] = wrapCallbackWithFinish(args[1], finish, context)
65
+ args[0] = wrapCallbackWithFinish(args[0], context)
66
+ if (args[1]) args[1] = wrapCallbackWithFinish(args[1], context)
67
67
 
68
68
  const originalThenResult = originalThen.apply(this, args)
69
69
 
70
70
  shimmer.wrap(originalThenResult, 'catch', originalCatch => function (...args) {
71
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
71
+ args[0] = wrapCallbackWithFinish(args[0], context)
72
72
  return originalCatch.apply(this, args)
73
73
  })
74
74
 
@@ -78,7 +78,7 @@ addHook({
78
78
 
79
79
  shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function (...args) {
80
80
  return rawQuerySubscribes.runStores(context, () => {
81
- args[0] = wrapCallbackWithFinish(args[0], finish, context)
81
+ args[0] = wrapCallbackWithFinish(args[0], context)
82
82
  return originalAsCallback.apply(this, args)
83
83
  })
84
84
  })
@@ -118,7 +118,11 @@ addHook({
118
118
  return Transaction
119
119
  })
120
120
 
121
- function wrapCallbackWithFinish (callback, finish, context) {
121
+ /**
122
+ * @param {unknown} callback
123
+ * @param {object} context
124
+ */
125
+ function wrapCallbackWithFinish (callback, context) {
122
126
  if (typeof callback !== 'function') return callback
123
127
 
124
128
  return shimmer.wrapFunction(callback, callback => function (...args) {
@@ -1055,9 +1055,9 @@ function createWrapCallbackGetConnection (options) {
1055
1055
  return function wrapGetConnection (getConnection) {
1056
1056
  return function () {
1057
1057
  const callback = arguments[arguments.length - 1]
1058
- if (typeof callback !== 'function') return getConnection.apply(this, arguments)
1059
-
1060
- if (!connectionStartCh.hasSubscribers) return getConnection.apply(this, arguments)
1058
+ if (typeof callback !== 'function' || !connectionStartCh.hasSubscribers) {
1059
+ return getConnection.apply(this, arguments)
1060
+ }
1061
1061
 
1062
1062
  if (!acquireStartCh.hasSubscribers) {
1063
1063
  const ctx = {}
@@ -11,33 +11,45 @@ const MINIMUM_MOCHA_VERSION = DD_MAJOR >= 6 ? '>=8.0.0' : '>=5.2.0'
11
11
  const parameterizedTestCh = channel('ci:mocha:test:parameterize')
12
12
  const patched = new WeakSet()
13
13
 
14
+ /** @typedef {{ moduleBaseDir?: string }} MochaHookMeta */
15
+
14
16
  /**
15
17
  * Registers every Mocha package view that can expose the constructor.
16
18
  *
17
19
  * @param {string[]} versions
18
- * @param {(Mocha: Function, frameworkVersion: string) => Function} wrapMochaRun
20
+ * @param {(Mocha: Function, frameworkVersion: string, hookMeta: MochaHookMeta) => Function} wrapMochaRun
19
21
  */
20
22
  function addMochaRunHooks (versions, wrapMochaRun) {
21
- const patchedMochaConstructors = new WeakSet()
23
+ const patchedMochaConstructors = new WeakMap()
22
24
 
23
25
  /**
24
26
  * @param {Function} Mocha
25
27
  * @param {string} frameworkVersion
28
+ * @param {boolean | undefined} isIitm
29
+ * @param {{ moduleBaseDir: string } | undefined} hookMeta
26
30
  * @returns {Function}
27
31
  */
28
- function wrapMochaOnce (Mocha, frameworkVersion) {
29
- if (patchedMochaConstructors.has(Mocha)) return Mocha
30
- patchedMochaConstructors.add(Mocha)
31
- return wrapMochaRun(Mocha, frameworkVersion)
32
+ function wrapMochaOnce (Mocha, frameworkVersion, isIitm, hookMeta) {
33
+ let metadata = patchedMochaConstructors.get(Mocha)
34
+ if (metadata) {
35
+ // A bundler can expose the constructor before an ordinary loader supplies its package directory.
36
+ metadata.moduleBaseDir ??= hookMeta?.moduleBaseDir
37
+ return Mocha
38
+ }
39
+ metadata = { moduleBaseDir: hookMeta?.moduleBaseDir }
40
+ patchedMochaConstructors.set(Mocha, metadata)
41
+ return wrapMochaRun(Mocha, frameworkVersion, metadata)
32
42
  }
33
43
 
34
44
  /**
35
45
  * @param {object|Function} MochaPackage
36
46
  * @param {string} frameworkVersion
47
+ * @param {boolean | undefined} isIitm
48
+ * @param {{ moduleBaseDir: string } | undefined} hookMeta
37
49
  * @returns {object|Function}
38
50
  */
39
- function wrapMochaPackage (MochaPackage, frameworkVersion) {
40
- wrapMochaOnce(MochaPackage.default ?? MochaPackage, frameworkVersion)
51
+ function wrapMochaPackage (MochaPackage, frameworkVersion, isIitm, hookMeta) {
52
+ wrapMochaOnce(MochaPackage.default ?? MochaPackage, frameworkVersion, isIitm, hookMeta)
41
53
  return MochaPackage
42
54
  }
43
55