@depup/dd-trace 6.20.0-depup.0 → 6.21.0-depup.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 (47) hide show
  1. package/README.md +2 -2
  2. package/changes.json +1 -1
  3. package/index.d.ts +91 -3
  4. package/package.json +8 -9
  5. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +57 -4
  6. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
  7. package/packages/datadog-instrumentations/src/jest.js +119 -1
  8. package/packages/datadog-instrumentations/src/mocha/utils.js +124 -36
  9. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +61 -34
  10. package/packages/datadog-instrumentations/src/mocha/worker.js +6 -3
  11. package/packages/datadog-instrumentations/src/playwright.js +3 -0
  12. package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
  13. package/packages/datadog-instrumentations/src/webdriverio.js +115 -15
  14. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +17 -0
  15. package/packages/datadog-plugin-mocha/src/index.js +216 -29
  16. package/packages/datadog-plugin-mocha/src/webdriverio-video.js +449 -0
  17. package/packages/dd-trace/src/config/supported-configurations.json +2 -2
  18. package/packages/dd-trace/src/debugger/constants.js +1 -0
  19. package/packages/dd-trace/src/debugger/devtools_client/index.js +5 -3
  20. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +17 -12
  21. package/packages/dd-trace/src/debugger/devtools_client/send.js +6 -2
  22. package/packages/dd-trace/src/debugger/devtools_client/worker-error.js +21 -0
  23. package/packages/dd-trace/src/debugger/index.js +24 -2
  24. package/packages/dd-trace/src/debugger/probe_sampler.js +108 -11
  25. package/packages/dd-trace/src/exporters/common/request.js +1 -0
  26. package/packages/dd-trace/src/exporters/common/url.js +1 -1
  27. package/packages/dd-trace/src/id.js +1 -4
  28. package/packages/dd-trace/src/llmobs/agent-manifest.js +296 -0
  29. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
  30. package/packages/dd-trace/src/llmobs/sdk.js +23 -6
  31. package/packages/dd-trace/src/llmobs/span_processor.js +17 -6
  32. package/packages/dd-trace/src/llmobs/tagger.js +54 -1
  33. package/packages/dd-trace/src/llmobs/writers/base.js +3 -1
  34. package/packages/dd-trace/src/llmobs/writers/util.js +3 -1
  35. package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +30 -1
  36. package/packages/dd-trace/src/openfeature/configuration_source.js +17 -2
  37. package/packages/dd-trace/src/openfeature/debug-logging-hook.js +25 -0
  38. package/packages/dd-trace/src/openfeature/flagging_provider.js +29 -0
  39. package/packages/dd-trace/src/openfeature/remote_config.js +9 -0
  40. package/packages/dd-trace/src/openfeature/writers/util.js +43 -4
  41. package/packages/dd-trace/src/opentelemetry/resource-attributes.js +1 -1
  42. package/packages/dd-trace/src/otel-thread-ctx.js +2 -2
  43. package/packages/dd-trace/src/plugins/util/url.js +6 -1
  44. package/packages/dd-trace/src/profiling/profilers/wall.js +4 -10
  45. package/packages/dd-trace/src/proxy.js +2 -0
  46. package/packages/dd-trace/src/serverless.js +5 -0
  47. package/packages/dd-trace/src/storage-channels.js +112 -46
package/README.md CHANGED
@@ -13,8 +13,8 @@ npm install @depup/dd-trace
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [dd-trace](https://www.npmjs.com/package/dd-trace) @ 6.20.0 |
17
- | Processed | 2026-10-07 |
16
+ | Original | [dd-trace](https://www.npmjs.com/package/dd-trace) @ 6.21.0 |
17
+ | Processed | 2026-10-15 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 1 |
20
20
 
package/changes.json CHANGED
@@ -5,6 +5,6 @@
5
5
  "to": "^3.5.2"
6
6
  }
7
7
  },
8
- "timestamp": "2026-10-07T00:36:07.921Z",
8
+ "timestamp": "2026-10-15T00:29:28.451Z",
9
9
  "totalUpdated": 1
10
10
  }
package/index.d.ts CHANGED
@@ -3857,7 +3857,8 @@ declare namespace tracer {
3857
3857
 
3858
3858
  /**
3859
3859
  * Sets inputs, outputs, tags, metadata, and metrics as provided for a given LLM Observability span.
3860
- * Note that with the exception of tags, this method will override any existing values for the provided fields.
3860
+ * Note that with the exception of tags and agent, this method will override any existing values for the provided fields.
3861
+ * Agent fields update earlier agent annotations one top-level field at a time.
3861
3862
  *
3862
3863
  * For example:
3863
3864
  * ```javascript
@@ -3882,7 +3883,7 @@ declare namespace tracer {
3882
3883
  * ```
3883
3884
  *
3884
3885
  * @param span The span to annotate (defaults to the current LLM Observability span if not provided)
3885
- * @param options An object containing the inputs, outputs, tags, metadata, tool definitions, and metrics to set on the span.
3886
+ * @param options An object containing the inputs, outputs, tags, metadata, tool definitions, metrics, and agent to set on the span.
3886
3887
  */
3887
3888
  annotate (options: llmobs.AnnotationOptions): void
3888
3889
  annotate (span: tracer.Span | undefined, options: llmobs.AnnotationOptions): void
@@ -4808,6 +4809,81 @@ declare namespace tracer {
4808
4809
  version? : string
4809
4810
  }
4810
4811
 
4812
+ interface AgentToolParameter {
4813
+ type?: string,
4814
+ required?: boolean
4815
+ }
4816
+
4817
+ /**
4818
+ * A plain JSON Schema object with `type: 'object'`, which is how it is told apart from a parameter map.
4819
+ * Schema-library objects (for example Zod schemas) must be converted first, for example with
4820
+ * `z.toJSONSchema()`, or they are dropped.
4821
+ */
4822
+ interface AgentToolJsonSchema {
4823
+ type: 'object',
4824
+ properties: { [param: string]: { type?: string, [key: string]: unknown } },
4825
+ required?: string[]
4826
+ }
4827
+
4828
+ interface AgentTool {
4829
+ name: string,
4830
+ description?: string,
4831
+ /**
4832
+ * Parameters as `{ [param]: { type, required } }`, or a JSON Schema object, which is flattened to the
4833
+ * same shape.
4834
+ */
4835
+ parameters?: { [param: string]: AgentToolParameter } | AgentToolJsonSchema
4836
+ }
4837
+
4838
+ /**
4839
+ * Inference parameters reported in an agent manifest. Keys are accepted in snake_case or camelCase and
4840
+ * reported in snake_case. Other keys are dropped, since provider-specific settings can carry secrets.
4841
+ */
4842
+ interface AgentModelSettings {
4843
+ frequency_penalty?: number,
4844
+ frequencyPenalty?: number,
4845
+ logit_bias?: { [token: string]: number },
4846
+ logitBias?: { [token: string]: number },
4847
+ logprobs?: boolean,
4848
+ max_tokens?: number,
4849
+ maxTokens?: number,
4850
+ parallel_tool_calls?: boolean,
4851
+ parallelToolCalls?: boolean,
4852
+ presence_penalty?: number,
4853
+ presencePenalty?: number,
4854
+ seed?: number,
4855
+ stop_sequences?: string[],
4856
+ stopSequences?: string[],
4857
+ temperature?: number,
4858
+ timeout?: number,
4859
+ tool_choice?: string,
4860
+ toolChoice?: string,
4861
+ top_k?: number,
4862
+ topK?: number,
4863
+ top_logprobs?: number,
4864
+ topLogprobs?: number,
4865
+ top_p?: number,
4866
+ topP?: number
4867
+ }
4868
+
4869
+ /**
4870
+ * Declares the agent an `agent` span represents, reported as the agent's manifest. Only applies to
4871
+ * `agent` spans. Unreportable values are dropped with a warning, and unset values (`undefined`, `null`,
4872
+ * `''`, `[]`) leave what an earlier annotation declared in place.
4873
+ */
4874
+ interface Agent {
4875
+ /** The agent's name. Defaults to the agent span's name. */
4876
+ name?: string,
4877
+ /** The system instructions the agent runs with. */
4878
+ instructions?: string,
4879
+ /** The model the agent is configured to call. */
4880
+ model?: string,
4881
+ /** Inference parameters. Replaces the settings an earlier annotation declared as a whole. */
4882
+ modelSettings?: AgentModelSettings,
4883
+ /** The tools the agent can call. Replaces tools declared by an earlier annotation. */
4884
+ tools?: AgentTool[]
4885
+ }
4886
+
4811
4887
  /**
4812
4888
  * Annotation options for LLM Observability spans.
4813
4889
  */
@@ -4858,7 +4934,12 @@ declare namespace tracer {
4858
4934
  * A list of ToolDefinition object that represents the tools available to the LLM for this span
4859
4935
  * Each definition requires a `name` and optionally accepts `description`, `schema`, and `version`.
4860
4936
  * */
4861
- toolDefinitions?: ToolDefinition[]
4937
+ toolDefinitions?: ToolDefinition[],
4938
+
4939
+ /**
4940
+ * Declares the agent this span represents. Only used on `agent` spans.
4941
+ */
4942
+ agent?: Agent
4862
4943
  }
4863
4944
 
4864
4945
  interface AnnotationContextOptions {
@@ -4883,6 +4964,13 @@ declare namespace tracer {
4883
4964
  * A Prompt object that represents the prompt used for an LLM call. Only used on `llm` spans.
4884
4965
  */
4885
4966
  prompt?: Prompt,
4967
+
4968
+ /**
4969
+ * Declares the agent running in this context, read when the context is entered. The manifest is
4970
+ * reported on every `agent` span in the context, nested ones included. Use `annotate` on a nested agent
4971
+ * span to declare its own agent.
4972
+ */
4973
+ agent?: Agent,
4886
4974
  }
4887
4975
 
4888
4976
  interface RoutingContextOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/dd-trace",
3
- "version": "6.20.0-depup.0",
3
+ "version": "6.21.0-depup.0",
4
4
  "description": "Datadog APM tracing client for JavaScript (with updated dependencies)",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -39,7 +39,7 @@
39
39
  "test:debugger": "mocha \"packages/dd-trace/test/debugger/**/*.spec.js\"",
40
40
  "test:debugger:ci": "node scripts/c8-ci.js test:debugger",
41
41
  "test:eslint-rules": "node scripts/run-eslint-rule-tests.mjs eslint-rules/*.test.mjs",
42
- "test:trace:core": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- \"packages/dd-trace/test/*.spec.js\" \"packages/dd-trace/test/{agent,ci-visibility,config,crashtracking,datastreams,encode,exporters,log-submission,msgpack,opentelemetry,opentracing,payload-tagging,plugins,remote_config,service-naming,standalone,telemetry,external-logger}/**/*.spec.js\"",
42
+ "test:trace:core": "node scripts/mocha-parallel-files.js --expose-gc --timeout 30000 -- \"packages/dd-trace/test/*.spec.js\" \"packages/dd-trace/test/{agent,ci-visibility,config,crashtracking,datastreams,encode,exporters,log-submission,msgpack,opentelemetry,opentracing,payload-tagging,plugins,remote_config,service-naming,setup,standalone,telemetry,external-logger}/**/*.spec.js\"",
43
43
  "test:trace:core:ci": "node scripts/c8-ci.js test:trace:core",
44
44
  "test:trace:guardrails": "mocha \"packages/dd-trace/test/guardrails/**/*.spec.js\"",
45
45
  "test:trace:guardrails:ci": "node scripts/c8-ci.js test:trace:guardrails",
@@ -198,7 +198,7 @@
198
198
  "@datadog/native-appsec": "11.0.3",
199
199
  "@datadog/native-iast-taint-tracking": "4.2.1",
200
200
  "@datadog/native-metrics": "4.0.0",
201
- "@datadog/pprof": "5.19.0",
201
+ "@datadog/pprof": "5.20.0",
202
202
  "@datadog/wasm-js-rewriter": "5.0.4",
203
203
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
204
204
  "@opentelemetry/api-logs": "<1.0.0",
@@ -221,7 +221,6 @@
221
221
  "@types/sinon": "^22.0.0",
222
222
  "@vercel/nft": "^1.11.0",
223
223
  "@yarnpkg/lockfile": "^1.1.0",
224
- "axios": "^1.20.0",
225
224
  "benchmark": "^2.1.4",
226
225
  "body-parser": "^2.3.0",
227
226
  "bun": "1.4.2",
@@ -232,14 +231,14 @@
232
231
  "eslint-plugin-import-x": "^4.16.2",
233
232
  "eslint-plugin-jsdoc": "^64.5.4",
234
233
  "eslint-plugin-mocha": "^12.0.2",
235
- "eslint-plugin-n": "^18.3.0",
234
+ "eslint-plugin-n": "^18.4.0",
236
235
  "eslint-plugin-promise": "^7.3.0",
237
236
  "eslint-plugin-regexp": "^3.3.1",
238
- "eslint-plugin-sonarjs": "^4.2.1",
237
+ "eslint-plugin-sonarjs": "^4.2.2",
239
238
  "eslint-plugin-unicorn": "^74.0.0",
240
239
  "express": "^5.1.0",
241
240
  "glob": "^10.4.5",
242
- "globals": "^17.12.0",
241
+ "globals": "^17.13.0",
243
242
  "graphql": "*",
244
243
  "husky": "^9.1.7",
245
244
  "istanbul-lib-coverage": "^3.2.2",
@@ -280,8 +279,8 @@
280
279
  },
281
280
  "depsUpdated": 1,
282
281
  "originalPackage": "dd-trace",
283
- "originalVersion": "6.20.0",
284
- "processedAt": "2026-10-07T00:36:24.046Z",
282
+ "originalVersion": "6.21.0",
283
+ "processedAt": "2026-10-15T00:29:46.639Z",
285
284
  "smokeTest": "passed"
286
285
  }
287
286
  }
@@ -80,6 +80,19 @@ module.exports = [
80
80
  },
81
81
  channelName: 'Runner_run',
82
82
  },
83
+ {
84
+ module: {
85
+ name: '@wdio/runner',
86
+ versionRange: '>=9.0.0',
87
+ filePath: 'build/index.js',
88
+ },
89
+ functionQuery: {
90
+ className: 'Runner',
91
+ methodName: '_startSession',
92
+ kind: 'Async',
93
+ },
94
+ channelName: 'Runner_startSession',
95
+ },
83
96
  {
84
97
  module: {
85
98
  name: '@wdio/runner',
@@ -130,6 +143,33 @@ module.exports = [
130
143
  channelName: 'BaseReporter_waitForSync',
131
144
  transform: 'waitForAsyncEnd',
132
145
  },
146
+ {
147
+ module: {
148
+ name: '@wdio/mocha-framework',
149
+ versionRange: '>=9.0.0',
150
+ filePath: 'build/index.js',
151
+ },
152
+ functionQuery: {
153
+ className: 'MochaAdapter',
154
+ methodName: 'init',
155
+ kind: 'Async',
156
+ },
157
+ channelName: 'MochaAdapter_init',
158
+ },
159
+ {
160
+ module: {
161
+ name: '@wdio/mocha-framework',
162
+ versionRange: '>=9.0.0',
163
+ filePath: 'build/index.js',
164
+ },
165
+ astQuery: 'VariableDeclarator[id.name="MochaAdapter"] > ClassExpression > ClassBody > ' +
166
+ 'MethodDefinition[key.name="init"] ReturnStatement > ' +
167
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"], ' +
168
+ 'ClassDeclaration[id.name="MochaAdapter"] > ClassBody > MethodDefinition[key.name="init"] ReturnStatement > ' +
169
+ 'CallExpression[callee.object.name="promise"][callee.property.name="then"]',
170
+ channelName: 'MochaAdapter_init',
171
+ transform: 'waitForAsyncEnd',
172
+ },
133
173
  {
134
174
  module: {
135
175
  name: '@wdio/jasmine-framework',
@@ -495,7 +535,7 @@ module.exports = [
495
535
  {
496
536
  module: {
497
537
  name: 'jasmine-core',
498
- versionRange: '>=5.0.0 <6.0.0',
538
+ versionRange: '>=5.0.0 <7.0.0',
499
539
  filePath: 'lib/jasmine-core/jasmine.js',
500
540
  },
501
541
  astQuery: 'AssignmentExpression[left.object.object.name="Spec"]' +
@@ -508,7 +548,7 @@ module.exports = [
508
548
  {
509
549
  module: {
510
550
  name: 'jasmine-core',
511
- versionRange: '>=5.0.0 <6.0.0',
551
+ versionRange: '>=5.0.0 <7.0.0',
512
552
  filePath: 'lib/jasmine-core/jasmine.js',
513
553
  },
514
554
  astQuery: 'AssignmentExpression[left.object.object.name="Spec"]' +
@@ -521,7 +561,20 @@ module.exports = [
521
561
  {
522
562
  module: {
523
563
  name: 'jasmine-core',
524
- versionRange: '>=5.0.0 <6.0.0',
564
+ versionRange: '>=5.0.0 <7.0.0',
565
+ filePath: 'lib/jasmine-core/jasmine.js',
566
+ },
567
+ functionQuery: {
568
+ className: 'Spec',
569
+ methodName: 'status',
570
+ kind: 'Sync',
571
+ },
572
+ channelName: 'Spec_attemptDone',
573
+ },
574
+ {
575
+ module: {
576
+ name: 'jasmine-core',
577
+ versionRange: '>=5.0.0 <7.0.0',
525
578
  filePath: 'lib/jasmine-core/jasmine.js',
526
579
  },
527
580
  functionQuery: {
@@ -534,7 +587,7 @@ module.exports = [
534
587
  {
535
588
  module: {
536
589
  name: 'jasmine-core',
537
- versionRange: '>=5.0.0 <6.0.0',
590
+ versionRange: '>=5.0.0 <7.0.0',
538
591
  filePath: 'lib/jasmine-core/jasmine.js',
539
592
  },
540
593
  functionQuery: {
@@ -45,6 +45,7 @@
45
45
  "@wdio/config/build/node/index.js": "@wdio/config",
46
46
  "@wdio/jasmine-framework/build/index.js": "@wdio/jasmine-framework",
47
47
  "@wdio/local-runner/build/index.js": "@wdio/local-runner",
48
+ "@wdio/mocha-framework/build/index.js": "@wdio/mocha-framework",
48
49
  "@wdio/runner/build/index.js": "@wdio/runner",
49
50
  "@wdio/utils/build/index.js": "@wdio/utils",
50
51
  "ai/dist/index.js": "ai",
@@ -10,6 +10,7 @@ const { performance } = require('node:perf_hooks')
10
10
  const path = require('path')
11
11
  const satisfies = require('../../../vendor/dist/semifies')
12
12
  const { DD_MAJOR } = require('../../../version')
13
+ const { storage } = require('../../datadog-core')
13
14
  const shimmer = require('../../datadog-shimmer')
14
15
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
15
16
  const log = require('../../dd-trace/src/log')
@@ -88,6 +89,8 @@ const testSkippedCh = channel('ci:jest:test:skip')
88
89
  const testFinishCh = channel('ci:jest:test:finish')
89
90
  const testErrCh = channel('ci:jest:test:err')
90
91
  const testFnCh = channel('ci:jest:test:fn')
92
+ const snapshotStorage = storage('ci:jest:snapshots')
93
+ let activeSnapshotTrackers = 0
91
94
  const testSuiteHookFnCh = channel('ci:jest:test-suite:hook:fn')
92
95
  const consoleLogSubmissionCh = channel('ci:log-submission:console')
93
96
  const logSubmissionFlushCh = channel('ci:log-submission:flush')
@@ -666,7 +669,12 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
666
669
  #discardedEfdRetryTests
667
670
  #earlyFlakeDetectionRetryPolicy
668
671
  #efdRetryGatesByName
672
+ #expect
669
673
  #pendingPre30ConcurrentTests
674
+ /** @type {(() => void)|undefined} */
675
+ #restoreSnapshotState
676
+ /** @type {Set<string>|undefined} */
677
+ #snapshotTestNames
670
678
 
671
679
  constructor (config, context) {
672
680
  super(config, context)
@@ -1445,6 +1453,98 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1445
1453
  }
1446
1454
  }
1447
1455
 
1456
+ getSnapshotState () {
1457
+ return this.#expect?.getState?.()?.snapshotState
1458
+ }
1459
+
1460
+ /**
1461
+ * Attributes snapshot increments to the executing test when serial and concurrent bodies can overlap.
1462
+ * Both Jest and image snapshot matchers write this shared counter directly.
1463
+ */
1464
+ #trackQuarantinedSnapshots () {
1465
+ if (!this.hasConcurrentTests || !this.testManagementTestsForThisSuite?.quarantined?.length) return
1466
+
1467
+ const snapshotState = this.getSnapshotState()
1468
+ const descriptor = snapshotState && Object.getOwnPropertyDescriptor(snapshotState, 'unmatched')
1469
+ if (!descriptor?.configurable || typeof descriptor.value !== 'number') return
1470
+
1471
+ let unmatched = descriptor.value
1472
+ try {
1473
+ Object.defineProperty(snapshotState, 'unmatched', {
1474
+ configurable: true,
1475
+ enumerable: descriptor.enumerable,
1476
+ get () { return unmatched },
1477
+ /** @param {number} value */
1478
+ set (value) {
1479
+ const ctx = /** @type {{ unmatchedSnapshots?: number }|undefined} */ (snapshotStorage.getStore())
1480
+ if (ctx?.unmatchedSnapshots !== undefined && value > unmatched) {
1481
+ ctx.unmatchedSnapshots += value - unmatched
1482
+ }
1483
+ unmatched = value
1484
+ },
1485
+ })
1486
+ } catch (error) {
1487
+ log.error('Could not track quarantined Jest snapshots: %s', error)
1488
+ return
1489
+ }
1490
+
1491
+ if (activeSnapshotTrackers++ === 0) testFnCh.bindStore(snapshotStorage)
1492
+ this.#restoreSnapshotState = () => {
1493
+ try {
1494
+ Object.defineProperty(snapshotState, 'unmatched', { ...descriptor, value: unmatched })
1495
+ } catch (error) {
1496
+ log.error('Could not restore Jest snapshot state: %s', error)
1497
+ } finally {
1498
+ if (--activeSnapshotTrackers === 0) testFnCh.unbindStore(snapshotStorage)
1499
+ }
1500
+ }
1501
+ }
1502
+
1503
+ /**
1504
+ * Keeps the snapshot results of a quarantined test from failing the run.
1505
+ *
1506
+ * Jest fails the run on unmatched or obsolete snapshots even when no test failed.
1507
+ *
1508
+ * @param {object} test
1509
+ */
1510
+ ignoreQuarantinedSnapshotResults (test) {
1511
+ const ctx = testContexts.get(test)
1512
+ const unmatchedBeforeTest = ctx?.unmatchedSnapshotsBeforeTest
1513
+ const unmatchedSnapshots = ctx?.unmatchedSnapshots
1514
+ // Jest retries the attempts that still have errors and resets their snapshot results itself.
1515
+ if ((unmatchedBeforeTest === undefined && unmatchedSnapshots === undefined) || test.errors?.length) return
1516
+
1517
+ const snapshotState = this.getSnapshotState()
1518
+ if (!snapshotState) return
1519
+
1520
+ if (unmatchedSnapshots !== undefined) {
1521
+ snapshotState.unmatched -= unmatchedSnapshots
1522
+ ctx.unmatchedSnapshots = 0
1523
+ } else if (snapshotState.unmatched > unmatchedBeforeTest) {
1524
+ snapshotState.unmatched = unmatchedBeforeTest
1525
+ }
1526
+ // Jest's name-based marker can consume other tests' keys, so delete only keys owned by this test.
1527
+ const keys = snapshotState._uncheckedKeys
1528
+ const testNames = this.#snapshotTestNames
1529
+ if (!keys?.delete || !testNames) return
1530
+ const testName = getRawJestTestName(test)
1531
+ const hintPrefix = `${testName}: `
1532
+ for (const key of keys) {
1533
+ const snapshotName = key.slice(0, key.lastIndexOf(' '))
1534
+ if (snapshotName !== testName && !snapshotName.startsWith(hintPrefix)) continue
1535
+ let belongsToAnotherTest = false
1536
+ // Snapshot names do not identify their owner when another registered name matches the same key.
1537
+ for (const name of testNames) {
1538
+ if (name !== testName &&
1539
+ (snapshotName === name || snapshotName.startsWith(`${name}: `))) {
1540
+ belongsToAnotherTest = true
1541
+ break
1542
+ }
1543
+ }
1544
+ if (!belongsToAnotherTest) keys.delete(key)
1545
+ }
1546
+ }
1547
+
1448
1548
  // This function returns an array if the known tests are valid and null otherwise.
1449
1549
  getKnownTestsForSuite (suiteKnownTests) {
1450
1550
  // `suiteKnownTests` is `this.testEnvironmentOptions._ddKnownTests`,
@@ -1819,6 +1919,11 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1819
1919
  if (event.concurrent) {
1820
1920
  this.hasConcurrentTests = true
1821
1921
  }
1922
+ const registeredTest = getTestEntries(state.currentDescribeBlock)?.at(-1)
1923
+ if (registeredTest && this.testManagementTestsForThisSuite?.quarantined?.length) {
1924
+ this.#snapshotTestNames ??= new Set()
1925
+ this.#snapshotTestNames.add(getRawJestTestName(registeredTest))
1926
+ }
1822
1927
  if (event.failing) {
1823
1928
  return
1824
1929
  }
@@ -1827,7 +1932,6 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1827
1932
  const concurrentTestContexts = this.concurrentTestContexts.get(testFullName)
1828
1933
  const concurrentTestState = this.concurrentTestStates.get(event.fn) ||
1829
1934
  concurrentTestContexts?.at(-1)?.concurrentTestState
1830
- const registeredTest = getTestEntries(state.currentDescribeBlock)?.at(-1)
1831
1935
  if (concurrentTestState && registeredTest?.fn === event.fn) {
1832
1936
  testContexts.set(registeredTest, concurrentTestState.ctx)
1833
1937
  }
@@ -1925,10 +2029,12 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
1925
2029
  }
1926
2030
 
1927
2031
  if (event.name === 'run_start') {
2032
+ this.#trackQuarantinedSnapshots()
1928
2033
  const registerResultHandler = dynamicAtrResultHandlerRegistrations.get(this)
1929
2034
  dynamicAtrResultHandlerRegistrations.delete(this)
1930
2035
  registerResultHandler?.()
1931
2036
  } else if (event.name === 'setup') {
2037
+ this.#expect = event.runtimeGlobals?.expect ?? this.global.expect
1932
2038
  this.wrapConcurrentTest(state)
1933
2039
  this.bindTestEach(this.global.test)
1934
2040
  }
@@ -2044,6 +2150,13 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2044
2150
  ctx.concurrentTestState = concurrentTestState
2045
2151
  concurrentTestState.ctx = ctx
2046
2152
  }
2153
+ if (isQuarantined && !isAttemptToFix && !event.test.concurrent && !ctx.concurrentTestState) {
2154
+ if (this.#restoreSnapshotState) {
2155
+ ctx.unmatchedSnapshots = 0
2156
+ } else if (!this.hasConcurrentTests) {
2157
+ ctx.unmatchedSnapshotsBeforeTest = this.getSnapshotState()?.unmatched
2158
+ }
2159
+ }
2047
2160
  testContexts.set(event.test, ctx)
2048
2161
 
2049
2162
  if (isAttemptToFix) {
@@ -2282,6 +2395,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2282
2395
  event.test.errors = []
2283
2396
  }
2284
2397
  }
2398
+ this.ignoreQuarantinedSnapshotResults(event.test)
2285
2399
 
2286
2400
  // Quarantine must consume terminal failures before we save errors for Jest's final result.
2287
2401
  if (dynamicAtrCount !== undefined && failedAllTests && event.test.errors?.length) {
@@ -2359,6 +2473,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2359
2473
  ctx.currentStore = undefined
2360
2474
  }
2361
2475
  } else if (event.name === 'run_finish') {
2476
+ this.#restoreSnapshotState?.()
2477
+ this.#restoreSnapshotState = undefined
2362
2478
  this.removeDiscardedEfdRetries()
2363
2479
  for (const [test, errors] of atrSuppressedErrors) {
2364
2480
  // Do not restore errors for non-ATF quarantined tests — they should stay suppressed
@@ -2528,6 +2644,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
2528
2644
  }
2529
2645
 
2530
2646
  teardown () {
2647
+ this.#restoreSnapshotState?.()
2648
+ this.#restoreSnapshotState = undefined
2531
2649
  if (this._globalProxy?.propertyToValue) {
2532
2650
  for (const [key] of this._globalProxy.propertyToValue) {
2533
2651
  if (typeof key === 'string' && key.startsWith('_dd')) {