vitest-auto-spy 5.29.0 → 5.31.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.
package/AGENTS.md CHANGED
@@ -216,7 +216,10 @@ the test must not touch the real one.
216
216
  verbose for the most common thing it says — _observe one method of the object under test and let it
217
217
  run_ — so the helper says exactly that and hands back the single spy. It is also the drop-in for a
218
218
  bare `vi.spyOn(component, 'method')` where a preset's `no-restricted-properties` bans `vi.spyOn`:
219
- same default semantics, record and call through, and `restoreSpiedInstance` puts it back.
219
+ same default semantics, record and call through, and `restoreSpiedInstance` puts it back. It is a
220
+ core export — `import { spyOnOwnMethod } from 'vitest-auto-spy'`, or the runner entry on
221
+ `bun test` / `node --test` — while `vitest-auto-spy/angular` and `vitest-auto-spy/nestjs` have no
222
+ core re-export, so those suites import it from the root; `spyOnVoidMethod` below is the same.
220
223
 
221
224
  **Do not `createSpyFromInstance` a DOM node that must keep living a DOM life.** Discovery walks the
222
225
  node's prototype chain, and past the component's own class that chain is the engine's: happy-dom's
@@ -1508,15 +1511,24 @@ setupAutoSpy({ strayTimers: true }); // wrap the schedulers, sweep the survivors
1508
1511
 
1509
1512
  The pieces are exported too — `trackStrayTimers()` (idempotent, returns the undo),
1510
1513
  `cancelStrayTimers()` (returns how many it cancelled), `countStrayTimers()` and
1511
- `describeStrayTimers()` (each pending timer's kind, the spec file that scheduled it and up to five
1512
- frames), all from `vitest-auto-spy/setup`. Use `expect(countStrayTimers()).toBe(0)` in an `afterEach`
1513
- to make a leak fail rather than be tidied away, or take the per-file report from the sweep itself —
1514
- `timers` carries the same origins, so the failure diff names the file and the scheduling call:
1514
+ `describeStrayTimers()` (each pending timer's `kind`, the `delay` of a timeout or interval, the spec
1515
+ `file` that scheduled it and up to five `frames`), all from `vitest-auto-spy/setup`. Use
1516
+ `expect(countStrayTimers()).toBe(0)` in an `afterEach` to make a leak fail rather than be tidied
1517
+ away, or take the per-file report from the sweep itself — `timers` carries the same origins, so the
1518
+ failure diff names the file and the scheduling call:
1515
1519
 
1516
1520
  ```ts
1517
1521
  setupAutoSpy({ strayTimers: true, onStrayTimers: ({ timers }) => expect(timers).toEqual([]) });
1518
1522
  ```
1519
1523
 
1524
+ `frames` starts below the tracking wrapper and is up to forty frames deep, so a zone or an rxjs
1525
+ scheduler in between does not hide the caller: project frames come first; when the call came from
1526
+ dependencies only, their frames stand in. The package's own frames are never quoted, from source or
1527
+ from `dist`. `onStrayTimers: 'throw'` fails the file with a message that lists every stray as
1528
+ `timeout (300 ms) from <file> <frames[0]>`; a handler that prints its own message should print the
1529
+ same `kind`, `delay`, `file` and `frames[0]` — they are what makes a report that only reproduces
1530
+ under a slow coverage run actionable the first time.
1531
+
1520
1532
  A stray whose `file` is not the file that failed was scheduled after the previous file's sweep —
1521
1533
  the previous file is the one to fix.
1522
1534
 
@@ -1651,7 +1663,13 @@ initialisation — and the `afterAll` takes off everything added since. The piec
1651
1663
  `removeStrayListeners()` (returns how many), `countStrayListeners()` (throws before
1652
1664
  `trackStrayListeners()` has run, like the timer counter) and `describeStrayListeners()` — each
1653
1665
  stray's target, type, spec file and up to five frames, the list `onStrayListeners({ removed, listeners })`
1654
- receives when a file should fail instead: `onStrayListeners: ({ removed }) => expect(removed).toBe(0)`.
1666
+ receives when a file should fail instead: `onStrayListeners: ({ removed }) => expect(removed).toBe(0)`,
1667
+ or `onStrayListeners: 'throw'`, whose message lists each as `keydown on document from <file> <frames[0]>`.
1668
+ A listener has `type` and `target` where a timer has `kind` and `delay` — a handler that prints its own
1669
+ message prints those four fields instead.
1670
+ With `strayTimers` on too, both reports run after both sweeps and both run even if the first throws —
1671
+ a handler or `'throw'` alike; two failures surface as one `AggregateError`, so a throwing report never
1672
+ leaves a timer uncancelled.
1655
1673
  Under jsdom a listener registered with `{ once: true }` that already fired stays counted until
1656
1674
  something removes it: the wrapper cannot observe the firing without breaking identity-based
1657
1675
  `removeEventListener` from the code under test, and removing an already-fired listener is a no-op
@@ -2160,8 +2178,8 @@ an unconfigured call returns — a semantic switch, not a grade; the name was ta
2160
2178
  `unconfiguredReads`, its read side (survey with `onUnstubbedRead` before turning it on),
2161
2179
  `blockNetwork` (changes the code under test), `restoreMocks` (drops `beforeAll` spies), failing on
2162
2180
  stray-timer counts (the sweep fails the file from `afterAll`, and a callback scheduled after the
2163
- previous file's sweep is charged to the next — opt in with
2164
- `onStrayTimers: ({ timers }) => expect(timers).toEqual([])`, whose diff names each one's file), and
2181
+ previous file's sweep is charged to the next — opt in with `onStrayTimers: 'throw'`, whose message
2182
+ names each one's file, or `onStrayTimers: ({ timers }) => expect(timers).toEqual([])`), and
2165
2183
  `enableAngularDiagnostics()`, which lives in `/angular/diagnostics` — call it in the same setup file as the Angular half of strict.
2166
2184
 
2167
2185
  `misconfiguration: 'throw'` on its own makes the library's misuse reports — an `onlyMethodsToSpyOn`
@@ -3883,6 +3901,7 @@ blanket downgrade so those keep their severity; do not copy the two names into a
3883
3901
  | `no-unregistered-inject-spy` | `error` | — | `injectSpy(X)` for a token this file never registered → the real instance, whose spy helpers exist only for the compiler |
3884
3902
  | `prefer-render-shallow` | `warn` | suggest | `TestBed.createComponent` in a file that never reads the template → `renderShallow(X)`; 0.24× the per-test cycle at 100 children |
3885
3903
  | `prefer-set-inputs` | `warn` | suggest | a run of `fixture.componentRef.setInput('title', v)` on one fixture → `await setInputs(fixture, { title: v })` — the name is resolved against the compiled definition before the first write (an undeclared one is an `NG0303` and no change) and the value is typed. The run collapses into one call and a `detectChanges()` under it goes; offered, not applied, because `stable()` ticks and a zone.js suite answers that with `NG0101` |
3904
+ | `prefer-spy-on-own-method` | `warn` | `--fix` / suggest | `createSpyFromInstance(x, { onlyMethodsToSpyOn: ['m'], passthrough: true })` read for `m` alone — `.m` on the call, `const { m } = …`, a bare statement, or a name read only as `v.m` → `spyOnOwnMethod(x, 'm')`; the same whitelist with `returns: { m: undefined }` → `spyOnVoidMethod(x, 'm')`. Both fix, import and all; a `Spy<X>` annotation becomes `Spy<X>['m']` in a suggestion. A bare `returns: { m: undefined }` seed is a suggestion, offered only on a real event or element — `new MouseEvent(…)`, `document.createElement(…)`, `fixture.nativeElement` — never on a double |
3886
3905
  | `prefer-observer-stub` | `error` | — | a hand-rolled observer global → `stubIntersectionObserver()` / `stubResizeObserver()` / `stubMutationObserver()`; the manual save-and-restore goes too, `restoreMockedProps()` runs the undo |
3887
3906
  | `no-hand-assigned-global` | `error` | — | a double assigned to a global (`global.fetch = vi.fn()`, `window.matchMedia = vi.fn()`, `window.localStorage = { getItem: vi.fn() }`) with no restore in `afterEach` / `afterAll` / `onTestFinished` → `mockValueProp(globalThis, name, value)` or `vi.stubGlobal` + `unstubGlobals`; `blockNetwork()` for network globals, `stubWebStorage()` for the storages; the three observers stay with `prefer-observer-stub` |
3888
3907
  | `prefer-stub-response` | `error` | — | an object literal cast to `Response` (`as Response`, `as unknown as Response`, `<Response>{ … }`) or `createMock<Response>(…)` / `createAutoMock<Response>(…)` → `stubResponse({ body })` from `/setup`; the literal answers `undefined` for every member it does not list (`status`, `headers`, `text()`) and the cast is what makes that compile. `Response` must resolve to the **global**, so an Express handler's or a generated client's `Response` is never reported |
@@ -3910,14 +3929,14 @@ blanket downgrade so those keep their severity; do not copy the two names into a
3910
3929
  | `no-save-arguments-by-value` | `error` | — | `spy.calls.saveArgumentsByValue()` — a no-op here, so the spec silently asserts on post-mutation state |
3911
3930
  | `prefer-native-spy-api` | `error` | `--fix` / suggest | `.and` / `.calls` where the spy's own API says the same thing — turn it on for the last mile off the jasmine shim |
3912
3931
 
3913
- Forty-eight rules, **every one an `error` since 4.0.0 except `prefer-render-shallow`,
3932
+ Forty-nine rules, **every one an `error` since 4.0.0 except `prefer-render-shallow`,
3914
3933
  `no-stub-class-double`, `no-structural-double`, `prefer-create-mock`, `no-instance-lifecycle-spy`,
3915
- `prefer-set-inputs` and `no-unasserted-argument`**; five fix on their own, eighteen offer suggestions. Forty-five are syntactic; `no-private-member-access`, `no-mistyped-use-value` and
3934
+ `prefer-set-inputs`, `no-unasserted-argument` and `prefer-spy-on-own-method`**; six fix on their own, nineteen offer suggestions. Forty-six are syntactic; `no-private-member-access`, `no-mistyped-use-value` and
3916
3935
  `no-unknown-use-value-key` read types, and all three report nothing at all without `parserOptions.project` / `projectService`
3917
3936
  rather than guessing. `no-compile-components` waits the same way for a fact no file holds — which
3918
3937
  builder the project has — and reports nothing until `{ builder: 'inline-resources' }` states it. The config used to be a graded mix of `error` / `warn` / `off`, which decided for the
3919
3938
  consumer how much each finding mattered — a `warn` nothing reads is `off` with extra output. The
3920
- seven `warn`s left are not judgements about how much a finding matters. `prefer-render-shallow` is
3939
+ eight `warn`s left are not judgements about how much a finding matters. `prefer-render-shallow` is
3921
3940
  about the _kind_ of finding: every other rule names something wrong or dead, while this one names a
3922
3941
  file that could render more cheaply, and `renderShallow` is a migration a suite either takes or does
3923
3942
  not. At `error` the plugin would gate that migration — 491 findings across 398 of one consumer's
@@ -3940,7 +3959,8 @@ repair _needs_ rather than on its evidence: both of its readings are facts out o
3940
3959
  subject some other test in the same file pins with `toHaveBeenCalledWith`, a title saying `with` over
3941
3960
  a body whose every assertion is a bare call — but the repair is the argument list the test should
3942
3961
  have named, which is the one thing the rule cannot supply. Every `error` here names an edit or names
3943
- a helper; this one names a question for the author. Set any of the seven `warn`s to `'error'` once the batch is done. Three of
3962
+ a helper; this one names a question for the author. `prefer-spy-on-own-method` names a shorter spelling of a correct call — the
3963
+ `createSpyFromInstance` it reports does exactly what the helper does — and its exact shapes carry a fix. Set any of the eight `warn`s to `'error'` once the batch is done. Three of
3944
3964
  them can report on a _correct_ project, and only one has an option:
3945
3965
  `jasmine-namespace-without-entry` takes `['error', { setupModules: ['./test-setup'] }]`, naming the
3946
3966
  file where `enableJasmineCompat()` is called; `prefer-native-spy-api` goes `'off'` for as long as a
package/CHANGELOG.md CHANGED
@@ -10,6 +10,90 @@ The latest released version here must always match the one published on
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [5.31.0] - 2026-09-25
14
+
15
+ ### Added
16
+
17
+ - **`onStrayTimers: 'throw'` and `onStrayListeners: 'throw'` fail the file with every stray named.**
18
+ Failing a file on a stray took a handler, and a handler that printed its own message had to rebuild
19
+ the line the `--detect-async-leaks` warning already prints. `'throw'` fails the file from the same
20
+ `afterAll` a handler runs in, with one line per stray — `timeout (300 ms) from <file> <frames[0]>`
21
+ for a timer, `keydown on document from <file> <frames[0]>` for a listener — every one, not the
22
+ warning's first three. The sweep still cancels and removes first; the preset is unchanged. The option
23
+ type widens from a handler to a handler or `'throw'`. With both set to `'throw'`, a file that leaks
24
+ a timer and a listener fails with both errors in one `AggregateError`, the timer already cancelled.
25
+
26
+ ### Fixed
27
+
28
+ - **A throwing `onStrayListeners` no longer leaves the file's stray timers running.** The timer
29
+ sweep was its own `afterAll`, and Vitest skips the remaining `afterAll` hooks once one throws: with
30
+ `strayTimers` and `strayListeners` both on, a failing listener report hid the timer report and left
31
+ the timer uncancelled, free to fire in the next file on the worker under `isolate: false`. The timer
32
+ sweep now runs in the file-boundary hook, after the other repairs and before any handler; every
33
+ handler runs, and two failures are thrown together as an `AggregateError`. A single failure is
34
+ thrown as it was, and non-throwing handlers behave as before.
35
+ - **`calledWith(new URL(a))` no longer answers a call made with `new URL(b)`.** A URL keeps its state
36
+ in internal slots, so the argument key rendered every one as `URL{}` and any two URLs matched each
37
+ other — `mustBeCalledWith` included, which then let the wrong URL through instead of throwing.
38
+ `toHaveBeenCalledWith` compares them by `href`, and so do `calledWith` and `mustBeCalledWith` now,
39
+ on the key path and beside an asymmetric matcher alike. A mismatch message prints the URL instead
40
+ of `URL{}`.
41
+
42
+ ### Docs
43
+
44
+ - **A custom `onStrayListeners` handler is told which fields to print.** The advice to print `kind`,
45
+ `delay` and `frames[0]` sat next to the timer handler only, and a listener has neither `kind` nor
46
+ `delay`: the listener section now names `type`, `target`, `file` and `frames[0]`.
47
+ - **The Russian API table lists the `delay` `describeStrayTimers()` returns**, as the English one does.
48
+ - **"Which of the forty-nine apply to you" counts forty-five core rules, not forty-four.** 5.30.0 added
49
+ `prefer-spy-on-own-method` and bumped every total to forty-nine but this one, so core and jasmine
50
+ rules added up to forty-eight.
51
+
52
+ ## [5.30.0] - 2026-09-25
53
+
54
+ ### Added
55
+
56
+ - **`prefer-spy-on-own-method`, in `recommended` at `warn`.** It finds the long spelling of the two
57
+ 5.29 helpers, which a text search misses once the call spans several lines:
58
+ `createSpyFromInstance(x, { onlyMethodsToSpyOn: ['m'], passthrough: true })` read for `m` alone —
59
+ `.m` on the call, `const { m } = …`, a bare statement, or a name read only as `v.m` — is
60
+ `spyOnOwnMethod(x, 'm')`, and the same whitelist with `returns: { m: undefined }` is
61
+ `spyOnVoidMethod(x, 'm')`. Both are exact, so `--fix` rewrites the call and every `v.m` read, imports
62
+ the helper beside the factory and drops the factory's import once nothing else uses it. A
63
+ `Spy<X>` annotation becomes `Spy<X>['m']` in a suggestion. A bare `returns: { m: undefined }` seed,
64
+ whose discovery also spies every other method, is offered as a suggestion only on a real event or
65
+ element (`new MouseEvent(…)`, `document.createElement(…)`, `fixture.nativeElement`, one name away
66
+ included), never on a double. `warn`, because the call it reports is correct. `/eslint-plugin`
67
+ grows 51.61 → 53.56 kB min+gzip (+1.96 kB, +3.8 %), all of it this rule: the fixer that follows
68
+ every `v.m` read, rewrites imports and the `Spy<X>` annotation. The plugin runs in the linter, never
69
+ in a test, and no runtime entry imports it.
70
+
71
+ ### Fixed
72
+
73
+ - **A stray timer's origin names the code that scheduled it, not the tracking wrapper.** Built from
74
+ `dist`, the report quoted `at captureOrigin (…/node_modules/vitest-auto-spy/dist/setup.js)`: the
75
+ filter for the wrapper's own frames matched the source file name, which the bundle does not have,
76
+ and twelve frames ran out inside a zone or an rxjs scheduler before the first line outside
77
+ dependencies, so the fallback quoted the wrapper. The stack is now cut at the installed
78
+ `setTimeout` / `setInterval` / `requestAnimationFrame` wrapper and taken forty frames deep below it;
79
+ the package's own frames are never quoted, and when the call came from dependencies only, their
80
+ frames stand in. The same `dist` filter now applies to stray listeners, console calls and
81
+ rejections. A flaky stray that shows up only under a slow coverage run is now actionable from the
82
+ first report.
83
+ - **`StrayTimer` carries the `delay`, and the `--detect-async-leaks` warning prints it.** Each
84
+ timeout and interval in `describeStrayTimers()` and in `onStrayTimers`' `timers` now has the delay
85
+ it was scheduled with (a frame has none), and the warning reads `timeout (300 ms) from …` instead
86
+ of `timeout from …`. An additive field; a handler that prints its own message should print `kind`,
87
+ `delay` and `frames[0]`.
88
+
89
+ ### Docs
90
+
91
+ - **`AGENTS.md` says which entry `spyOnOwnMethod` and `spyOnVoidMethod` come from.** The §2
92
+ introduction sat in Angular-flavoured company, and `vitest-auto-spy/angular` has no core
93
+ re-export — an Angular-suite reader importing the helper there hit a missing export. The
94
+ paragraph now names the core entry (root, or the runner entry off Vitest), as the docs-site
95
+ page already does.
96
+
13
97
  ## [5.29.0] - 2026-09-24
14
98
 
15
99
  ### Added
@@ -7845,7 +7929,9 @@ by hand there, in more than one place, by more than one person.
7845
7929
  `mockAccessorsProp`.
7846
7930
  - Dual ESM + CJS build with type declarations; 100% test coverage.
7847
7931
 
7848
- [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.29.0...HEAD
7932
+ [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.31.0...HEAD
7933
+ [5.31.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.30.0...v5.31.0
7934
+ [5.30.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.29.0...v5.30.0
7849
7935
  [5.29.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.28.0...v5.29.0
7850
7936
  [5.28.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.27.0...v5.28.0
7851
7937
  [5.27.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.26.0...v5.27.0
package/README.md CHANGED
@@ -23,7 +23,7 @@ faster at suite scale ([benchmarks](#benchmarks)) — and for
23
23
  [![downloads per month](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.npmjs.org%2Fdownloads%2Fpoint%2Flast-month%2Fvitest-auto-spy&query=%24.downloads&color=brightgreen&logo=npm&label=downloads%2Fmonth)](https://www.npmjs.com/package/vitest-auto-spy)
24
24
  [![downloads over 18 months](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.npmjs.org%2Fdownloads%2Fpoint%2F2026-06-21%3A2030-01-01%2Fvitest-auto-spy&query=%24.downloads&color=brightgreen&logo=npm&label=downloads%2F18mo)](https://www.npmjs.com/package/vitest-auto-spy)
25
25
  [![CI](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml/badge.svg)](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
26
- [![minzipped size](https://img.shields.io/badge/minzip-23.2%20kB-brightgreen)](#install)
26
+ [![minzipped size](https://img.shields.io/badge/minzip-23.3%20kB-brightgreen)](#install)
27
27
  [![types](https://img.shields.io/npm/types/vitest-auto-spy?logo=typescript&logoColor=white)](https://www.npmjs.com/package/vitest-auto-spy)
28
28
  [![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
29
29
  [![license](https://img.shields.io/npm/l/vitest-auto-spy?color=blue)](./LICENSE)
@@ -81,7 +81,7 @@ faster at suite scale ([benchmarks](#benchmarks)) — and for
81
81
  - 🧩 Module mocks that prove they applied — `assertMocked`, `moduleNamespace`, for a `vi.mock()` a bundler quietly ignored; `moduleNamespace(await importOriginal(), { passthrough: true })` is Vitest's `{ spy: true }` with `calledWith` on top, on any runner
82
82
  - 🧾 Fixtures without casts — deep-partial `createMock`, `createFixture` / `createFixtureFactory`, `narrow()`, `withOverrides()`, `asInstances()`, `captureArg()`, and `outOfType()` for the fixture that is outside its type on purpose
83
83
  - 🚚 A migration you can verify — `vitest-auto-spy/diagnostics`: `compareTestRuns` on the two JSON reports, `summarizeTestRun` / `formatTestRunComparison` to read the answer, `diffByField` for the assertion the reporter collapses, `explainSpy` for a double that answered something you did not configure
84
- - 📏 Lint rules and one-line test-run hygiene — forty-eight rules in `vitest-auto-spy/eslint-plugin` (five `--fix`, eighteen suggestions, four of them for a suite mid-migration off jasmine), `setupAutoSpy()` — with `preset: 'strict'` for every guard at its strictest grade, and under `isolate: false` `strayListeners` / `restoreGlobals` for the listeners and raw global assignments a file leaves the next one, `restoreStorageSpies` (on by default) for the storage spy happy-dom will not let `mockRestore()` remove
84
+ - 📏 Lint rules and one-line test-run hygiene — forty-nine rules in `vitest-auto-spy/eslint-plugin` (six `--fix`, nineteen suggestions, four of them for a suite mid-migration off jasmine), `setupAutoSpy()` — with `preset: 'strict'` for every guard at its strictest grade, and under `isolate: false` `strayListeners` / `restoreGlobals` for the listeners and raw global assignments a file leaves the next one, `restoreStorageSpies` (on by default) for the storage spy happy-dom will not let `mockRestore()` remove
85
85
  - 🩺 [Editor diagnostics](#editor-diagnostics--webstorm--vs-code) — the same anti-patterns underlined while you type: native ESLint inspections in **WebStorm** and the other JetBrains IDEs, the ESLint extension in **VS Code**, no extra plugin either way
86
86
  - 🔎 [`npx vitest-auto-spy doctor`](#the-cli--doctor-perf-codemod-and-init) — suite-level defects **that never fail a run**: a `tsconfig` `include` matching no file, a production module importing a spec, a `@jest-environment` pragma the runner never reads, config left behind for a runner that is gone. Read-only, no config, exits 1 in CI
87
87
  - ⏱️ [`npx vitest-auto-spy perf`](#perf--where-the-cpu-time-actually-goes) — where a suite's CPU time actually goes, phase by phase, and which spec files to act on: the ones that reach no DOM and could run under `node`, the ones that import a barrel. Runs Vitest once with a reporter this package ships, reads `TestModule.diagnostic()`, names files, states the rule behind each finding
@@ -3206,7 +3206,7 @@ single-purpose utility you can pick up independently — they all ride on the sa
3206
3206
  | `guardGlobalPatches(reaction)` | `/setup` | Name the test that redefined a property of `document` / `navigator` / `globalThis` as non-configurable |
3207
3207
  | `guardStrayConsole(reaction)` | `/setup` | Fail a test that wrote to the console without absorbing it, and a file that wrote outside any test ([details](#test-run-hygiene)) |
3208
3208
  | `withoutStrayTimerTracking(work)` | `/setup` | Run setup work whose timers the stray-timer tracker neither counts nor cancels — jsdom schedules one per Web Storage write |
3209
- | `describeStrayTimers()` | `/setup` | Every timer still pending, with its kind, the spec file that scheduled it and the scheduling frames — the list `onStrayTimers` gets. Blind to anything scheduled under fake timers — `vi.useFakeTimers()` assigns over the wrapper |
3209
+ | `describeStrayTimers()` | `/setup` | Every timer still pending, with its kind and delay, the spec file that scheduled it and the scheduling frames — the list `onStrayTimers` gets. Blind to anything scheduled under fake timers — `vi.useFakeTimers()` assigns over the wrapper |
3210
3210
  | `guardPrototypePollution(reaction)` | `/setup` | Name the test that left a key on `Object.prototype` — it stops later files collecting ([details](#test-run-hygiene)) |
3211
3211
  | `guardDocumentPollution(option)` | `/setup` | Name the test that left an attribute on `<html>` / `<body>`, and put it back ([details](#test-run-hygiene)) |
3212
3212
  | `installPerTest(install)` | `/setup` | Re-install a stub before every test of the block — a `describe`-level stub is restored away after the first |
@@ -3587,7 +3587,7 @@ not a function` on Node 25, `undefined` on Node 26, under jsdom and happy-dom al
3587
3587
  | `propsOutsideHooks` | `'warn'` | Name a `mock*Prop` patch made in a `describe` body or `beforeAll` — it survives one test; `'throw'`, `'off'`. `reportPropsOutsideHooks(reaction)` sets the same dial without the setup helper |
3588
3588
  | `restoreMocks` | `false` | `vi.restoreAllMocks()` in a global `afterEach` — turn on for `isolate: false` |
3589
3589
  | `strayTimers` | `false` | Cancel timeouts, intervals and frames that outlive their file — does not compose with `globalFakeTimers`, which hands out timers the tracking never sees |
3590
- | `onStrayTimers` | — | Takes the per-file count and each stray's origin (file, frames) — see `--detect-async-leaks` |
3590
+ | `onStrayTimers` | — | Takes the per-file count and each stray's origin (file, frames) — see `--detect-async-leaks`; `'throw'` fails the file with every stray listed |
3591
3591
  | `strayRejections` | `false` | Fail the test a rejection zone.js swallowed surfaced in — needs zone.js |
3592
3592
  | `blockNetwork` | `false` | Close every network channel the environment has — `true`, or a narrowing object |
3593
3593
  | `guardGlobals` | `'off'` | Report a test that **adds** a non-configurable property to `globalThis`, `document`, `navigator`, `location`, `screen` or the DOM prototypes; an existing name redefined in place is its blind spot |
@@ -3790,7 +3790,7 @@ export default [
3790
3790
  ];
3791
3791
  ```
3792
3792
 
3793
- One of the four exceptions is `prefer-render-shallow`, which ships as a **`warn`**, and its reason is the kind
3793
+ One of the exceptions is `prefer-render-shallow`, which ships as a **`warn`**, and its reason is the kind
3794
3794
  of thing it says rather than how much it matters. Every other rule here names something wrong or dead
3795
3795
  — a double that drifts from its class, an assertion that never runs, a provider the container already
3796
3796
  dropped, a schema guarding nothing. That one names a file that could render more cheaply, which is a
@@ -3800,6 +3800,10 @@ it was measured against the rule reports 491 times across 398 files — a first
3800
3800
  have to answer with a project-wide `warn` of its own. A project that has decided to make the move sets
3801
3801
  it to `'error'` in the same one line that turns the others down.
3802
3802
 
3803
+ `prefer-spy-on-own-method` is graded on the same reading. The `createSpyFromInstance` call it reports is
3804
+ correct and does exactly what `spyOnOwnMethod` / `spyOnVoidMethod` does: the rule names a shorter
3805
+ spelling, not a defect, and its exact shapes carry a fix, so `'error'` is one `eslint --fix` away.
3806
+
3803
3807
  The other two, `no-stub-class-double` and `no-structural-double` (5.5.0), are graded on the
3804
3808
  _evidence_ rather than on the kind of finding. Both report the same drift
3805
3809
  `prefer-create-spy-from-class` reports at `error` — a double whose shape was written by hand and is
@@ -3862,6 +3866,7 @@ export can never be.
3862
3866
  | `no-unregistered-inject-spy` | `error` | — | `injectSpy(X)` for a token this file never registered → the real instance, whose spy helpers exist only for the compiler |
3863
3867
  | `prefer-render-shallow` | `warn` | suggest | `TestBed.createComponent` in a file that never reads the template → `renderShallow(X)`; 0.24× the per-test cycle at 100 children |
3864
3868
  | `prefer-set-inputs` | `warn` | suggest | a run of `fixture.componentRef.setInput('title', v)` on one fixture → `await setInputs(fixture, { title: v })`, which resolves every name against the compiled definition before it writes one — an undeclared name is an `NG0303` on the console and no change at all — and types the value. The suggestion collapses the run, drops a `detectChanges()` under it and makes the callback `async`; it is offered rather than applied, because `stable()` ticks and a zone.js suite can answer that with `NG0101` |
3869
+ | `prefer-spy-on-own-method` | `warn` | `--fix` / suggest | `createSpyFromInstance(x, { onlyMethodsToSpyOn: ['m'], passthrough: true })` read for `m` alone — `.m` on the call, `const { m } = …`, a bare statement, or a name read only as `v.m` → `spyOnOwnMethod(x, 'm')`; the same whitelist with `returns: { m: undefined }` → `spyOnVoidMethod(x, 'm')`. Both fix, import and all; a `Spy<X>` annotation becomes `Spy<X>['m']` in a suggestion. A bare `returns: { m: undefined }` seed is a suggestion, offered only on a real event or element — `new MouseEvent(…)`, `document.createElement(…)`, `fixture.nativeElement` — never on a double |
3865
3870
  | `prefer-observer-stub` | `error` | — | a hand-rolled `IntersectionObserver` / `ResizeObserver` / `MutationObserver` written into a global → `stubIntersectionObserver()` and friends, whose undo `restoreMockedProps()` already runs |
3866
3871
  | `no-hand-assigned-global` | `error` | — | `global.fetch = vi.fn(…)` and any other double assigned to a global with no restore in a teardown hook → `mockValueProp(globalThis, …)` / `vi.stubGlobal` + `unstubGlobals`, `blockNetwork()` for a spec that only stays offline, `stubWebStorage()` for the storages |
3867
3872
  | `prefer-stub-response` | `error` | — | an object literal cast to `Response` (`as Response`, `as unknown as Response`, `<Response>{ … }`) or a `createMock<Response>(…)` / `createAutoMock<Response>(…)` call → `stubResponse({ body })` from `/setup`, which builds the platform's own and answers every member; `Response` has to resolve to the global, so an Express handler's or a generated client's envelope of the same name is left alone |
@@ -3893,7 +3898,7 @@ Every message ends with a link to the matching [recipe](#how-to-mock): a rule th
3893
3898
  "don't" moves the problem rather than solving it. Rules travel with the API they recommend, so they
3894
3899
  are versioned together and stop being re-written in every project that installs the package.
3895
3900
 
3896
- **Five of the forty-eight fix on their own, eighteen offer suggestions**, and the split is not about how hard
3901
+ **Six of the forty-nine fix on their own, nineteen offer suggestions**, and the split is not about how hard
3897
3902
  the rewrite is. `no-mocked-for-spy` touches a _declaration_: get it wrong and the file stops
3898
3903
  compiling, which is the loudest, cheapest failure there is — so `--fix` rewrites the type, adds
3899
3904
  `import type { Spy } from 'vitest-auto-spy'` and drops the `Mocked` import once nothing else uses
@@ -4064,7 +4069,7 @@ package's own — it needs its ESLint integration switched on.
4064
4069
  ### WebStorm and the other JetBrains IDEs
4065
4070
 
4066
4071
  No plugin to install: WebStorm, IntelliJ IDEA Ultimate, PhpStorm, PyCharm Professional and RubyMine
4067
- all run ESLint natively, so the forty-eight rules appear inline, in the **Problems** tool window, and
4072
+ all run ESLint natively, so the forty-nine rules appear inline, in the **Problems** tool window, and
4068
4073
  under **Code → Inspect Code** for the whole project.
4069
4074
 
4070
4075
  ```js
@@ -4081,7 +4086,7 @@ has supported flat config since 2023.3); scope the block to spec files yourself;
4081
4086
  the fixes and suggestions live.
4082
4087
 
4083
4088
  A native JetBrains plugin is **not** planned — it would duplicate an integration the IDE already has
4084
- and then keep a second copy of forty-eight rules, in Kotlin, in step with the TypeScript ones.
4089
+ and then keep a second copy of forty-nine rules, in Kotlin, in step with the TypeScript ones.
4085
4090
 
4086
4091
  ### VS Code, Cursor, Windsurf, VSCodium
4087
4092
 
@@ -1,12 +1,12 @@
1
1
  import { assertAngularInternals, instrumentTestBed, onTestingModuleConfigured, onComponentCreated, beforeTestBedReset, verifyOnTeardown } from './chunk-ROSQKG22.js';
2
2
  export { disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, reportSpecTiming } from './chunk-ROSQKG22.js';
3
- import { failOnUnspiedProvider } from './chunk-34S5ZMWU.js';
3
+ import { failOnUnspiedProvider } from './chunk-2O3N4OPX.js';
4
4
  import './chunk-FZMWANZV.js';
5
- import './chunk-73FGLUVI.js';
6
- import './chunk-6FIKN2RJ.js';
5
+ import './chunk-TBT4J2AX.js';
6
+ import './chunk-VSWA6PQW.js';
7
7
  import './chunk-YZSBSAYZ.js';
8
8
  import './chunk-PC3FAZT3.js';
9
- import './chunk-V4XBUP4D.js';
9
+ import './chunk-64KOOW3H.js';
10
10
  import { isAutoSpyLike } from './chunk-7TGT2436.js';
11
11
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
12
12
  import { withDocs } from './chunk-TZ7DRSRD.js';
@@ -1,10 +1,10 @@
1
- import { useVitestAdapter } from './chunk-2ISMAFNN.js';
2
- import './chunk-R7DIFC2L.js';
1
+ import { useVitestAdapter } from './chunk-NFFBGS7E.js';
2
+ import './chunk-5FM2TZKG.js';
3
3
  import './chunk-YHDBRBGU.js';
4
4
  import './chunk-L6VPMLRJ.js';
5
5
  import './chunk-YZSBSAYZ.js';
6
6
  import './chunk-PC3FAZT3.js';
7
- import { createFunctionSpy } from './chunk-V4XBUP4D.js';
7
+ import { createFunctionSpy } from './chunk-64KOOW3H.js';
8
8
  import './chunk-7TGT2436.js';
9
9
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
10
10
  import { withDocs } from './chunk-TZ7DRSRD.js';
@@ -1,5 +1,5 @@
1
1
  import { angularInternalsError } from './chunk-FZMWANZV.js';
2
- import { createFunctionSpy } from './chunk-V4XBUP4D.js';
2
+ import { createFunctionSpy } from './chunk-64KOOW3H.js';
3
3
  import './chunk-7TGT2436.js';
4
4
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
5
5
  import { withDocs } from './chunk-TZ7DRSRD.js';
package/dist/angular.js CHANGED
@@ -852,6 +852,9 @@ function serializeShape(value, context) {
852
852
  if (value instanceof RegExp) {
853
853
  return String(value);
854
854
  }
855
+ if (value instanceof URL) {
856
+ return `new URL(${quoteString(value.href)})`;
857
+ }
855
858
  if (value instanceof Error) {
856
859
  return serializeError(value, context);
857
860
  }
@@ -1012,6 +1015,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
1012
1015
  if (expected instanceof RegExp || actual instanceof RegExp) {
1013
1016
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
1014
1017
  }
1018
+ if (expected instanceof URL || actual instanceof URL) {
1019
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
1020
+ }
1015
1021
  if (expected instanceof Error || actual instanceof Error) {
1016
1022
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
1017
1023
  }
@@ -1,19 +1,19 @@
1
- import { createSpyForToken } from './chunk-IOBBADJP.js';
2
- export { injectSpy, provideAutoSpy } from './chunk-34S5ZMWU.js';
1
+ import { createSpyForToken } from './chunk-33JL4DF3.js';
2
+ export { injectSpy, provideAutoSpy } from './chunk-2O3N4OPX.js';
3
3
  import { stable, flushEffects } from './chunk-V76LFJW4.js';
4
4
  export { flushEffects, stable } from './chunk-V76LFJW4.js';
5
5
  import { angularInternalsError } from './chunk-FZMWANZV.js';
6
6
  import './chunk-6RP37RWX.js';
7
- export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-CYS3E4TA.js';
8
- import { mockValueProp } from './chunk-73FGLUVI.js';
9
- export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-73FGLUVI.js';
10
- export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6FIKN2RJ.js';
7
+ export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-F4SLC724.js';
8
+ import { mockValueProp } from './chunk-TBT4J2AX.js';
9
+ export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-TBT4J2AX.js';
10
+ export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-VSWA6PQW.js';
11
11
  import './chunk-SOROJD3W.js';
12
12
  import './chunk-L6VPMLRJ.js';
13
13
  import './chunk-YZSBSAYZ.js';
14
14
  import './chunk-PC3FAZT3.js';
15
- import { libraryWarn } from './chunk-V4XBUP4D.js';
16
- export { createFunctionSpy, errorHandler } from './chunk-V4XBUP4D.js';
15
+ import { libraryWarn } from './chunk-64KOOW3H.js';
16
+ export { createFunctionSpy, errorHandler } from './chunk-64KOOW3H.js';
17
17
  import './chunk-7TGT2436.js';
18
18
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
19
19
  import { withDocs } from './chunk-TZ7DRSRD.js';
package/dist/bun.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import './chunk-6RP37RWX.js';
2
- export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-CYS3E4TA.js';
3
- export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-73FGLUVI.js';
4
- export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6FIKN2RJ.js';
2
+ export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-F4SLC724.js';
3
+ export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-TBT4J2AX.js';
4
+ export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-VSWA6PQW.js';
5
5
  import './chunk-SOROJD3W.js';
6
6
  import './chunk-L6VPMLRJ.js';
7
7
  import './chunk-YZSBSAYZ.js';
8
8
  import './chunk-PC3FAZT3.js';
9
- export { createFunctionSpy, errorHandler } from './chunk-V4XBUP4D.js';
9
+ export { createFunctionSpy, errorHandler } from './chunk-64KOOW3H.js';
10
10
  import './chunk-7TGT2436.js';
11
11
  import './chunk-2XXGISYD.js';
12
12
  import './chunk-TZ7DRSRD.js';
@@ -1,6 +1,6 @@
1
- import { currentSpecFile } from './chunk-73FGLUVI.js';
2
- import { createSpyFromClass } from './chunk-6FIKN2RJ.js';
3
- import { misconfigurationThrows, reportMisconfiguration } from './chunk-V4XBUP4D.js';
1
+ import { currentSpecFile } from './chunk-TBT4J2AX.js';
2
+ import { createSpyFromClass } from './chunk-VSWA6PQW.js';
3
+ import { misconfigurationThrows, reportMisconfiguration } from './chunk-64KOOW3H.js';
4
4
  import { isAutoSpyLike } from './chunk-7TGT2436.js';
5
5
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
6
6
  import { withDocs } from './chunk-TZ7DRSRD.js';
@@ -1,4 +1,4 @@
1
- import { createSpyFromClass, createAutoMock } from './chunk-6FIKN2RJ.js';
1
+ import { createSpyFromClass, createAutoMock } from './chunk-VSWA6PQW.js';
2
2
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
3
3
  import { withDocs } from './chunk-TZ7DRSRD.js';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { DISPOSE } from './chunk-PC3FAZT3.js';
2
- import { isFastSpy, FAST_SPY_BRAND, isThenable } from './chunk-V4XBUP4D.js';
2
+ import { isFastSpy, FAST_SPY_BRAND, isThenable } from './chunk-64KOOW3H.js';
3
3
  import { setSharedHelperSink, hooksOf } from './chunk-7TGT2436.js';
4
4
 
5
5
  // src/lib/fast-spy.ts
@@ -75,6 +75,9 @@ function serializeShape(value, context) {
75
75
  if (value instanceof RegExp) {
76
76
  return String(value);
77
77
  }
78
+ if (value instanceof URL) {
79
+ return `new URL(${quoteString(value.href)})`;
80
+ }
78
81
  if (value instanceof Error) {
79
82
  return serializeError(value, context);
80
83
  }
@@ -271,6 +274,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
271
274
  if (expected instanceof RegExp || actual instanceof RegExp) {
272
275
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
273
276
  }
277
+ if (expected instanceof URL || actual instanceof URL) {
278
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
279
+ }
274
280
  if (expected instanceof Error || actual instanceof Error) {
275
281
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
276
282
  }
@@ -1,9 +1,9 @@
1
- import { mockValueProp, mockAccessorsProp } from './chunk-73FGLUVI.js';
2
- import { resolveConfiguration, mergeAutoSpyDefaults, resolveReadGuard, mergeMethodNames, getCallableMemberNames, createTrackedPropSpy, applyConfiguredReturns, createSpyFromClass, warnOnUnknownMethods, warnOnAccessorNamingAMethod, resolveAccessors, createAccessorsSpies, createProxyPropStore, storeWriteTraps, describeStoredProp, hasStoredProp, isProtocolKey, isDeletedProp, readStoredAccessor, NOT_STORED, disposeAutoSpy, writeStoredValue } from './chunk-6FIKN2RJ.js';
1
+ import { mockValueProp, mockAccessorsProp } from './chunk-TBT4J2AX.js';
2
+ import { resolveConfiguration, mergeAutoSpyDefaults, resolveReadGuard, mergeMethodNames, getCallableMemberNames, createTrackedPropSpy, applyConfiguredReturns, createSpyFromClass, warnOnUnknownMethods, warnOnAccessorNamingAMethod, resolveAccessors, createAccessorsSpies, createProxyPropStore, storeWriteTraps, describeStoredProp, hasStoredProp, isProtocolKey, isDeletedProp, readStoredAccessor, NOT_STORED, disposeAutoSpy, writeStoredValue } from './chunk-VSWA6PQW.js';
3
3
  import { unpatchedSetTimeout, unpatchedClearTimeout } from './chunk-SOROJD3W.js';
4
4
  import { redefineFailure } from './chunk-YZSBSAYZ.js';
5
5
  import { DISPOSE } from './chunk-PC3FAZT3.js';
6
- import { defineHelper, adoptFunctionSpy, reinstallDispatch, serializeValue, resolveUnstubbedGuard, createFunctionSpy, reportMisconfiguration } from './chunk-V4XBUP4D.js';
6
+ import { defineHelper, adoptFunctionSpy, reinstallDispatch, serializeValue, resolveUnstubbedGuard, createFunctionSpy, reportMisconfiguration } from './chunk-64KOOW3H.js';
7
7
  import { isMarkedMock, DEEP_CHILDREN } from './chunk-7TGT2436.js';
8
8
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
9
9
  import { withDocs } from './chunk-TZ7DRSRD.js';
@@ -1,4 +1,4 @@
1
- import { clearAllFastSpies, resetAllFastSpies, getSpyEngine, createFastSpy } from './chunk-R7DIFC2L.js';
1
+ import { clearAllFastSpies, resetAllFastSpies, getSpyEngine, createFastSpy } from './chunk-5FM2TZKG.js';
2
2
  import { SWEEP_SENTINEL } from './chunk-YHDBRBGU.js';
3
3
  import { guardAccessorSpies, spyOnAccessorByRedefine } from './chunk-L6VPMLRJ.js';
4
4
  import { hasMockAdapter, registerMockAdapter } from './shared-state.js';
@@ -1,5 +1,5 @@
1
1
  import { isCannotRedefine, redefineFailure } from './chunk-YZSBSAYZ.js';
2
- import { libraryWarn } from './chunk-V4XBUP4D.js';
2
+ import { libraryWarn } from './chunk-64KOOW3H.js';
3
3
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
4
4
  import { withDocs } from './chunk-TZ7DRSRD.js';
5
5
  import { getMockAdapter } from './shared-state.js';
@@ -1,5 +1,5 @@
1
1
  import { DISPOSE } from './chunk-PC3FAZT3.js';
2
- import { defaultStrict, resolveUnstubbedGuard, reportMisconfiguration, seedReturnValue, createFunctionSpy } from './chunk-V4XBUP4D.js';
2
+ import { defaultStrict, resolveUnstubbedGuard, reportMisconfiguration, seedReturnValue, createFunctionSpy } from './chunk-64KOOW3H.js';
3
3
  import { runClearHook, runConfigReset, AUTO_SPY_MARK, markAsMock, isMarkedMock, readDeepChildren } from './chunk-7TGT2436.js';
4
4
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
5
5
  import { withDocs } from './chunk-TZ7DRSRD.js';
package/dist/cli.js CHANGED
@@ -3088,7 +3088,7 @@ function checkForeignPragma(graph) {
3088
3088
  }
3089
3089
 
3090
3090
  // src/cli/checks/export-map.generated.ts
3091
- var EXPORT_MAP_VERSION = "5.28.0";
3091
+ var EXPORT_MAP_VERSION = "5.30.0";
3092
3092
  var ENTRY_SPECIFIERS = "vitest-auto-spy vitest-auto-spy/bun vitest-auto-spy/bun-angular vitest-auto-spy/node vitest-auto-spy/rstest vitest-auto-spy/rxjs vitest-auto-spy/console vitest-auto-spy/dom-stubs vitest-auto-spy/diagnostics vitest-auto-spy/jasmine vitest-auto-spy/jasmine-compat vitest-auto-spy/observer-spy vitest-auto-spy/angular vitest-auto-spy/angular/diagnostics vitest-auto-spy/angular/doubles vitest-auto-spy/angular/matchers vitest-auto-spy/angular-http vitest-auto-spy/angular-router vitest-auto-spy/signal-forms vitest-auto-spy/nestjs vitest-auto-spy/react vitest-auto-spy/vue vitest-auto-spy/svelte vitest-auto-spy/setup vitest-auto-spy/zone vitest-auto-spy/eslint-plugin vitest-auto-spy/perf-reporter";
3093
3093
  var EXPORTED_BY = {
3094
3094
  AccessorImplementations: "0 1 2 3 4 12 20 21 22",
package/dist/console.js CHANGED
@@ -1,10 +1,10 @@
1
- import { useVitestAdapter } from './chunk-2ISMAFNN.js';
2
- import './chunk-R7DIFC2L.js';
1
+ import { useVitestAdapter } from './chunk-NFFBGS7E.js';
2
+ import './chunk-5FM2TZKG.js';
3
3
  import './chunk-YHDBRBGU.js';
4
4
  import './chunk-L6VPMLRJ.js';
5
5
  import './chunk-YZSBSAYZ.js';
6
6
  import './chunk-PC3FAZT3.js';
7
- import { createFunctionSpy } from './chunk-V4XBUP4D.js';
7
+ import { createFunctionSpy } from './chunk-64KOOW3H.js';
8
8
  import './chunk-7TGT2436.js';
9
9
  import './chunk-2XXGISYD.js';
10
10
  import './chunk-TZ7DRSRD.js';
@@ -123,6 +123,9 @@ function serializeShape(value, context) {
123
123
  if (value instanceof RegExp) {
124
124
  return String(value);
125
125
  }
126
+ if (value instanceof URL) {
127
+ return `new URL(${quoteString(value.href)})`;
128
+ }
126
129
  if (value instanceof Error) {
127
130
  return serializeError(value, context);
128
131
  }