dd-trace 6.9.0 → 6.10.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 (59) hide show
  1. package/ci/vitest-no-worker-init-setup.mjs +112 -10
  2. package/index.d.ts +42 -0
  3. package/package.json +4 -3
  4. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  5. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
  6. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
  7. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
  8. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
  9. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  10. package/packages/datadog-instrumentations/src/jest.js +1 -1
  11. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  12. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -8
  13. package/packages/datadog-instrumentations/src/mysql.js +45 -15
  14. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  15. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  16. package/packages/datadog-instrumentations/src/pg.js +116 -92
  17. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
  18. package/packages/datadog-instrumentations/src/vitest-main.js +169 -17
  19. package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
  20. package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
  21. package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
  22. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  23. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
  24. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  25. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +1 -1
  26. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  27. package/packages/datadog-plugin-jest/src/index.js +5 -4
  28. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  29. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  30. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
  31. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  32. package/packages/datadog-plugin-mocha/src/index.js +550 -39
  33. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  34. package/packages/datadog-plugin-next/src/index.js +1 -19
  35. package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
  36. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  37. package/packages/datadog-plugin-pg/src/index.js +1 -0
  38. package/packages/datadog-plugin-vitest/src/index.js +8 -20
  39. package/packages/datadog-plugin-ws/src/util.js +2 -1
  40. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  41. package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
  42. package/packages/dd-trace/src/carrier.js +356 -0
  43. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -0
  44. package/packages/dd-trace/src/config/supported-configurations.json +10 -0
  45. package/packages/dd-trace/src/datastreams/context.js +6 -1
  46. package/packages/dd-trace/src/datastreams/manager.js +5 -1
  47. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  48. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  49. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  50. package/packages/dd-trace/src/llmobs/index.js +34 -2
  51. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  52. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  53. package/packages/dd-trace/src/llmobs/util.js +78 -0
  54. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  55. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  56. package/packages/dd-trace/src/plugin_manager.js +2 -0
  57. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +1 -62
  58. package/packages/dd-trace/src/plugins/util/test.js +84 -5
  59. package/packages/dd-trace/src/plugins/util/web.js +53 -2
@@ -4,6 +4,8 @@ const path = require('node:path')
4
4
  const { fileURLToPath } = require('node:url')
5
5
  const { MessagePort } = require('node:worker_threads')
6
6
 
7
+ const satisfies = require('../../../vendor/dist/semifies')
8
+
7
9
  const shimmer = require('../../datadog-shimmer')
8
10
  const log = require('../../dd-trace/src/log')
9
11
  const { EMPTY_EFD_RETRY_POLICY } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
@@ -12,16 +14,19 @@ const {
12
14
  VITEST_WORKER_COVERAGE_PAYLOAD_CODE,
13
15
  VITEST_WORKER_LOGS_PAYLOAD_CODE,
14
16
  VITEST_WORKER_TELEMETRY_PAYLOAD_CODE,
17
+ VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE,
18
+ VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE,
15
19
  collectTestOptimizationSummariesFromTraces,
20
+ getIsFaultyEarlyFlakeDetection,
16
21
  logTestOptimizationSummary,
17
22
  TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE,
18
23
  getTestOptimizationRequestResults,
19
24
  getTestSuitePath,
20
25
  isModifiedTest,
26
+ isMarkedAsUnskippable,
21
27
  recordTestManagementExecution,
22
28
  recordAttemptToFixExecution,
23
29
  } = require('../../dd-trace/src/plugins/util/test')
24
- const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
25
30
  const { getChannelPromise } = require('./helpers/channel')
26
31
  const { addHook, channel } = require('./helpers/instrument')
27
32
  const noWorkerInit = require('./vitest-main-no-worker-init')
@@ -38,7 +43,6 @@ const {
38
43
  testSessionConfigurationCh,
39
44
  libraryConfigurationCh,
40
45
  knownTestsCh,
41
- isEarlyFlakeDetectionFaultyCh,
42
46
  testManagementTestsCh,
43
47
  modifiedFilesCh,
44
48
  workerReportTraceCh,
@@ -50,6 +54,7 @@ const {
50
54
  findExportByName,
51
55
  getTypeTasks,
52
56
  getWorkspaceProject,
57
+ parseProvidedContextValue,
53
58
  setProvidedContext,
54
59
  getVitestTestProperties,
55
60
  } = require('./vitest-util')
@@ -66,6 +71,7 @@ let isFlakyTestRetriesEnabled = false
66
71
  let flakyTestRetriesCount = 0
67
72
  let isEarlyFlakeDetectionEnabled = false
68
73
  let earlyFlakeDetectionRetryPolicy = EMPTY_EFD_RETRY_POLICY
74
+ let earlyFlakeDetectionFaultyThreshold = 0
69
75
  let isEarlyFlakeDetectionFaulty = false
70
76
  let isKnownTestsEnabled = false
71
77
  let isTestManagementTestsEnabled = false
@@ -97,6 +103,10 @@ let hasRunnableSuites = false
97
103
  let hasSelectedSuites = false
98
104
  let itrCorrelationId
99
105
  let tiaRepositoryRoot = process.cwd()
106
+ let activeNoWorkerInitState
107
+ let isEfdSuiteAdmissionEnabled = false
108
+ let maximumSuitesWithNewTests = 0
109
+ const suitesWithNewTests = new Set()
100
110
  const tinyPoolClassWrappers = new WeakMap()
101
111
  const itrSkippedSuitesCh = channel('ci:vitest:itr:skipped-suites')
102
112
  const skippableSuitesCh = channel('ci:vitest:test-suite:skippable')
@@ -223,6 +233,100 @@ function getNormalizedTestSuitePath (testFilepath, repositoryRoot) {
223
233
  return getTestSuitePath(realpath(testSuiteAbsolutePath), realpath(repositoryRoot))
224
234
  }
225
235
 
236
+ /**
237
+ * Resets suite-level EFD admission state between Vitest runs.
238
+ *
239
+ * @returns {void}
240
+ */
241
+ function resetEfdSuiteTracker () {
242
+ activeNoWorkerInitState = undefined
243
+ isEfdSuiteAdmissionEnabled = false
244
+ maximumSuitesWithNewTests = 0
245
+ suitesWithNewTests.clear()
246
+ }
247
+
248
+ /**
249
+ * Returns whether a Vitest pool has a transport for runtime EFD suite admission.
250
+ *
251
+ * @param {string|undefined} pool
252
+ * @returns {boolean}
253
+ */
254
+ function isEfdSuiteAdmissionPool (pool) {
255
+ return pool === undefined || pool === 'forks' || pool === 'threads' || pool === 'browser'
256
+ }
257
+
258
+ /**
259
+ * Returns whether Vitest exposes the worker transports used for runtime EFD suite admission.
260
+ *
261
+ * @param {string} frameworkVersion
262
+ * @param {object[]|undefined} testSpecifications
263
+ * @param {object} ctx
264
+ * @returns {boolean}
265
+ */
266
+ function supportsEfdSuiteAdmission (frameworkVersion, testSpecifications, ctx) {
267
+ if (!satisfies(frameworkVersion, '>=4.0.0')) return false
268
+ const defaultPool = ctx?.config?.pool
269
+ if (!Array.isArray(testSpecifications) || testSpecifications.length === 0) {
270
+ return isEfdSuiteAdmissionPool(defaultPool)
271
+ }
272
+
273
+ for (const testSpecification of testSpecifications) {
274
+ const pool = getTestSpecificationPool(testSpecification) || defaultPool
275
+ if (!isEfdSuiteAdmissionPool(pool)) return false
276
+ }
277
+ return true
278
+ }
279
+
280
+ /**
281
+ * Configures the EFD threshold against the unique suites selected by Vitest.
282
+ *
283
+ * @param {string[]} testFilepaths
284
+ * @param {string} repositoryRoot
285
+ * @returns {void}
286
+ */
287
+ function configureEfdSuiteTracker (testFilepaths, repositoryRoot) {
288
+ const testSuites = new Set()
289
+ for (const testFilepath of testFilepaths) {
290
+ testSuites.add(getNormalizedTestSuitePath(testFilepath, repositoryRoot))
291
+ }
292
+
293
+ maximumSuitesWithNewTests = Math.floor(Math.max(
294
+ earlyFlakeDetectionFaultyThreshold,
295
+ testSuites.size * earlyFlakeDetectionFaultyThreshold / 100
296
+ ))
297
+ isEfdSuiteAdmissionEnabled = true
298
+ }
299
+
300
+ /**
301
+ * Returns whether a suite may schedule EFD retries and records runnable suites with new tests.
302
+ *
303
+ * @param {string} testSuite
304
+ * @param {boolean} hasNewTest
305
+ * @returns {boolean}
306
+ */
307
+ function reserveEarlyFlakeDetectionSuite (testSuite, hasNewTest) {
308
+ if (!isEfdSuiteAdmissionEnabled || typeof testSuite !== 'string') return false
309
+ if (isEarlyFlakeDetectionFaulty) return false
310
+
311
+ if (hasNewTest) {
312
+ suitesWithNewTests.add(testSuite)
313
+ if (suitesWithNewTests.size > maximumSuitesWithNewTests) {
314
+ isEarlyFlakeDetectionEnabled = false
315
+ isEarlyFlakeDetectionFaulty = true
316
+ if (activeNoWorkerInitState) {
317
+ activeNoWorkerInitState.isEarlyFlakeDetectionEnabled = false
318
+ activeNoWorkerInitState.isEarlyFlakeDetectionFaulty = true
319
+ }
320
+ log.warn(
321
+ 'Early Flake Detection retries are disabled because the number of suites with new tests is too high.'
322
+ )
323
+ return false
324
+ }
325
+ }
326
+
327
+ return true
328
+ }
329
+
226
330
  function resetSuiteSkippingRunState () {
227
331
  skippableSuites = []
228
332
  resetAppliedSuiteSkippingState()
@@ -543,6 +647,7 @@ function resetLibraryConfig () {
543
647
  flakyTestRetriesCount = 0
544
648
  isEarlyFlakeDetectionEnabled = false
545
649
  earlyFlakeDetectionRetryPolicy = EMPTY_EFD_RETRY_POLICY
650
+ earlyFlakeDetectionFaultyThreshold = 0
546
651
  isEarlyFlakeDetectionFaulty = false
547
652
  isDiEnabled = false
548
653
  isKnownTestsEnabled = false
@@ -558,6 +663,7 @@ function applyLibraryConfig (libraryConfig) {
558
663
  flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
559
664
  isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
560
665
  earlyFlakeDetectionRetryPolicy = libraryConfig.earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
666
+ earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold ?? 0
561
667
  isEarlyFlakeDetectionFaulty = false
562
668
  isDiEnabled = libraryConfig.isDiEnabled
563
669
  isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
@@ -573,6 +679,7 @@ function resetMainProcessProvidedContext (ctx) {
573
679
  _ddIsDiEnabled: false,
574
680
  _ddIsEarlyFlakeDetectionEnabled: false,
575
681
  _ddEarlyFlakeDetectionRetryPolicy: EMPTY_EFD_RETRY_POLICY,
682
+ _ddIsEfdSuiteAdmissionEnabled: false,
576
683
  _ddIsFlakyTestRetriesEnabled: false,
577
684
  _ddFlakyTestRetriesCount: 0,
578
685
  _ddFlakyTestRetriesIncludesUnnamedProject: false,
@@ -616,6 +723,7 @@ async function runMainProcessSetup (
616
723
  }
617
724
 
618
725
  resetSuiteSkippingRunState()
726
+ resetEfdSuiteTracker()
619
727
  isVitestBrowserModeActive ||= shouldInstallBrowserReporter
620
728
  isTestImpactAnalysisDisabled =
621
729
  disableTestImpactAnalysis || shouldInstallNoWorkerInit || isVitestBrowserModeActive
@@ -732,21 +840,27 @@ async function runMainProcessSetup (
732
840
  const currentTestFilepaths = await getCurrentTestFilepaths()
733
841
 
734
842
  if (isValidKnownTests(knownTests)) {
735
- isEarlyFlakeDetectionFaultyCh.publish({
736
- knownTests: knownTests.vitest,
737
- testFilepaths: currentTestFilepaths,
738
- onDone: (isFaulty) => {
739
- isEarlyFlakeDetectionFaulty = isFaulty
740
- },
741
- })
742
- if (isEarlyFlakeDetectionFaulty) {
743
- isEarlyFlakeDetectionEnabled = false
744
- log.warn('New test detection is disabled because the number of new tests is too high.')
843
+ if (!shouldInstallNoWorkerInit && supportsEfdSuiteAdmission(frameworkVersion, testSpecifications, ctx)) {
844
+ configureEfdSuiteTracker(currentTestFilepaths, repositoryRoot)
745
845
  } else {
846
+ const projectSuites = currentTestFilepaths.map(testFilepath => getTestSuitePath(testFilepath, repositoryRoot))
847
+ isEarlyFlakeDetectionFaulty = getIsFaultyEarlyFlakeDetection(
848
+ projectSuites,
849
+ knownTests.vitest,
850
+ earlyFlakeDetectionFaultyThreshold
851
+ )
852
+ if (isEarlyFlakeDetectionFaulty) {
853
+ isEarlyFlakeDetectionEnabled = false
854
+ log.warn('New test detection is disabled because the number of new tests is too high.')
855
+ }
856
+ }
857
+
858
+ if (!isEarlyFlakeDetectionFaulty) {
746
859
  knownTestsBySuite = knownTests.vitest
747
860
  shouldSendTestProperties = true
748
861
  if (!shouldInstallNoWorkerInit) {
749
862
  setProvidedContext(ctx, {
863
+ _ddIsEfdSuiteAdmissionEnabled: isEfdSuiteAdmissionEnabled,
750
864
  _ddIsKnownTestsEnabled: isKnownTestsEnabled,
751
865
  _ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled,
752
866
  _ddEarlyFlakeDetectionRetryPolicy: earlyFlakeDetectionRetryPolicy,
@@ -821,6 +935,7 @@ async function runMainProcessSetup (
821
935
  const reporterTestSpecifications = shouldInstallNoWorkerInit
822
936
  ? testSpecifications
823
937
  : getBrowserTestSpecifications(testSpecifications)
938
+ activeNoWorkerInitState = getNoWorkerInitState()
824
939
  noWorkerInit.configure(ctx, frameworkVersion, reporterTestSpecifications, {
825
940
  knownTests,
826
941
  knownTestsBySuite,
@@ -832,8 +947,9 @@ async function runMainProcessSetup (
832
947
  testPropertiesByFilepath: testPropertiesByFilepath || {},
833
948
  testSessionConfiguration,
834
949
  }, {
950
+ reserveEarlyFlakeDetectionSuite,
835
951
  shouldReportTestModule: shouldInstallBrowserReporter ? isBrowserTestModule : undefined,
836
- state: getNoWorkerInitState(),
952
+ state: activeNoWorkerInitState,
837
953
  })
838
954
  }
839
955
 
@@ -846,6 +962,7 @@ function getNoWorkerInitState () {
846
962
  return {
847
963
  attemptToFixExecutions,
848
964
  earlyFlakeDetectionRetryPolicy,
965
+ isEfdSuiteAdmissionEnabled,
849
966
  isEarlyFlakeDetectionEnabled,
850
967
  isEarlyFlakeDetectionFaulty,
851
968
  isFlakyTestRetriesEnabled,
@@ -1172,8 +1289,9 @@ function getTestSpecificationOptions (testSpecification) {
1172
1289
  function getTestSpecificationPool (testSpecification) {
1173
1290
  const options = getTestSpecificationOptions(testSpecification)
1174
1291
  const project = getTestSpecificationProject(testSpecification)
1175
- return options?.pool || project?.config?.pool || project?.serializedConfig?.pool || project?.pool ||
1176
- testSpecification?.pool
1292
+ const filePool = Array.isArray(testSpecification) ? testSpecification[1]?.pool : undefined
1293
+ return options?.pool || filePool || project?.config?.pool || project?.serializedConfig?.pool ||
1294
+ project?.pool || testSpecification?.pool
1177
1295
  }
1178
1296
 
1179
1297
  /**
@@ -1328,7 +1446,7 @@ function getMainProcessProvidedContext (ctx) {
1328
1446
  const providedContext = workspaceProject.getProvidedContext?.() || workspaceProject._provided || {}
1329
1447
 
1330
1448
  return {
1331
- testPropertiesByFilepath: providedContext._ddTestPropertiesByFilepath || {},
1449
+ testPropertiesByFilepath: parseProvidedContextValue(providedContext._ddTestPropertiesByFilepath) || {},
1332
1450
  }
1333
1451
  } catch {
1334
1452
  return {
@@ -1750,7 +1868,10 @@ function getWrappedOn (on) {
1750
1868
  arguments[1] = shimmer.wrapFunction(callback, callback => function (message) {
1751
1869
  if (message.type !== 'Buffer' && Array.isArray(message)) {
1752
1870
  const [interprocessCode, data] = message
1753
- if (handleWorkerReport(interprocessCode, data)) {
1871
+ if (
1872
+ handleEfdAdmissionMessage(this, interprocessCode, data) ||
1873
+ handleWorkerReport(interprocessCode, data)
1874
+ ) {
1754
1875
  // If we execute the callback vitest crashes, as the message is not supported
1755
1876
  return
1756
1877
  }
@@ -1761,6 +1882,37 @@ function getWrappedOn (on) {
1761
1882
  }
1762
1883
  }
1763
1884
 
1885
+ /**
1886
+ * Handles an EFD suite admission request sent through a Vitest worker transport.
1887
+ *
1888
+ * @param {object} workerProcess
1889
+ * @param {number} interprocessCode
1890
+ * @param {object} data
1891
+ * @returns {boolean}
1892
+ */
1893
+ function handleEfdAdmissionMessage (workerProcess, interprocessCode, data) {
1894
+ if (interprocessCode !== VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE) return false
1895
+
1896
+ const response = [VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE, {
1897
+ allowed: reserveEarlyFlakeDetectionSuite(data?.testSuite, data?.hasNewTest === true),
1898
+ requestId: data?.requestId,
1899
+ }]
1900
+ try {
1901
+ if (typeof workerProcess.send === 'function') {
1902
+ workerProcess.send(response, (error) => {
1903
+ if (error) {
1904
+ log.error('Could not send Vitest EFD suite admission response: %s', error.message)
1905
+ }
1906
+ })
1907
+ } else {
1908
+ workerProcess.postMessage(response)
1909
+ }
1910
+ } catch (error) {
1911
+ log.error('Could not send Vitest EFD suite admission response: %s', error?.message)
1912
+ }
1913
+ return true
1914
+ }
1915
+
1764
1916
  function handleWorkerReport (interprocessCode, data) {
1765
1917
  if (interprocessCode === VITEST_WORKER_TRACE_PAYLOAD_CODE) {
1766
1918
  collectTestOptimizationSummariesFromTraces(data, {
@@ -29,10 +29,12 @@ const testSessionFinishCh = channel('ci:vitest:session:finish')
29
29
  const testSessionConfigurationCh = channel('ci:vitest:session:configuration')
30
30
  const libraryConfigurationCh = channel('ci:vitest:library-configuration')
31
31
  const knownTestsCh = channel('ci:vitest:known-tests')
32
- const isEarlyFlakeDetectionFaultyCh = channel('ci:vitest:is-early-flake-detection-faulty')
33
32
  const testManagementTestsCh = channel('ci:vitest:test-management-tests')
34
33
  const modifiedFilesCh = channel('ci:vitest:modified-files')
35
34
 
35
+ const CLOSING_SCRIPT_TAG_RE = /<\/script/i
36
+ const SERIALIZED_CONTEXT_PREFIX = '\u0000dd-vitest-context:'
37
+
36
38
  const workerReportTraceCh = channel('ci:vitest:worker-report:trace')
37
39
  const workerReportCoverageCh = channel('ci:vitest:worker-report:coverage')
38
40
  const workerReportLogsCh = channel('ci:vitest:worker-report:logs')
@@ -105,18 +107,72 @@ function getWorkspaceProject (ctx) {
105
107
 
106
108
  function setProvidedContext (ctx, values, warningMessage) {
107
109
  try {
108
- Object.assign(getWorkspaceProject(ctx)._provided, values)
110
+ const providedContext = getWorkspaceProject(ctx)._provided
111
+ for (const key of Object.keys(values)) {
112
+ providedContext[key] = key.startsWith('_dd')
113
+ ? makeProvidedContextBrowserSafe(values[key])
114
+ : values[key]
115
+ }
109
116
  } catch {
110
117
  log.warn(warningMessage)
111
118
  }
112
119
  }
113
120
 
121
+ /**
122
+ * Prevent Vitest Browser Mode from terminating its inline bootstrap script with Datadog metadata.
123
+ *
124
+ * @param {unknown} value
125
+ * @returns {unknown}
126
+ */
127
+ function makeProvidedContextBrowserSafe (value) {
128
+ if (typeof value !== 'string' && (typeof value !== 'object' || value === null)) return value
129
+ if (typeof value === 'string' && !CLOSING_SCRIPT_TAG_RE.test(value)) return value
130
+
131
+ const serializedValue = JSON.stringify(value)
132
+ return CLOSING_SCRIPT_TAG_RE.test(serializedValue)
133
+ ? SERIALIZED_CONTEXT_PREFIX + serializedValue.replaceAll('<', String.raw`\u003c`)
134
+ : value
135
+ }
136
+
137
+ /**
138
+ * Restore context serialized by makeProvidedContextBrowserSafe.
139
+ *
140
+ * @param {unknown} value
141
+ * @returns {unknown}
142
+ */
143
+ function parseProvidedContextValue (value) {
144
+ if (typeof value !== 'string' || !value.startsWith(SERIALIZED_CONTEXT_PREFIX)) return value
145
+
146
+ let parsedValue
147
+ try {
148
+ parsedValue = JSON.parse(value.slice(SERIALIZED_CONTEXT_PREFIX.length))
149
+ } catch {}
150
+ return parsedValue
151
+ }
152
+
153
+ /**
154
+ * Restores Datadog context values serialized for Vitest Browser Mode.
155
+ *
156
+ * @param {Record<string, unknown>} values
157
+ * @returns {Record<string, unknown>}
158
+ */
159
+ function parseProvidedContextValues (values) {
160
+ const parsedValues = {}
161
+ for (const key of Object.keys(values)) {
162
+ if (key.startsWith('_dd')) {
163
+ parsedValues[key] = parseProvidedContextValue(values[key])
164
+ }
165
+ }
166
+ return parsedValues
167
+ }
168
+
114
169
  function getProvidedContext () {
115
170
  try {
116
171
  const {
117
172
  _ddIsEarlyFlakeDetectionEnabled,
173
+ _ddIsEfdSuiteAdmissionEnabled: isEfdSuiteAdmissionEnabled,
118
174
  _ddIsDiEnabled,
119
- _ddTestPropertiesByFilepath: testPropertiesByFilepath,
175
+ _ddTestPropertiesByFilepath,
120
176
  _ddEarlyFlakeDetectionRetryPolicy: earlyFlakeDetectionRetryPolicy,
121
177
  _ddIsKnownTestsEnabled: isKnownTestsEnabled,
122
178
  _ddIsTestManagementTestsEnabled: isTestManagementTestsEnabled,
@@ -135,11 +191,13 @@ function getProvidedContext () {
135
191
  _ddItrCorrelationId: itrCorrelationId,
136
192
  _ddUnskippableSuites: unskippableSuites,
137
193
  _ddForcedToRunSuites: forcedToRunSuites,
138
- } = globalThis.__vitest_worker__.providedContext
194
+ } = parseProvidedContextValues(globalThis.__vitest_worker__.providedContext)
139
195
  const retryPolicy = earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
196
+ const testPropertiesByFilepath = _ddTestPropertiesByFilepath || {}
140
197
 
141
198
  return {
142
199
  isDiEnabled: _ddIsDiEnabled,
200
+ isEfdSuiteAdmissionEnabled,
143
201
  isEarlyFlakeDetectionEnabled: _ddIsEarlyFlakeDetectionEnabled && hasEfdRetries(retryPolicy),
144
202
  testPropertiesByFilepath,
145
203
  earlyFlakeDetectionRetryPolicy: retryPolicy,
@@ -165,6 +223,7 @@ function getProvidedContext () {
165
223
  log.error('Vitest workers could not parse provided context, so some features will not work.')
166
224
  return {
167
225
  isDiEnabled: false,
226
+ isEfdSuiteAdmissionEnabled: false,
168
227
  isEarlyFlakeDetectionEnabled: false,
169
228
  testPropertiesByFilepath: {},
170
229
  earlyFlakeDetectionRetryPolicy: EMPTY_EFD_RETRY_POLICY,
@@ -258,7 +317,6 @@ module.exports = {
258
317
  testSessionConfigurationCh,
259
318
  libraryConfigurationCh,
260
319
  knownTestsCh,
261
- isEarlyFlakeDetectionFaultyCh,
262
320
  testManagementTestsCh,
263
321
  modifiedFilesCh,
264
322
  workerReportTraceCh,
@@ -273,6 +331,7 @@ module.exports = {
273
331
  getTestName,
274
332
  getWorkspaceProject,
275
333
  setProvidedContext,
334
+ parseProvidedContextValue,
276
335
  getProvidedContext,
277
336
  isFlakyTestRetriesEnabledForTask,
278
337
  getVitestTestProperties,