dd-trace 6.16.0 → 6.18.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 (356) hide show
  1. package/ci/diagnose.js +0 -23
  2. package/ci/test-optimization-validation/approval-artifacts.js +0 -3
  3. package/ci/test-optimization-validation/approval.js +0 -6
  4. package/ci/test-optimization-validation/artifact-id.js +0 -1
  5. package/ci/test-optimization-validation/bounded-json.js +0 -1
  6. package/ci/test-optimization-validation/cli.js +0 -12
  7. package/ci/test-optimization-validation/command-output-policy.js +0 -1
  8. package/ci/test-optimization-validation/command-runner.js +0 -3
  9. package/ci/test-optimization-validation/environment.js +0 -4
  10. package/ci/test-optimization-validation/executable-approval.js +0 -1
  11. package/ci/test-optimization-validation/executable.js +0 -5
  12. package/ci/test-optimization-validation/framework-adapters/cucumber.js +0 -6
  13. package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
  14. package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
  15. package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
  16. package/ci/test-optimization-validation/generated-test-contract.js +0 -5
  17. package/ci/test-optimization-validation/generated-verifier.js +0 -1
  18. package/ci/test-optimization-validation/literal-environment.js +0 -1
  19. package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
  20. package/ci/test-optimization-validation/manifest-schema.js +0 -21
  21. package/ci/test-optimization-validation/offline-fixtures.js +0 -4
  22. package/ci/test-optimization-validation/plan-writer.js +0 -11
  23. package/ci/test-optimization-validation/preflight-runner.js +0 -1
  24. package/ci/test-optimization-validation/redaction.js +0 -4
  25. package/ci/test-optimization-validation/report-writer.js +0 -16
  26. package/ci/test-optimization-validation/runner-command.js +0 -3
  27. package/ci/test-optimization-validation/runner-contract.js +0 -4
  28. package/ci/test-optimization-validation/safe-files.js +0 -1
  29. package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
  30. package/ci/test-optimization-validation/scenarios/ci-wiring.js +0 -1
  31. package/ci/test-optimization-validation/source-text.js +0 -3
  32. package/ci/vitest-no-worker-init-setup.mjs +41 -16
  33. package/index.d.ts +208 -0
  34. package/package.json +17 -16
  35. package/packages/datadog-esbuild/src/utils.js +0 -2
  36. package/packages/datadog-instrumentations/src/aerospike.js +28 -6
  37. package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +0 -2
  38. package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
  39. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +0 -2
  40. package/packages/datadog-instrumentations/src/console.js +97 -0
  41. package/packages/datadog-instrumentations/src/cucumber.js +77 -12
  42. package/packages/datadog-instrumentations/src/cypress-config.js +27 -38
  43. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +6 -0
  44. package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
  45. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -1
  46. package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
  47. package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -6
  48. package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +0 -3
  49. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
  50. package/packages/datadog-instrumentations/src/helpers/register.js +24 -0
  51. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +111 -26
  52. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +41 -0
  53. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -17
  54. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +55 -0
  55. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
  56. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +13 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +28 -3
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +20 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +0 -5
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
  63. package/packages/datadog-instrumentations/src/jest.js +165 -51
  64. package/packages/datadog-instrumentations/src/knex.js +0 -1
  65. package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
  66. package/packages/datadog-instrumentations/src/mariadb.js +0 -2
  67. package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
  68. package/packages/datadog-instrumentations/src/mocha/main.js +25 -26
  69. package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
  70. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
  71. package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
  72. package/packages/datadog-instrumentations/src/mysql2.js +0 -2
  73. package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
  74. package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
  75. package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
  76. package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
  77. package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
  78. package/packages/datadog-instrumentations/src/openai.js +51 -12
  79. package/packages/datadog-instrumentations/src/oracledb.js +9 -3
  80. package/packages/datadog-instrumentations/src/playwright-reporter.js +6 -20
  81. package/packages/datadog-instrumentations/src/playwright.js +280 -56
  82. package/packages/datadog-instrumentations/src/{azure-cosmos.js → postgres.js} +1 -1
  83. package/packages/datadog-instrumentations/src/router.js +0 -2
  84. package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
  85. package/packages/datadog-instrumentations/src/sequelize.js +0 -1
  86. package/packages/datadog-instrumentations/src/supabase.js +15 -0
  87. package/packages/datadog-instrumentations/src/undici.js +7 -3
  88. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
  89. package/packages/datadog-instrumentations/src/vitest-main.js +121 -30
  90. package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
  91. package/packages/datadog-instrumentations/src/vitest-worker.js +49 -13
  92. package/packages/datadog-instrumentations/src/webdriverio.js +44 -47
  93. package/packages/datadog-instrumentations/src/ws.js +41 -2
  94. package/packages/datadog-plugin-ai/src/utils.js +0 -2
  95. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
  96. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
  97. package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
  98. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +0 -1
  99. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
  100. package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
  101. package/packages/datadog-plugin-azure-durable-functions/src/index.js +0 -1
  102. package/packages/datadog-plugin-cucumber/src/index.js +9 -0
  103. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +211 -85
  104. package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
  105. package/packages/datadog-plugin-cypress/src/index.js +3 -1
  106. package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
  107. package/packages/datadog-plugin-cypress/src/support.js +52 -7
  108. package/packages/datadog-plugin-graphql/src/resolve-error.js +1 -2
  109. package/packages/datadog-plugin-graphql/src/utils.js +0 -5
  110. package/packages/datadog-plugin-jest/src/index.js +12 -0
  111. package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
  112. package/packages/datadog-plugin-mocha/src/index.js +38 -11
  113. package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
  114. package/packages/datadog-plugin-openai/src/index.js +16 -1
  115. package/packages/datadog-plugin-openai/src/realtime.js +144 -0
  116. package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
  117. package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
  118. package/packages/datadog-plugin-playwright/src/index.js +81 -9
  119. package/packages/datadog-plugin-postgres/src/index.js +167 -0
  120. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
  121. package/packages/datadog-plugin-redis/src/index.js +15 -1
  122. package/packages/datadog-plugin-supabase/src/error.js +18 -0
  123. package/packages/datadog-plugin-supabase/src/index.js +21 -0
  124. package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
  125. package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
  126. package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
  127. package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
  128. package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
  129. package/packages/datadog-plugin-supabase/src/url.js +17 -0
  130. package/packages/datadog-plugin-vitest/src/index.js +9 -0
  131. package/packages/datadog-plugin-ws/src/producer.js +1 -1
  132. package/packages/datadog-plugin-ws/src/util.js +0 -4
  133. package/packages/datadog-shimmer/src/shimmer.js +14 -10
  134. package/packages/datadog-turbopack/index.js +4 -7
  135. package/packages/datadog-turbopack/src/loader.js +6 -18
  136. package/packages/datadog-webpack/src/loader.js +0 -1
  137. package/packages/dd-trace/src/agent/info.js +5 -4
  138. package/packages/dd-trace/src/aiguard/client.js +2 -3
  139. package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
  140. package/packages/dd-trace/src/aiguard/index.js +2 -2
  141. package/packages/dd-trace/src/aiguard/integrations/index.js +1 -1
  142. package/packages/dd-trace/src/aiguard/integrations/openai.js +81 -7
  143. package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
  144. package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
  145. package/packages/dd-trace/src/aiguard/messages/utils.js +0 -1
  146. package/packages/dd-trace/src/aiguard/redaction.js +0 -1
  147. package/packages/dd-trace/src/aiguard/sdk.js +1 -1
  148. package/packages/dd-trace/src/appsec/activation.js +1 -1
  149. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
  150. package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
  151. package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
  152. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
  153. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
  155. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  157. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
  158. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
  159. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
  160. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
  161. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
  162. package/packages/dd-trace/src/appsec/index.js +2 -2
  163. package/packages/dd-trace/src/appsec/lambda.js +71 -2
  164. package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
  165. package/packages/dd-trace/src/appsec/remote_config.js +8 -6
  166. package/packages/dd-trace/src/appsec/reporter.js +10 -6
  167. package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
  168. package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
  169. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  170. package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
  171. package/packages/dd-trace/src/carrier.js +0 -5
  172. package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
  173. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
  174. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
  175. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
  176. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
  177. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
  178. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
  179. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
  180. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
  181. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
  182. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
  183. package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
  184. package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
  185. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
  186. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
  187. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
  188. package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
  189. package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
  190. package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
  191. package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
  192. package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
  193. package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
  194. package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
  195. package/packages/dd-trace/src/config/defaults.js +3 -2
  196. package/packages/dd-trace/src/config/generated-config-types.d.ts +88 -82
  197. package/packages/dd-trace/src/config/helper.js +0 -1
  198. package/packages/dd-trace/src/config/index.js +31 -30
  199. package/packages/dd-trace/src/config/parsers.js +34 -6
  200. package/packages/dd-trace/src/config/remote_config.js +25 -109
  201. package/packages/dd-trace/src/config/supported-configurations.json +150 -10
  202. package/packages/dd-trace/src/datastreams/encoding.js +0 -1
  203. package/packages/dd-trace/src/datastreams/pathway.js +0 -1
  204. package/packages/dd-trace/src/debugger/constants.js +10 -0
  205. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +62 -10
  206. package/packages/dd-trace/src/debugger/devtools_client/config.js +4 -1
  207. package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
  208. package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
  209. package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
  210. package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
  211. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +21 -8
  212. package/packages/dd-trace/src/debugger/devtools_client/send.js +41 -15
  213. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
  214. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
  215. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +5 -3
  216. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
  217. package/packages/dd-trace/src/debugger/devtools_client/status.js +21 -7
  218. package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
  219. package/packages/dd-trace/src/debugger/index.js +51 -3
  220. package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
  221. package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
  222. package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
  223. package/packages/dd-trace/src/dogstatsd.js +0 -23
  224. package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
  225. package/packages/dd-trace/src/encode/0.4.js +0 -7
  226. package/packages/dd-trace/src/encode/0.5.js +0 -2
  227. package/packages/dd-trace/src/encode/tags-processors.js +0 -1
  228. package/packages/dd-trace/src/evp_proxy/constants.js +2 -0
  229. package/packages/dd-trace/src/evp_proxy/direct.js +17 -13
  230. package/packages/dd-trace/src/evp_proxy/discovery.js +14 -11
  231. package/packages/dd-trace/src/evp_proxy/path.js +21 -9
  232. package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
  233. package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
  234. package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
  235. package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
  236. package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
  237. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  238. package/packages/dd-trace/src/exporters/common/url.js +33 -4
  239. package/packages/dd-trace/src/exporters/common/writer.js +0 -2
  240. package/packages/dd-trace/src/id.js +0 -11
  241. package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
  242. package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
  243. package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
  244. package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
  245. package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
  246. package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
  247. package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
  248. package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
  249. package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
  250. package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
  251. package/packages/dd-trace/src/llmobs/index.js +1 -3
  252. package/packages/dd-trace/src/llmobs/noop.js +10 -0
  253. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
  254. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
  255. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
  256. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
  257. package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
  258. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
  259. package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
  260. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
  261. package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
  262. package/packages/dd-trace/src/llmobs/prompts/manager.js +647 -0
  263. package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
  264. package/packages/dd-trace/src/llmobs/prompts/prompt.js +158 -0
  265. package/packages/dd-trace/src/llmobs/sdk.js +21 -6
  266. package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
  267. package/packages/dd-trace/src/llmobs/tagger.js +39 -11
  268. package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
  269. package/packages/dd-trace/src/llmobs/util.js +0 -34
  270. package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
  271. package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
  272. package/packages/dd-trace/src/log/channels.js +3 -0
  273. package/packages/dd-trace/src/log/index.js +23 -5
  274. package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
  275. package/packages/dd-trace/src/msgpack/chunk.js +0 -1
  276. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
  277. package/packages/dd-trace/src/openfeature/configuration_source.js +4 -1
  278. package/packages/dd-trace/src/openfeature/encoding.js +0 -2
  279. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
  280. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -3
  281. package/packages/dd-trace/src/openfeature/index.js +6 -6
  282. package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
  283. package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
  284. package/packages/dd-trace/src/openfeature/writers/base.js +90 -23
  285. package/packages/dd-trace/src/openfeature/writers/exposures.js +4 -5
  286. package/packages/dd-trace/src/openfeature/writers/util.js +104 -37
  287. package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
  288. package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
  289. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
  290. package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
  291. package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +0 -1
  292. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
  293. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
  294. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -14
  295. package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
  296. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +30 -13
  297. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
  298. package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
  299. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
  300. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
  301. package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
  302. package/packages/dd-trace/src/opentracing/span_context.js +0 -1
  303. package/packages/dd-trace/src/opentracing/tracer.js +3 -3
  304. package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
  305. package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
  306. package/packages/dd-trace/src/plugin_manager.js +27 -8
  307. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -2
  308. package/packages/dd-trace/src/plugins/database.js +2 -6
  309. package/packages/dd-trace/src/plugins/index.js +7 -0
  310. package/packages/dd-trace/src/plugins/plugin.js +0 -4
  311. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  312. package/packages/dd-trace/src/plugins/util/git.js +1 -3
  313. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
  314. package/packages/dd-trace/src/plugins/util/llm.js +0 -2
  315. package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
  316. package/packages/dd-trace/src/plugins/util/test.js +26 -20
  317. package/packages/dd-trace/src/plugins/util/url.js +0 -5
  318. package/packages/dd-trace/src/priority_sampler.js +0 -6
  319. package/packages/dd-trace/src/process-tags/index.js +0 -1
  320. package/packages/dd-trace/src/profiler.js +132 -35
  321. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
  322. package/packages/dd-trace/src/profiling/profiler.js +101 -41
  323. package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
  324. package/packages/dd-trace/src/propagation-hash/index.js +0 -1
  325. package/packages/dd-trace/src/proxy.js +23 -47
  326. package/packages/dd-trace/src/random_sampler.js +0 -4
  327. package/packages/dd-trace/src/rate_limiter.js +0 -4
  328. package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
  329. package/packages/dd-trace/src/remote_config/index.js +0 -1
  330. package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
  331. package/packages/dd-trace/src/sampler.js +0 -4
  332. package/packages/dd-trace/src/sampling_rule.js +0 -7
  333. package/packages/dd-trace/src/serverless/vercel.js +0 -1
  334. package/packages/dd-trace/src/serverless.js +0 -1
  335. package/packages/dd-trace/src/service-naming/index.js +0 -1
  336. package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
  337. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
  338. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
  339. package/packages/dd-trace/src/span_processor.js +2 -2
  340. package/packages/dd-trace/src/span_sampler.js +0 -1
  341. package/packages/dd-trace/src/standalone/product.js +2 -2
  342. package/packages/dd-trace/src/standalone/tracesource.js +0 -1
  343. package/packages/dd-trace/src/startup-log.js +1 -1
  344. package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
  345. package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
  346. package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
  347. package/packages/dd-trace/src/telemetry/metrics.js +0 -2
  348. package/packages/dd-trace/src/telemetry/send-data.js +2 -1
  349. package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
  350. package/packages/dd-trace/src/tracer.js +5 -4
  351. package/packages/dd-trace/src/util.js +13 -1
  352. package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
  353. package/packages/datadog-instrumentations/src/bullmq.js +0 -11
  354. package/packages/datadog-instrumentations/src/langchain.js +0 -7
  355. package/packages/datadog-instrumentations/src/langgraph.js +0 -7
  356. package/packages/datadog-instrumentations/src/mercurius.js +0 -11
@@ -14,6 +14,7 @@ const {
14
14
  hasEfdRetries,
15
15
  shouldSkipEfdRetry,
16
16
  } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
17
+ const { getDynamicAtrRetryCount } = require('../../dd-trace/src/ci-visibility/dynamic-atr-retries')
17
18
  const {
18
19
  parseAnnotations,
19
20
  getTestSuitePath,
@@ -65,8 +66,10 @@ const testPageGotoCh = channel('ci:playwright:test:page-goto')
65
66
 
66
67
  const dispatcherRunCh = tracingChannel('orchestrion:playwright:Dispatcher_run')
67
68
  const dispatcherCreateWorkerCh = tracingChannel('orchestrion:playwright:Dispatcher_createWorker')
69
+ const filterForShardCh = tracingChannel('orchestrion:playwright:filterForShard')
68
70
  const processHostStartRunnerCh = tracingChannel('orchestrion:playwright:ProcessHost_startRunner')
69
71
  const createRootSuiteCh = tracingChannel('orchestrion:playwright:createRootSuite')
72
+ const lastRunTestIdCh = tracingChannel('orchestrion:playwright:lastRunTestId')
70
73
  const artifactsRecorderScreenshotPathCh =
71
74
  tracingChannel('orchestrion:playwright:ArtifactsRecorder_createScreenshotAttachmentPath')
72
75
  const snapshotRecorderScreenshotPathCh = tracingChannel('orchestrion:playwright:SnapshotRecorder_createAttachmentPath')
@@ -74,6 +77,7 @@ const saveAutomaticVideoCh = tracingChannel('orchestrion:playwright:saveAutomati
74
77
  const pageGotoCh = tracingChannel('orchestrion:playwright-core:Page_goto')
75
78
 
76
79
  const testToCtx = new WeakMap()
80
+ const originalTestIdsByRetry = new WeakMap()
77
81
  const testSuiteToCtx = new Map()
78
82
  const testSuiteToTestStatuses = new Map()
79
83
  const testSuiteToErrors = new Map()
@@ -112,6 +116,8 @@ let isEarlyFlakeDetectionFaulty = false
112
116
  let earlyFlakeDetectionFaultyThreshold = 0
113
117
  let isFlakyTestRetriesEnabled = false
114
118
  let flakyTestRetriesCount = 0
119
+ let isDynamicAtrEnabled = false
120
+ let dynamicAtrBuckets
115
121
  let knownTests = {}
116
122
  let isTestManagementTestsEnabled = false
117
123
  let testManagementAttemptToFixRetries = 0
@@ -121,6 +127,9 @@ let modifiedFiles = {}
121
127
  let playwrightRunSummary
122
128
  let recordedTestOptimizationExecutions = new Set()
123
129
  let testsReportedInGenerateSummary = new Set()
130
+ let reportedTestExecutions = new WeakMap()
131
+ let hasTestsAssignedToShard = false
132
+ let hasTestsBeforeSharding = false
124
133
  const newTestsWithDynamicNames = new Set()
125
134
  const attemptToFixExecutions = new Map()
126
135
  const loggedAttemptToFixTests = new Set()
@@ -131,6 +140,8 @@ const efdRetryTestsById = new Map()
131
140
  const efdScheduledOriginalTestKeys = new Set()
132
141
  const efdStartedOriginalTestKeys = new Set()
133
142
  const efdSlowAbortedTests = new Set()
143
+ const dynamicAtrRetryCountByTestKey = new Map()
144
+ const automaticRetryProjects = new Set()
134
145
  const ddPropertiesByTestId = new Map()
135
146
  const ddPropertiesRequestsByTestId = new Map()
136
147
  const disabledTestIds = new Set()
@@ -159,7 +170,6 @@ const automaticFailureVideoPaths = new Set()
159
170
  * Returns whether Playwright's internal screenshot recorder created an attachment.
160
171
  *
161
172
  * @param {object} attachment - Playwright attachment payload
162
- * @returns {boolean}
163
173
  */
164
174
  function isAutomaticFailureScreenshotAttachment (attachment) {
165
175
  return typeof attachment?.path === 'string' && automaticFailureScreenshotPaths.delete(attachment.path)
@@ -169,7 +179,6 @@ function isAutomaticFailureScreenshotAttachment (attachment) {
169
179
  * Returns whether Playwright's internal video recorder created an attachment.
170
180
  *
171
181
  * @param {object} attachment - Playwright attachment payload
172
- * @returns {boolean}
173
182
  */
174
183
  function isAutomaticFailureVideoAttachment (attachment) {
175
184
  return typeof attachment?.path === 'string' && automaticFailureVideoPaths.delete(attachment.path)
@@ -230,7 +239,6 @@ function getTestRepeatEachKey (test) {
230
239
 
231
240
  /**
232
241
  * @param {object} test
233
- * @returns {string}
234
242
  */
235
243
  function getTestEfdKey (test) {
236
244
  const projectKey = getTestProjectKey(test)
@@ -263,9 +271,6 @@ function registerEfdRetryTest (test) {
263
271
  })
264
272
  }
265
273
 
266
- /**
267
- * @returns {boolean}
268
- */
269
274
  function shouldRunEarlyFlakeDetection () {
270
275
  return isEarlyFlakeDetectionEnabled && hasEfdRetries(earlyFlakeDetectionRetryPolicy)
271
276
  }
@@ -389,7 +394,6 @@ function sendDdPropertiesToWorkerWhenAvailable (workerProcess, testId) {
389
394
 
390
395
  /**
391
396
  * @param {object} test
392
- * @returns {boolean}
393
397
  */
394
398
  function shouldRequestEfdRetryCount (test) {
395
399
  // The main process remains the source of truth. repeatEachIndex is only used as
@@ -473,6 +477,7 @@ function deepCloneSuite (suite, filterTest, tags = [], configureCopiedTest) {
473
477
  } else {
474
478
  if (filterTest(entry)) {
475
479
  const copiedTest = entry._clone()
480
+ originalTestIdsByRetry.set(copiedTest, originalTestIdsByRetry.get(entry) ?? entry.id)
476
481
  if (configureCopiedTest) {
477
482
  configureCopiedTest(copiedTest, entry)
478
483
  }
@@ -519,6 +524,8 @@ function getTestsBySuiteFromTestsById (testsById) {
519
524
  }
520
525
 
521
526
  function getPlaywrightConfig (playwrightRunner) {
527
+ if (!playwrightRunner) return {}
528
+
522
529
  try {
523
530
  return playwrightRunner._configLoader.fullConfig()
524
531
  } catch {
@@ -558,7 +565,6 @@ function getProjectsFromRunner (runner, configArg) {
558
565
  * Returns whether at least one Playwright project captures automatic screenshots for failed tests.
559
566
  *
560
567
  * @param {Array<object>} projects - Playwright projects with resolved use options
561
- * @returns {boolean} Whether failure screenshot capture is enabled
562
568
  */
563
569
  function isFailureScreenshotCaptureEnabled (projects) {
564
570
  for (const project of projects) {
@@ -575,7 +581,6 @@ function isFailureScreenshotCaptureEnabled (projects) {
575
581
  * Returns whether at least one Playwright project records videos that can be retained for failures.
576
582
  *
577
583
  * @param {Array<object>} projects - Playwright projects with resolved use options
578
- * @returns {boolean} Whether video capture is enabled
579
584
  */
580
585
  function isFailureVideoCaptureEnabled (projects) {
581
586
  for (const project of projects) {
@@ -599,14 +604,19 @@ function getProjectsFromDispatcher (dispatcher) {
599
604
  return dispatcher._loader?.fullConfig()?.projects
600
605
  }
601
606
 
602
- function getBrowserNameFromProjects (projects, test) {
607
+ /**
608
+ * Resolves the configured project by Playwright's unique ID or legacy index.
609
+ * @param {object[]} projects
610
+ * @param {object} test
611
+ */
612
+ function getTestProject (projects, test) {
603
613
  if (!projects || !test) {
604
614
  return null
605
615
  }
606
616
  const { _projectIndex, _projectId: testProjectId } = test
607
617
 
608
618
  if (_projectIndex !== undefined) {
609
- return projects[_projectIndex]?.name
619
+ return projects[_projectIndex]
610
620
  }
611
621
 
612
622
  return projects.find(({ __projectId, _id, name }) => {
@@ -617,7 +627,12 @@ function getBrowserNameFromProjects (projects, test) {
617
627
  return _id === testProjectId
618
628
  }
619
629
  return name === testProjectId
620
- })?.name
630
+ })
631
+ }
632
+
633
+ function getBrowserNameFromProjects (projects, test) {
634
+ const project = getTestProject(projects, test)
635
+ return project && project.name
621
636
  }
622
637
 
623
638
  function formatTestHookError (error, hookType, isTimeout) {
@@ -671,8 +686,8 @@ function getTestByTestId (dispatcher, testId) {
671
686
  // Inspired by https://github.com/microsoft/playwright/blob/2b77ed4d7aafa85a600caa0b0d101b72c8437eeb/packages/playwright/src/reporters/base.ts#L293
672
687
  // We can't use test.outcome() directly because it's set on follow up handlers:
673
688
  // our `testEndHandler` is called before the outcome is set.
674
- function testWillRetry (test, testStatus) {
675
- return testStatus === 'fail' && test.results.length <= test.retries
689
+ function testWillRetry (test, status, expectedStatus = test.expectedStatus) {
690
+ return status !== 'skipped' && status !== expectedStatus && test.results.length <= test.retries
676
691
  }
677
692
 
678
693
  function getFinalStatus ({
@@ -682,7 +697,6 @@ function getFinalStatus ({
682
697
  isAtrRetry,
683
698
  isEfdManagedTest,
684
699
  isAttemptToFix,
685
- hasFailedAllRetries,
686
700
  hasFailedAttemptToFixRetries,
687
701
  hasPassedAnyEfdAttempt,
688
702
  testStatus,
@@ -694,7 +708,7 @@ function getFinalStatus ({
694
708
  return 'skip'
695
709
  }
696
710
  if (isAtrRetry) {
697
- return hasFailedAllRetries ? 'fail' : 'pass'
711
+ return testStatus
698
712
  }
699
713
  if (isEfdManagedTest) {
700
714
  return hasPassedAnyEfdAttempt ? 'pass' : 'fail'
@@ -705,6 +719,17 @@ function getFinalStatus ({
705
719
  return testStatus
706
720
  }
707
721
 
722
+ /**
723
+ * Reports whether another test in the serial group can trigger this test to run again.
724
+ * @param {object} test
725
+ */
726
+ function isSerialTest (test) {
727
+ for (let suite = test.parent; suite; suite = suite.parent) {
728
+ if (suite._parallelMode === 'serial') return true
729
+ }
730
+ return false
731
+ }
732
+
708
733
  function getTestFullname (test) {
709
734
  let parent = test.parent
710
735
  const names = [test.title]
@@ -789,7 +814,6 @@ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
789
814
  *
790
815
  * @param {object} test
791
816
  * @param {string} testSuiteAbsolutePath
792
- * @returns {void}
793
817
  */
794
818
  function recordSkippedTestOptimizationExecution (test, testSuiteAbsolutePath) {
795
819
  if (recordedTestOptimizationExecutions.has(test) ||
@@ -852,6 +876,37 @@ function finishTestSuiteIfDone (testSuiteAbsolutePath, projects) {
852
876
  }
853
877
  }
854
878
 
879
+ /**
880
+ * Checks whether a test inherits the retry limit assigned by Test Optimization.
881
+ * @param {object} test
882
+ * @param {object[]} projects
883
+ */
884
+ function hasAutomaticRetries (test, projects) {
885
+ if (!automaticRetryProjects.has(getTestProject(projects, test))) return false
886
+ for (let suite = test.parent; suite; suite = suite.parent) {
887
+ if (suite._retries !== undefined) return false
888
+ }
889
+ return true
890
+ }
891
+
892
+ /**
893
+ * Records a completed test in its suite and removes it from pending executions.
894
+ * @param {object} test
895
+ * @param {string} testStatus
896
+ * @param {object} [error]
897
+ */
898
+ function recordFinalTestStatus (test, testStatus, error) {
899
+ const testSuiteAbsolutePath = test._requireFile
900
+ if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
901
+ testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
902
+ } else {
903
+ testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
904
+ }
905
+ if (error) addErrorToTestSuite(testSuiteAbsolutePath, error)
906
+ remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
907
+ .filter(currentTest => currentTest !== test)
908
+ }
909
+
855
910
  function testEndHandler ({
856
911
  test,
857
912
  annotations,
@@ -860,6 +915,10 @@ function testEndHandler ({
860
915
  isTimeout,
861
916
  shouldCreateTestSpan,
862
917
  projects,
918
+ testDuration,
919
+ testResultStatus,
920
+ expectedStatus = test.expectedStatus,
921
+ hasNonRetriableError,
863
922
  }) {
864
923
  const {
865
924
  _requireFile: testSuiteAbsolutePath,
@@ -892,19 +951,23 @@ function testEndHandler ({
892
951
 
893
952
  const isEfdManagedTest = isTestEfdManaged(test)
894
953
  const testFqn = getTestFullyQualifiedName(test)
895
- const testStatusKey = isEfdManagedTest ? getTestEfdKey(test) : testFqn
954
+ // Dynamic ATR budgets and retry status must be isolated per Playwright project.
955
+ const testStatusKey = (isEfdManagedTest || isDynamicAtrEnabled) ? getTestEfdKey(test) : testFqn
896
956
  const testStatuses = testsToTestStatuses.get(testStatusKey) || []
897
957
 
898
958
  if (testStatuses.length === 0) {
899
- testsToTestStatuses.set(testStatusKey, [testStatus])
959
+ testsToTestStatuses.set(testStatusKey, testStatuses)
900
960
  if (test._ddIsNew && DYNAMIC_NAME_RE.test(getTestFullname(test))) {
901
961
  newTestsWithDynamicNames.add(`${getTestSuitePath(test._requireFile, rootDir)} › ${getTestFullname(test)}`)
902
962
  }
903
- } else {
904
- testStatuses.push(testStatus)
963
+ }
964
+ testStatuses.push(testStatus)
965
+ if (testStatus === 'pass' || testStatus === 'fail') {
966
+ reportedTestExecutions.set(test, { status: testStatus, error })
905
967
  }
906
968
 
907
969
  const testEfdKey = getTestEfdKey(test)
970
+ const dynamicAtrTestKey = testEfdKey
908
971
  if (isEfdManagedTest && !test._ddIsEfdRetry && !efdRetryCountByTestKey.has(testEfdKey)) {
909
972
  const testResult = results.at(-1)
910
973
  const duration = testResult?.duration > 0 ? testResult.duration : performance.now() - test._ddStartTime
@@ -916,6 +979,23 @@ function testEndHandler ({
916
979
  }
917
980
 
918
981
  const testProperties = getTestProperties(test)
982
+ if (
983
+ isDynamicAtrEnabled &&
984
+ isFlakyTestRetriesEnabled &&
985
+ !testProperties.attemptToFix &&
986
+ !test._ddIsEfdRetry &&
987
+ !isEfdManagedTest &&
988
+ hasAutomaticRetries(test, projects) &&
989
+ !dynamicAtrRetryCountByTestKey.has(dynamicAtrTestKey)
990
+ ) {
991
+ const testResult = results.at(-1)
992
+ const duration = testDuration ??
993
+ (testResult?.duration > 0 ? testResult.duration : performance.now() - test._ddStartTime)
994
+ const retryCount = getDynamicAtrRetryCount(duration, earlyFlakeDetectionRetryPolicy, dynamicAtrBuckets)
995
+ dynamicAtrRetryCountByTestKey.set(dynamicAtrTestKey, retryCount)
996
+ // Serial groups may skip this test before its first actual execution.
997
+ test.retries = (testResult?.retry ?? 0) + retryCount
998
+ }
919
999
  const hasRecordedTestOptimizationExecution = recordedTestOptimizationExecutions.has(test)
920
1000
 
921
1001
  if (!hasRecordedTestOptimizationExecution) {
@@ -968,34 +1048,40 @@ function testEndHandler ({
968
1048
  test._ddHasFailedAllRetries = true
969
1049
  }
970
1050
 
971
- // ATR: set _ddHasFailedAllRetries when all auto test retries were exhausted and every attempt failed
1051
+ const willRetry = testWillRetry(test, testResultStatus, expectedStatus)
1052
+
1053
+ // ATR: use the effective native limit for tests with explicit Playwright retries.
1054
+ const atrRetryCount = isDynamicAtrEnabled
1055
+ ? dynamicAtrRetryCountByTestKey.get(dynamicAtrTestKey) ?? test.retries
1056
+ : flakyTestRetriesCount
972
1057
  if (isFlakyTestRetriesEnabled && !testProperties.attemptToFix && !test._ddIsEfdRetry &&
973
1058
  !(test._ddIsNew || test._ddIsModified) &&
974
- flakyTestRetriesCount != null && flakyTestRetriesCount > 0 &&
975
- testStatuses.length === flakyTestRetriesCount + 1 &&
1059
+ atrRetryCount != null && atrRetryCount > 0 &&
1060
+ !willRetry && testResultStatus !== expectedStatus &&
976
1061
  testStatuses.every(status => status === 'fail')) {
977
1062
  test._ddHasFailedAllRetries = true
978
1063
  }
979
1064
 
980
- const willRetry = testWillRetry(test, testStatus)
981
-
982
- // this handles tests that do not go through the worker process (because they're skipped)
1065
+ // Legacy Playwright also creates executed test spans in the main process.
983
1066
  if (shouldCreateTestSpan) {
984
1067
  const testResult = results.at(-1)
985
1068
  const testCtx = testToCtx.get(test)
1069
+ const retryTestId = testStatus !== 'skip' && !isEfdManagedTest &&
1070
+ !test._ddIsAttemptToFix && test.retries > 0
1071
+ ? test.id ?? test._id
1072
+ : undefined
986
1073
  const isAtrRetry = testResult?.retry > 0 &&
987
1074
  isFlakyTestRetriesEnabled &&
988
1075
  !test._ddIsAttemptToFix &&
989
1076
  !test._ddIsEfdRetry
990
1077
 
991
1078
  const finalStatus = getFinalStatus({
992
- isFinalExecution: !willRetry,
1079
+ isFinalExecution: retryTestId !== undefined || !willRetry,
993
1080
  isDisabled: test._ddIsDisabled,
994
1081
  isQuarantined: test._ddIsQuarantined,
995
1082
  isAtrRetry,
996
1083
  isEfdManagedTest,
997
1084
  isAttemptToFix: test._ddIsAttemptToFix,
998
- hasFailedAllRetries: test._ddHasFailedAllRetries,
999
1085
  hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
1000
1086
  hasPassedAnyEfdAttempt: testStatuses.includes('pass'),
1001
1087
  testStatus,
@@ -1005,6 +1091,8 @@ function testEndHandler ({
1005
1091
  if (testCtx) {
1006
1092
  testFinishCh.publish({
1007
1093
  testStatus,
1094
+ isExpectedFailure: testResultStatus === 'failed' && expectedStatus === 'failed',
1095
+ hasNonRetriableError,
1008
1096
  steps: testResult?.steps || [],
1009
1097
  isRetry: testResult?.retry > 0,
1010
1098
  error,
@@ -1021,28 +1109,15 @@ function testEndHandler ({
1021
1109
  isAtrRetry,
1022
1110
  isModified: test._ddIsModified,
1023
1111
  finalStatus,
1112
+ retryTestId,
1113
+ deferFinalStatus: willRetry,
1024
1114
  earlyFlakeAbortReason: efdSlowAbortedTests.has(testEfdKey) ? 'slow' : undefined,
1025
1115
  ...testCtx.currentStore,
1026
1116
  })
1027
1117
  }
1028
1118
  }
1029
1119
 
1030
- if (!willRetry) {
1031
- if (testSuiteToTestStatuses.has(testSuiteAbsolutePath)) {
1032
- testSuiteToTestStatuses.get(testSuiteAbsolutePath).push(testStatus)
1033
- } else {
1034
- testSuiteToTestStatuses.set(testSuiteAbsolutePath, [testStatus])
1035
- }
1036
-
1037
- if (error) {
1038
- addErrorToTestSuite(testSuiteAbsolutePath, error)
1039
- }
1040
- }
1041
-
1042
- if (!willRetry) {
1043
- remainingTestsByFile[testSuiteAbsolutePath] = remainingTestsByFile[testSuiteAbsolutePath]
1044
- .filter(currentTest => currentTest !== test)
1045
- }
1120
+ if (!willRetry) recordFinalTestStatus(test, testStatus, error)
1046
1121
 
1047
1122
  finishTestSuiteIfDone(testSuiteAbsolutePath, projects)
1048
1123
  }
@@ -1050,10 +1125,35 @@ function testEndHandler ({
1050
1125
  function dispatcherRunWrapper (run) {
1051
1126
  return function (...args) {
1052
1127
  remainingTestsByFile = getTestsBySuiteFromTestsById(this._testById)
1128
+ for (const tests of Object.values(remainingTestsByFile)) {
1129
+ if (tests.length > 0) {
1130
+ hasTestsAssignedToShard = true
1131
+ break
1132
+ }
1133
+ }
1053
1134
  return run.apply(this, args)
1054
1135
  }
1055
1136
  }
1056
1137
 
1138
+ function recordTestsBeforeSharding (testGroups) {
1139
+ hasTestsBeforeSharding = testGroups.some(group => group.tests.length > 0)
1140
+ }
1141
+
1142
+ function testGroupsHook (testGroupsPackage) {
1143
+ const filterForShard = testGroupsPackage.filterForShard
1144
+ const wrappedFilterForShard = function (...args) {
1145
+ recordTestsBeforeSharding(args.at(-1))
1146
+ return filterForShard.apply(this, args)
1147
+ }
1148
+
1149
+ return new Proxy(testGroupsPackage, {
1150
+ get (target, prop, receiver) {
1151
+ if (prop === 'filterForShard') return wrappedFilterForShard
1152
+ return Reflect.get(target, prop, receiver)
1153
+ },
1154
+ })
1155
+ }
1156
+
1057
1157
  function deferEfdRetryGroups (testGroups) {
1058
1158
  const groupsWithOriginalTests = []
1059
1159
  const efdRetryOnlyGroups = []
@@ -1090,6 +1190,13 @@ function deferEfdRetryGroups (testGroups) {
1090
1190
  function prepareDispatcherRun (dispatcher, args) {
1091
1191
  let testGroups = args[0]
1092
1192
 
1193
+ for (const group of testGroups) {
1194
+ if (group.tests.length > 0) {
1195
+ hasTestsAssignedToShard = true
1196
+ break
1197
+ }
1198
+ }
1199
+
1093
1200
  // Filter out disabled tests from testGroups before they get scheduled,
1094
1201
  // unless they have attemptToFix (in which case they should still run and be retried)
1095
1202
  if (isTestManagementTestsEnabled) {
@@ -1177,7 +1284,7 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1177
1284
  videos.push(attachment)
1178
1285
  }
1179
1286
  })
1180
- worker.on('testEnd', ({ testId, status, errors, annotations }) => {
1287
+ worker.on('testEnd', ({ testId, status, errors, annotations, duration, expectedStatus, hasNonRetriableError }) => {
1181
1288
  const test = getTestByTestId(dispatcher, testId)
1182
1289
  if (!test) return
1183
1290
 
@@ -1196,6 +1303,10 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1196
1303
  isTimeout,
1197
1304
  shouldCreateTestSpan,
1198
1305
  projects,
1306
+ testDuration: duration,
1307
+ testResultStatus: status,
1308
+ expectedStatus,
1309
+ hasNonRetriableError,
1199
1310
  }
1200
1311
  )
1201
1312
  const testResult = test.results.at(-1)
@@ -1241,10 +1352,16 @@ function onDispatcherCreateWorker (dispatcher, worker) {
1241
1352
  } else if (test._ddIsAttemptToFix) {
1242
1353
  isFinalExecution = !!(test._ddHasPassedAttemptToFixRetries || test._ddHasFailedAttemptToFixRetries)
1243
1354
  } else {
1244
- isFinalExecution = !testWillRetry(test, testStatus)
1355
+ isFinalExecution = !testWillRetry(test, status, expectedStatus)
1245
1356
  }
1246
1357
 
1358
+ const retryTestId = !isEfdManagedTest && !test._ddIsAttemptToFix && test.retries > 0 ? test.id : undefined
1359
+ const deferFinalStatus = retryTestId !== undefined &&
1360
+ (!isFinalExecution || (isSerialTest(test) && test.results.length <= test.retries))
1361
+
1247
1362
  const ddProperties = {
1363
+ _ddRetryTestId: retryTestId,
1364
+ _ddDeferFinalStatus: deferFinalStatus,
1248
1365
  _ddIsDisabled: test._ddIsDisabled,
1249
1366
  _ddIsQuarantined: test._ddIsQuarantined,
1250
1367
  _ddIsAttemptToFix: test._ddIsAttemptToFix,
@@ -1295,6 +1412,9 @@ function dispatcherHook (dispatcherExport) {
1295
1412
  test,
1296
1413
  annotations: params.annotations,
1297
1414
  testStatus: STATUS_TO_TEST_STATUS[testResult.status],
1415
+ testResultStatus: testResult.status,
1416
+ expectedStatus: params.expectedStatus,
1417
+ hasNonRetriableError: params.hasNonRetriableError,
1298
1418
  error: testResult.error,
1299
1419
  isTimeout,
1300
1420
  shouldCreateTestSpan: true,
@@ -1320,10 +1440,33 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
1320
1440
 
1321
1441
  function runAllTestsWrapper (runAllTests, playwrightVersion) {
1322
1442
  // Config parameter is only available from >=1.55.0
1323
- return async function (config) {
1443
+ return async function (config, options) {
1444
+ // A later run must not inherit ATR settings when configuration fails or the plugin is disabled.
1445
+ isFlakyTestRetriesEnabled = false
1446
+ flakyTestRetriesCount = 0
1447
+ isDynamicAtrEnabled = false
1448
+ dynamicAtrBuckets = undefined
1449
+ if (!libraryConfigurationCh.hasSubscribers) {
1450
+ // Instrumentation hooks still run when the plugin is disabled between runs.
1451
+ isKnownTestsEnabled = false
1452
+ isEarlyFlakeDetectionEnabled = false
1453
+ isTestManagementTestsEnabled = false
1454
+ isImpactedTestsEnabled = false
1455
+ knownTests = {}
1456
+ testManagementTests = {}
1457
+ modifiedFiles = {}
1458
+ return runAllTests.apply(this, arguments)
1459
+ }
1460
+
1461
+ testsToTestStatuses.clear()
1462
+ reportedTestExecutions = new WeakMap()
1463
+ dynamicAtrRetryCountByTestKey.clear()
1464
+ automaticRetryProjects.clear()
1324
1465
  reporterError = undefined
1325
1466
  hasReporterError = false
1326
1467
  playwrightRunSummary = undefined
1468
+ hasTestsAssignedToShard = false
1469
+ hasTestsBeforeSharding = false
1327
1470
  let restoreReporterConsoleError
1328
1471
  if (satisfies(playwrightVersion, '>=1.60.0') && config?.config) {
1329
1472
  const DatadogPlaywrightReporter = require('./playwright-reporter')
@@ -1333,6 +1476,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1333
1476
  config.config.reporter.unshift([require.resolve('./playwright-reporter')])
1334
1477
  }
1335
1478
  }
1479
+ const runnerConfig = getPlaywrightConfig(this)
1480
+ const playwrightConfig = config?.config || runnerConfig.config || runnerConfig
1336
1481
  rootDir = getRootDir(this, config)
1337
1482
  const projects = getProjectsFromRunner(this, config)
1338
1483
  const isFailureScreenshotEnabled = isFailureScreenshotCaptureEnabled(projects)
@@ -1361,6 +1506,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1361
1506
  earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
1362
1507
  isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
1363
1508
  flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
1509
+ isDynamicAtrEnabled = libraryConfig.isDynamicAtrEnabled
1510
+ dynamicAtrBuckets = libraryConfig.dynamicAtrBuckets
1364
1511
  isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
1365
1512
  testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
1366
1513
  isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
@@ -1447,11 +1594,23 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1447
1594
  // ATR and `--retries` are now compatible with Test Management.
1448
1595
  // Test Management tests have their retries set to 0 at the test level,
1449
1596
  // preventing them from being retried by ATR or `--retries`.
1450
- const shouldSetATRRetries = isFlakyTestRetriesEnabled && flakyTestRetriesCount > 0
1597
+ const shouldSetATRRetries = isFlakyTestRetriesEnabled &&
1598
+ (isDynamicAtrEnabled || flakyTestRetriesCount > 0)
1599
+ const projectsWithAutomaticRetries = []
1451
1600
  if (shouldSetATRRetries) {
1601
+ // Dynamic ATR starts at the maximum budget, then narrows each test after
1602
+ // its initial duration is known.
1603
+ const maximumDynamicAtrRetries = dynamicAtrBuckets
1604
+ ? Math.max(...dynamicAtrBuckets)
1605
+ : earlyFlakeDetectionRetryPolicy.schedulingRetryCount
1606
+ const atrRetries = isDynamicAtrEnabled
1607
+ ? Math.max(1, maximumDynamicAtrRetries)
1608
+ : flakyTestRetriesCount
1452
1609
  for (const project of projects) {
1453
1610
  if (project.retries === 0) { // Only if it hasn't been set by the user
1454
- project.retries = flakyTestRetriesCount
1611
+ projectsWithAutomaticRetries.push(project)
1612
+ automaticRetryProjects.add(project)
1613
+ project.retries = atrRetries
1455
1614
  }
1456
1615
  }
1457
1616
  }
@@ -1475,6 +1634,9 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1475
1634
  hasReporterError = false
1476
1635
  throw error
1477
1636
  } finally {
1637
+ for (const project of projectsWithAutomaticRetries) {
1638
+ project.retries = 0
1639
+ }
1478
1640
  restoreReporterConsoleError?.()
1479
1641
  }
1480
1642
 
@@ -1486,6 +1648,14 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1486
1648
  // there were tests that did not go through `testBegin` or `testEnd`,
1487
1649
  // because they were skipped
1488
1650
  for (const test of tests) {
1651
+ const lastExecution = reportedTestExecutions.get(test)
1652
+ if (lastExecution) {
1653
+ // Preserve a reported execution whose retry was canceled. Playwright can
1654
+ // also synthesize failed results after hook errors without emitting testEnd.
1655
+ recordFinalTestStatus(test, lastExecution.status, lastExecution.error)
1656
+ finishTestSuiteIfDone(test._requireFile, projects)
1657
+ continue
1658
+ }
1489
1659
  const alreadyReported = testsReportedInGenerateSummary.has(test)
1490
1660
  const browser = getBrowserNameFromProjects(projects, test)
1491
1661
  testBeginHandler(test, browser, !alreadyReported)
@@ -1493,6 +1663,7 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1493
1663
  test,
1494
1664
  annotations: [],
1495
1665
  testStatus: 'skip',
1666
+ testResultStatus: 'skipped',
1496
1667
  error: null,
1497
1668
  isTimeout: false,
1498
1669
  shouldCreateTestSpan: !alreadyReported,
@@ -1520,8 +1691,30 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1520
1691
  const finalStatus = hasReporterError
1521
1692
  ? 'fail'
1522
1693
  : (preventedToFail ? 'pass' : STATUS_TO_TEST_STATUS[sessionStatus])
1694
+ const isTestDiscovery = finalStatus === 'pass' &&
1695
+ Boolean(
1696
+ config?.listOnly ||
1697
+ config?.cliListOnly ||
1698
+ runnerConfig.cliListOnly ||
1699
+ runnerConfig._internal?.listOnly ||
1700
+ options?.listMode
1701
+ )
1702
+ const isEmptyShard = Boolean(playwrightConfig.shard) &&
1703
+ hasTestsBeforeSharding &&
1704
+ !hasTestsAssignedToShard &&
1705
+ testsReportedInGenerateSummary.size === 0
1706
+ const hasExecutedTests = [...testsToTestStatuses.values()].some(statuses =>
1707
+ statuses.some(status => status !== 'skip')
1708
+ )
1709
+ const hasSkippedTests = testsToTestStatuses.size > 0 || testsReportedInGenerateSummary.size > 0
1710
+ const testSessionEmptyReason = finalStatus === 'pass' && !hasExecutedTests
1711
+ ? (isTestDiscovery
1712
+ ? 'test_discovery'
1713
+ : isEmptyShard ? 'zero_test_shard' : hasSkippedTests ? 'all_tests_skipped' : 'zero_tests')
1714
+ : undefined
1523
1715
  await getChannelPromise(testSessionFinishCh, {
1524
- status: finalStatus,
1716
+ status: testSessionEmptyReason ? 'skip' : finalStatus,
1717
+ testSessionEmptyReason,
1525
1718
  error: finalizationError,
1526
1719
  isEarlyFlakeDetectionEnabled,
1527
1720
  isEarlyFlakeDetectionFaulty,
@@ -1537,6 +1730,8 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1537
1730
  playwrightRunSummary = undefined
1538
1731
  recordedTestOptimizationExecutions = new Set()
1539
1732
  testsReportedInGenerateSummary = new Set()
1733
+ hasTestsAssignedToShard = false
1734
+ hasTestsBeforeSharding = false
1540
1735
  efdManagedTestKeys.clear()
1541
1736
  efdRetryCountByTestKey.clear()
1542
1737
  efdRetryCountRequestsByTestKey.clear()
@@ -1693,6 +1888,12 @@ dispatcherCreateWorkerCh.subscribe({
1693
1888
  },
1694
1889
  })
1695
1890
 
1891
+ filterForShardCh.subscribe({
1892
+ start (ctx) {
1893
+ recordTestsBeforeSharding(ctx.arguments.at(-1))
1894
+ },
1895
+ })
1896
+
1696
1897
  processHostStartRunnerCh.subscribe({
1697
1898
  start (ctx) {
1698
1899
  prepareProcessHostStartRunner(ctx.self)
@@ -1722,6 +1923,14 @@ pageGotoCh.subscribe({
1722
1923
  },
1723
1924
  })
1724
1925
 
1926
+ // Retry clones exist only after discovery, so persist their original IDs for --last-failed.
1927
+ lastRunTestIdCh.subscribe({
1928
+ end (ctx) {
1929
+ const originalId = originalTestIdsByRetry.get(ctx.arguments[0])
1930
+ if (originalId !== undefined) ctx.result = originalId
1931
+ },
1932
+ })
1933
+
1725
1934
  reporterErrorCh.subscribe((error) => {
1726
1935
  recordReporterError(error)
1727
1936
  })
@@ -1734,7 +1943,6 @@ reporterRunSummaryCh.subscribe((runSummary) => {
1734
1943
  * Records a reporter failure even when the reporter throws a falsy value.
1735
1944
  *
1736
1945
  * @param {unknown} error
1737
- * @returns {void}
1738
1946
  */
1739
1947
  function recordReporterError (error) {
1740
1948
  if (hasReporterError) return
@@ -1756,7 +1964,6 @@ function recordReporterError (error) {
1756
1964
  * Records a path created by Playwright's automatic screenshot recorder.
1757
1965
  *
1758
1966
  * @param {object} ctx - Orchestrion context
1759
- * @returns {void}
1760
1967
  */
1761
1968
  function recordAutomaticFailureScreenshotPath (ctx) {
1762
1969
  if (isFailureScreenshotUploadEnabled &&
@@ -1770,7 +1977,6 @@ function recordAutomaticFailureScreenshotPath (ctx) {
1770
1977
  * Records only the destination used by Playwright's automatic video recorder.
1771
1978
  *
1772
1979
  * @param {object} ctx - Orchestrion context
1773
- * @returns {void}
1774
1980
  */
1775
1981
  function recordAutomaticFailureVideoPath (ctx) {
1776
1982
  const video = ctx.arguments?.[0]
@@ -1795,6 +2001,12 @@ snapshotRecorderScreenshotPathCh.subscribe({ end: recordAutomaticFailureScreensh
1795
2001
  saveAutomaticVideoCh.subscribe({ start: recordAutomaticFailureVideoPath })
1796
2002
 
1797
2003
  if (DD_MAJOR < 6) { // <1.38.0 is only supported up to version 5
2004
+ tracingChannel('orchestrion:@playwright/test:Multiplexer_onError').subscribe({
2005
+ start (ctx) {
2006
+ recordReporterError(ctx.arguments[0])
2007
+ },
2008
+ })
2009
+
1798
2010
  addHook({
1799
2011
  name: '@playwright/test',
1800
2012
  file: 'lib/runner.js',
@@ -1868,6 +2080,12 @@ addHook({
1868
2080
  versions: ['>=1.38.0 <1.60.0'],
1869
2081
  }, (dispatcher) => dispatcherHookNew(dispatcher, dispatcherRunWrapperNew))
1870
2082
 
2083
+ addHook({
2084
+ name: 'playwright',
2085
+ file: 'lib/runner/testGroups.js',
2086
+ versions: ['>=1.38.0 <1.60.0'],
2087
+ }, testGroupsHook)
2088
+
1871
2089
  addHook({
1872
2090
  name: 'playwright',
1873
2091
  file: 'lib/common/suiteUtils.js',
@@ -2460,14 +2678,16 @@ function instrumentWorkerMainMethods (workerMain) {
2460
2678
  })
2461
2679
  await Promise.race([ddPropertiesPromise, ddPropertiesTimeoutPromise])
2462
2680
 
2681
+ const retryTestId = test._ddRetryTestId
2463
2682
  const finalStatus = getFinalStatus({
2464
- isFinalExecution: test._ddIsFinalExecution,
2683
+ // Retain a candidate final status while a native retry is possible. The main
2684
+ // process removes it when another execution arrives, or keeps it if retries stop.
2685
+ isFinalExecution: retryTestId !== undefined || test._ddIsFinalExecution,
2465
2686
  isDisabled: test._ddIsDisabled,
2466
2687
  isQuarantined: test._ddIsQuarantined,
2467
2688
  isAtrRetry: test._ddIsAtrRetry,
2468
2689
  isEfdManagedTest: test._ddIsEfdManagedTest,
2469
2690
  isAttemptToFix: test._ddIsAttemptToFix,
2470
- hasFailedAllRetries: test._ddHasFailedAllRetries,
2471
2691
  hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
2472
2692
  hasPassedAnyEfdAttempt: test._ddHasPassedAnyEfdAttempt,
2473
2693
  testStatus: STATUS_TO_TEST_STATUS[status],
@@ -2475,6 +2695,10 @@ function instrumentWorkerMainMethods (workerMain) {
2475
2695
 
2476
2696
  await getChannelPromise(testFinishCh, {
2477
2697
  testStatus: STATUS_TO_TEST_STATUS[status],
2698
+ isExpectedFailure: status === 'failed' && testInfo.expectedStatus === 'failed',
2699
+ hasNonRetriableError: testInfo._hasNonRetriableError,
2700
+ retryTestId,
2701
+ deferFinalStatus: test._ddDeferFinalStatus,
2478
2702
  steps: steps.filter(step => step.testId === testId),
2479
2703
  error,
2480
2704
  extraTags: annotationTags,