dd-trace 6.6.0 → 6.8.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 (209) hide show
  1. package/ci/diagnose.js +162 -21
  2. package/ci/init.js +0 -1
  3. package/ci/runbook.md +187 -180
  4. package/ci/test-optimization-validation/approval-artifacts.js +3 -1
  5. package/ci/test-optimization-validation/approval.js +52 -15
  6. package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
  7. package/ci/test-optimization-validation/ci-discovery.js +1 -1
  8. package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
  9. package/ci/test-optimization-validation/ci-remediation.js +112 -39
  10. package/ci/test-optimization-validation/cli.js +516 -681
  11. package/ci/test-optimization-validation/command-blocker.js +188 -33
  12. package/ci/test-optimization-validation/command-output-policy.js +8 -31
  13. package/ci/test-optimization-validation/command-runner.js +189 -245
  14. package/ci/test-optimization-validation/environment.js +90 -0
  15. package/ci/test-optimization-validation/executable.js +159 -388
  16. package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
  17. package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
  18. package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
  19. package/ci/test-optimization-validation/generated-files.js +84 -22
  20. package/ci/test-optimization-validation/generated-test-contract.js +281 -0
  21. package/ci/test-optimization-validation/generated-verifier.js +49 -16
  22. package/ci/test-optimization-validation/literal-environment.js +57 -0
  23. package/ci/test-optimization-validation/manifest-loader.js +2 -22
  24. package/ci/test-optimization-validation/manifest-scaffold.js +815 -515
  25. package/ci/test-optimization-validation/manifest-schema.js +494 -702
  26. package/ci/test-optimization-validation/offline-fixtures.js +4 -1
  27. package/ci/test-optimization-validation/offline-output.js +6 -6
  28. package/ci/test-optimization-validation/plan-writer.js +243 -984
  29. package/ci/test-optimization-validation/preflight-runner.js +49 -55
  30. package/ci/test-optimization-validation/redaction.js +2 -1
  31. package/ci/test-optimization-validation/report-writer.js +391 -1357
  32. package/ci/test-optimization-validation/result-semantics.js +86 -0
  33. package/ci/test-optimization-validation/runner-command.js +249 -0
  34. package/ci/test-optimization-validation/runner-contract.js +664 -0
  35. package/ci/test-optimization-validation/safe-files.js +4 -4
  36. package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
  39. package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
  40. package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
  41. package/ci/test-optimization-validation/scenarios/test-management.js +6 -5
  42. package/ci/test-optimization-validation/source-text.js +87 -0
  43. package/ci/test-optimization-validation/test-output.js +12 -22
  44. package/ci/vitest-no-worker-init-setup.mjs +348 -51
  45. package/ext/tags.d.ts +1 -0
  46. package/index.d.ts +84 -13
  47. package/package.json +10 -4
  48. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  49. package/packages/datadog-esbuild/index.js +4 -2
  50. package/packages/datadog-esbuild/src/utils.js +1 -1
  51. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +4 -4
  52. package/packages/datadog-instrumentations/src/cucumber.js +9 -6
  53. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  54. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  55. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  56. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  57. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +1 -0
  58. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
  59. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
  60. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -0
  61. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  62. package/packages/datadog-instrumentations/src/helpers/router-helper.js +1 -1
  63. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  64. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  65. package/packages/datadog-instrumentations/src/jest.js +8 -14
  66. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  67. package/packages/datadog-instrumentations/src/mocha/main.js +2 -42
  68. package/packages/datadog-instrumentations/src/mocha/utils.js +68 -2
  69. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +19 -0
  70. package/packages/datadog-instrumentations/src/mocha/worker.js +446 -42
  71. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  72. package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
  73. package/packages/datadog-instrumentations/src/playwright.js +3 -2
  74. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  75. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +525 -56
  76. package/packages/datadog-instrumentations/src/vitest-main.js +90 -10
  77. package/packages/datadog-instrumentations/src/webdriverio.js +914 -0
  78. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  79. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  80. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  81. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  82. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  83. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  84. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  85. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  86. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  87. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +5 -8
  88. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  89. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  90. package/packages/datadog-plugin-fs/src/index.js +0 -4
  91. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  92. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  93. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  94. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  95. package/packages/datadog-plugin-http/src/client.js +2 -1
  96. package/packages/datadog-plugin-jest/src/index.js +2 -3
  97. package/packages/datadog-plugin-jest/src/util.js +2 -1
  98. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  99. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  100. package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
  101. package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
  102. package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
  103. package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
  104. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  105. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  106. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  107. package/packages/datadog-plugin-undici/src/index.js +2 -1
  108. package/packages/datadog-plugin-vitest/src/index.js +84 -11
  109. package/packages/datadog-webpack/index.js +2 -2
  110. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  111. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  112. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  113. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  114. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  116. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  117. package/packages/dd-trace/src/appsec/sdk/track_event.js +1 -1
  118. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  119. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  120. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +50 -51
  121. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -1
  122. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +4 -0
  123. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  124. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  125. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
  126. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  127. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +7 -5
  128. package/packages/dd-trace/src/config/defaults.js +14 -6
  129. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  130. package/packages/dd-trace/src/config/index.js +15 -0
  131. package/packages/dd-trace/src/config/parsers.js +19 -1
  132. package/packages/dd-trace/src/config/supported-configurations.json +12 -6
  133. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  134. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  135. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  136. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  137. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  138. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  139. package/packages/dd-trace/src/encode/span-stats.js +7 -1
  140. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  141. package/packages/dd-trace/src/exporter.js +16 -9
  142. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  143. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  144. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  145. package/packages/dd-trace/src/flare/index.js +2 -2
  146. package/packages/dd-trace/src/id.js +1 -1
  147. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  148. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  149. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  150. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  151. package/packages/dd-trace/src/llmobs/experiments/index.js +51 -12
  152. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  153. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  154. package/packages/dd-trace/src/llmobs/experiments/util.js +218 -0
  155. package/packages/dd-trace/src/llmobs/index.js +9 -1
  156. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
  157. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  158. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  159. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  160. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  161. package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
  162. package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
  163. package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
  164. package/packages/dd-trace/src/llmobs/sdk.js +6 -12
  165. package/packages/dd-trace/src/llmobs/span_processor.js +14 -7
  166. package/packages/dd-trace/src/llmobs/tagger.js +24 -5
  167. package/packages/dd-trace/src/llmobs/util.js +56 -3
  168. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  169. package/packages/dd-trace/src/noop/proxy.js +2 -2
  170. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
  171. package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
  172. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
  173. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  174. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  175. package/packages/dd-trace/src/opentracing/span.js +1 -1
  176. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  177. package/packages/dd-trace/src/plugins/ci_plugin.js +114 -23
  178. package/packages/dd-trace/src/plugins/index.js +2 -0
  179. package/packages/dd-trace/src/plugins/outbound.js +4 -1
  180. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  181. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  182. package/packages/dd-trace/src/plugins/util/ci.js +7 -6
  183. package/packages/dd-trace/src/plugins/util/git.js +1 -1
  184. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +1 -1
  185. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  186. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  187. package/packages/dd-trace/src/plugins/util/test.js +38 -12
  188. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  189. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  190. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  191. package/packages/dd-trace/src/priority_sampler.js +6 -3
  192. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  193. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  194. package/packages/dd-trace/src/ritm.js +5 -20
  195. package/packages/dd-trace/src/span_processor.js +1 -1
  196. package/packages/dd-trace/src/span_stats.js +22 -4
  197. package/packages/dd-trace/src/startup-log.js +3 -0
  198. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  199. package/packages/dd-trace/src/util.js +16 -0
  200. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  201. package/vendor/dist/pprof-format/index.js +1 -1
  202. package/vendor/dist/source-map/index.js +1 -1
  203. package/ci/test-optimization-validation/command-suitability.js +0 -471
  204. package/ci/test-optimization-validation/init-probe-preload.js +0 -163
  205. package/ci/test-optimization-validation/init-probe.js +0 -246
  206. package/ci/test-optimization-validation/late-initialization.js +0 -63
  207. package/ci/test-optimization-validation/local-command.js +0 -163
  208. package/ci/test-optimization-validation/setup-runner.js +0 -97
  209. package/ci/test-optimization-validation-manifest.schema.json +0 -1
@@ -7,6 +7,7 @@ const {
7
7
  failWithDebugRerun,
8
8
  pass,
9
9
  prepareGeneratedScenario,
10
+ reportMissingGeneratedTest,
10
11
  requireGeneratedScenario,
11
12
  runInstrumentedCommand,
12
13
  skip,
@@ -28,14 +29,14 @@ async function runEarlyFlakeDetection ({ framework, out, options }) {
28
29
 
29
30
  const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
30
31
  if (discovery.tests.length === 0) {
31
- return failWithDebugRerun({
32
+ return reportMissingGeneratedTest({
32
33
  command: scenario.runCommand,
33
34
  diagnosis: 'The generated new-test candidate was not reported during baseline identity discovery.',
34
- evidence: discoveryEvidence(discovery),
35
+ discovery,
35
36
  framework,
36
37
  options,
37
38
  out,
38
- outDir: discovery.outDir,
39
+ scenario,
39
40
  scenarioName,
40
41
  })
41
42
  }
@@ -4,7 +4,7 @@ const fs = require('node:fs')
4
4
  const path = require('path')
5
5
 
6
6
  const { getArtifactId } = require('../artifact-id')
7
- const { buildCiWiringEnv, buildDatadogEnv, runCommand } = require('../command-runner')
7
+ const { buildDatadogEnv, buildOfflineCaptureEnv, runCommand } = require('../command-runner')
8
8
  const {
9
9
  cleanupGeneratedRuntimeFiles,
10
10
  findGeneratedScenario,
@@ -14,10 +14,10 @@ const {
14
14
  eventsOfType,
15
15
  findTestsByIdentity,
16
16
  } = require('../payload-normalizer')
17
- const { getLocalValidationCommand } = require('../local-command')
18
17
  const { cleanupOfflineFixture, createOfflineFixture } = require('../offline-fixtures')
19
18
  const { readOfflineOutput } = require('../offline-output')
20
19
  const { sanitizeForReport, sanitizeString } = require('../redaction')
20
+ const { getGeneratedCommand } = require('../runner-command')
21
21
  const { ensureSafeDirectory, writeFileSafely } = require('../safe-files')
22
22
 
23
23
  const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
@@ -34,7 +34,7 @@ async function runInstrumentedCommand ({
34
34
  options,
35
35
  extraEnv,
36
36
  fixtureConfig,
37
- ciWiring = false,
37
+ injectInitialization = true,
38
38
  allowMissingInitialization = false,
39
39
  }) {
40
40
  const outDir = frameworkOutDir(out, framework, scenarioName)
@@ -52,9 +52,9 @@ async function runInstrumentedCommand ({
52
52
  scenarioName,
53
53
  ...fixtureConfig,
54
54
  })
55
- const validationEnv = ciWiring
56
- ? buildCiWiringEnv({ fixture, outputRoot: rawOutputRoot })
57
- : buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
55
+ const validationEnv = injectInitialization
56
+ ? buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
57
+ : buildOfflineCaptureEnv({ fixture, outputRoot: rawOutputRoot })
58
58
  result = await runCommand(command, {
59
59
  env: {
60
60
  ...validationEnv,
@@ -82,7 +82,7 @@ async function runInstrumentedCommand ({
82
82
  `${JSON.stringify(sanitizeForReport(result), null, 2)}\n`,
83
83
  'scenario result artifact'
84
84
  )
85
- if (!offline.initialized && !ciWiring && !allowMissingInitialization) {
85
+ if (!offline.initialized && injectInitialization && !allowMissingInitialization) {
86
86
  const stderr = sanitizeString(result.stderr).trim().slice(-2000)
87
87
  throw new Error(
88
88
  'Offline Test Optimization exporter did not initialize or write completion evidence. ' +
@@ -180,11 +180,11 @@ async function prepareGeneratedScenario (framework, scenarioId) {
180
180
  const scenario = findGeneratedScenario(framework, scenarioId)
181
181
  if (!scenario) return { scenario: null, written: [] }
182
182
  cleanupGeneratedRuntimeFiles(framework)
183
- const written = await writeGeneratedFiles(framework)
183
+ const written = await writeGeneratedFiles(framework, scenario)
184
184
  return {
185
185
  scenario: {
186
186
  ...scenario,
187
- runCommand: getLocalValidationCommand(framework, scenario.runCommand),
187
+ runCommand: getGeneratedCommand(framework, scenario),
188
188
  },
189
189
  written,
190
190
  }
@@ -314,6 +314,63 @@ async function discoverScenarioTests ({ framework, out, scenarioName, scenario,
314
314
  }
315
315
  }
316
316
 
317
+ /**
318
+ * Reports a missing generated test without blaming dd-trace when clean execution was unproven.
319
+ *
320
+ * @param {object} input missing-test evidence
321
+ * @param {object} input.command generated scenario command
322
+ * @param {string} input.diagnosis diagnosis used when clean execution was proven
323
+ * @param {object} input.discovery instrumented baseline result
324
+ * @param {object} input.framework framework manifest entry
325
+ * @param {object} input.options execution options
326
+ * @param {string} input.out validation output root
327
+ * @param {object} input.scenario generated scenario
328
+ * @param {string} input.scenarioName advanced scenario name
329
+ * @returns {object|Promise<object>} incomplete or confirmed failure result
330
+ */
331
+ function reportMissingGeneratedTest ({
332
+ command,
333
+ diagnosis,
334
+ discovery,
335
+ framework,
336
+ options,
337
+ out,
338
+ scenario,
339
+ scenarioName,
340
+ }) {
341
+ const verification = framework.generatedTestStrategy?.verification?.observedScenarios
342
+ ?.find(observed => observed.id === scenario.id)
343
+ const evidence = {
344
+ ...discoveryEvidence(discovery),
345
+ generatedVerificationObservedTestCount: verification?.observedTestCount,
346
+ }
347
+ if (verification?.observedTestCount === null) {
348
+ return inconclusive(
349
+ framework,
350
+ scenarioName,
351
+ 'The clean temporary validation command exited as expected without a parseable test count, and the ' +
352
+ 'instrumented baseline emitted no matching test event. The validator cannot prove that the generated test ' +
353
+ 'executed, so no advanced-feature conclusion was reached.',
354
+ {
355
+ ...evidence,
356
+ reasonCode: 'generated-test-execution-unproven',
357
+ },
358
+ discovery.outDir
359
+ )
360
+ }
361
+
362
+ return failWithDebugRerun({
363
+ command,
364
+ diagnosis,
365
+ evidence,
366
+ framework,
367
+ options,
368
+ out,
369
+ outDir: discovery.outDir,
370
+ scenarioName,
371
+ })
372
+ }
373
+
317
374
  function testsForDiscoveredScenario (events, scenario, discovery) {
318
375
  if (discovery?.testIdentities?.length > 0) {
319
376
  return findTestsByIdentity(events, discovery.testIdentities)
@@ -528,6 +585,7 @@ module.exports = {
528
585
  inconclusive,
529
586
  pass,
530
587
  prepareGeneratedScenario,
588
+ reportMissingGeneratedTest,
531
589
  requireGeneratedScenario,
532
590
  runDebugInstrumentedCommand,
533
591
  runInstrumentedCommand,
@@ -9,6 +9,7 @@ const {
9
9
  failWithDebugRerun,
10
10
  pass,
11
11
  prepareGeneratedScenario,
12
+ reportMissingGeneratedTest,
12
13
  requireGeneratedScenario,
13
14
  runInstrumentedCommand,
14
15
  testEventSamples,
@@ -25,14 +26,14 @@ async function runTestManagement ({ framework, out, options }) {
25
26
  const { scenario } = await prepareGeneratedScenario(framework, 'test-management-target')
26
27
  const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
27
28
  if (discovery.tests.length === 0) {
28
- return failWithDebugRerun({
29
+ return reportMissingGeneratedTest({
29
30
  command: scenario.runCommand,
30
31
  diagnosis: 'The test-management target was not reported during baseline identity discovery.',
31
- evidence: discoveryEvidence(discovery),
32
+ discovery,
32
33
  framework,
33
34
  options,
34
35
  out,
35
- outDir: discovery.outDir,
36
+ scenario,
36
37
  scenarioName,
37
38
  })
38
39
  }
@@ -148,7 +149,7 @@ function buildQuarantinedResponse (framework, scenario, discoveredIdentities = [
148
149
  for (const identity of identities) {
149
150
  for (const suite of getSuiteCandidates(identity, scenario)) {
150
151
  for (const name of getNameCandidates(identity)) {
151
- suites[suite] = suites[suite] || { tests: {} }
152
+ suites[suite] ||= { tests: {} }
152
153
  suites[suite].tests[name] = {
153
154
  properties: {
154
155
  quarantined: true,
@@ -209,7 +210,7 @@ function summarizeManagedTests (testManagementTests) {
209
210
  }
210
211
  summary.set(displaySuite, testNames)
211
212
  }
212
- return [...summary.entries()].slice(0, 5).map(([suite, tests]) => ({
213
+ return [...summary].slice(0, 5).map(([suite, tests]) => ({
213
214
  suite,
214
215
  tests: [...tests].slice(0, 5),
215
216
  }))
@@ -0,0 +1,87 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Replaces JavaScript comments with spaces while preserving line structure and string literals.
5
+ *
6
+ * @param {string} source JavaScript or TypeScript source
7
+ * @returns {string} source with comments masked
8
+ */
9
+ function maskJavaScriptComments (source) {
10
+ return maskJavaScriptSource(source, false)
11
+ }
12
+
13
+ /**
14
+ * Replaces JavaScript comments and string literals with spaces while preserving line structure.
15
+ *
16
+ * @param {string} source JavaScript or TypeScript source
17
+ * @returns {string} source with non-code text masked
18
+ */
19
+ function maskJavaScriptNonCode (source) {
20
+ return maskJavaScriptSource(source, true)
21
+ }
22
+
23
+ /**
24
+ * Masks comments and optionally string literals in JavaScript-like source.
25
+ *
26
+ * @param {string} source JavaScript or TypeScript source
27
+ * @param {boolean} maskStrings whether string and template literal contents should be masked
28
+ * @returns {string} masked source
29
+ */
30
+ function maskJavaScriptSource (source, maskStrings) {
31
+ const characters = [...source]
32
+ let blockComment = false
33
+ let lineComment = false
34
+ let quote = ''
35
+
36
+ for (let index = 0; index < characters.length; index++) {
37
+ const character = characters[index]
38
+ const next = characters[index + 1]
39
+ if (lineComment) {
40
+ if (character === '\n') {
41
+ lineComment = false
42
+ } else {
43
+ characters[index] = ' '
44
+ }
45
+ continue
46
+ }
47
+ if (blockComment) {
48
+ if (character === '*' && next === '/') {
49
+ characters[index] = ' '
50
+ characters[++index] = ' '
51
+ blockComment = false
52
+ } else if (character !== '\r' && character !== '\n') {
53
+ characters[index] = ' '
54
+ }
55
+ continue
56
+ }
57
+ if (quote) {
58
+ if (maskStrings && character !== '\r' && character !== '\n') characters[index] = ' '
59
+ if (character.charCodeAt(0) === 92) {
60
+ if (maskStrings && index + 1 < characters.length &&
61
+ characters[index + 1] !== '\r' && characters[index + 1] !== '\n') {
62
+ characters[index + 1] = ' '
63
+ }
64
+ index++
65
+ } else if (character === quote) {
66
+ quote = ''
67
+ }
68
+ continue
69
+ }
70
+ if (character === '"' || character === '\'' || character === '`') {
71
+ quote = character
72
+ if (maskStrings) characters[index] = ' '
73
+ } else if (character === '/' && next === '/') {
74
+ characters[index] = ' '
75
+ characters[++index] = ' '
76
+ lineComment = true
77
+ } else if (character === '/' && next === '*') {
78
+ characters[index] = ' '
79
+ characters[++index] = ' '
80
+ blockComment = true
81
+ }
82
+ }
83
+
84
+ return characters.join('')
85
+ }
86
+
87
+ module.exports = { maskJavaScriptComments, maskJavaScriptNonCode }
@@ -1,5 +1,9 @@
1
1
  'use strict'
2
2
 
3
+ const cypressAdapter = require('./framework-adapters/cypress')
4
+ const cucumberAdapter = require('./framework-adapters/cucumber')
5
+ const playwrightAdapter = require('./framework-adapters/playwright')
6
+
3
7
  const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
4
8
 
5
9
  /**
@@ -11,16 +15,14 @@ const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*
11
15
  * @returns {number|null} observed count when a supported summary was found
12
16
  */
13
17
  function getObservedTestCount (framework, stdout = '', stderr = '') {
14
- const output = `${stdout}\n${stderr}`.replaceAll(ANSI_PATTERN, '')
18
+ const output = stripAnsi(`${stdout}\n${stderr}`)
19
+ if (framework === 'cucumber') return cucumberAdapter.getObservedTestCount(output)
20
+ if (framework === 'cypress') return cypressAdapter.getObservedTestCount(output)
21
+ if (framework === 'playwright') return playwrightAdapter.getObservedTestCount(output)
15
22
  if (framework === 'jest') return getJestObservedTestCount(output)
16
23
  if (framework === 'vitest') return getVitestObservedTestCount(output)
17
- if (framework === 'playwright') return getPlaywrightObservedTestCount(output)
18
24
 
19
- const totalPatterns = framework === 'node:test'
20
- ? [/^# tests\s+(\d+)\s*$/gim]
21
- : framework === 'cucumber'
22
- ? [/\b(\d+)\s+scenarios?\b/gi]
23
- : []
25
+ const totalPatterns = framework === 'node:test' ? [/^# tests\s+(\d+)\s*$/gim] : []
24
26
 
25
27
  for (const pattern of totalPatterns) {
26
28
  const count = getLastMatchCount(output, pattern)
@@ -38,20 +40,8 @@ function getObservedTestCount (framework, stdout = '', stderr = '') {
38
40
  return getLastMatchCount(output, /\b(\d+)\s+tests?\s+(?:passed|failed)\b/gi)
39
41
  }
40
42
 
41
- /**
42
- * Counts Playwright tests that completed instead of treating skipped tests as executions.
43
- *
44
- * @param {string} output test output without ANSI codes
45
- * @returns {number|null} executed test count
46
- */
47
- function getPlaywrightObservedTestCount (output) {
48
- const observed = sumLastMatchCounts(output, [
49
- /^\s*(\d+)\s+passed\b/gim,
50
- /^\s*(\d+)\s+failed\b/gim,
51
- /^\s*(\d+)\s+flaky\b/gim,
52
- ])
53
- if (observed !== null) return observed
54
- return /^\s*\d+\s+skipped\b/im.test(output) ? 0 : null
43
+ function stripAnsi (value) {
44
+ return String(value || '').replaceAll(ANSI_PATTERN, '')
55
45
  }
56
46
 
57
47
  /**
@@ -126,4 +116,4 @@ function sumLastMatchCounts (output, patterns) {
126
116
  return found ? count : null
127
117
  }
128
118
 
129
- module.exports = { getObservedTestCount }
119
+ module.exports = { getObservedTestCount, stripAnsi }