vitest-auto-spy 5.30.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
@@ -1524,8 +1524,10 @@ setupAutoSpy({ strayTimers: true, onStrayTimers: ({ timers }) => expect(timers).
1524
1524
  `frames` starts below the tracking wrapper and is up to forty frames deep, so a zone or an rxjs
1525
1525
  scheduler in between does not hide the caller: project frames come first; when the call came from
1526
1526
  dependencies only, their frames stand in. The package's own frames are never quoted, from source or
1527
- from `dist`. A handler that prints its own message should print `kind`, `delay` and `frames[0]` —
1528
- they are what makes a report that only reproduces under a slow coverage run actionable the first time.
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.
1529
1531
 
1530
1532
  A stray whose `file` is not the file that failed was scheduled after the previous file's sweep —
1531
1533
  the previous file is the one to fix.
@@ -1661,7 +1663,13 @@ initialisation — and the `afterAll` takes off everything added since. The piec
1661
1663
  `removeStrayListeners()` (returns how many), `countStrayListeners()` (throws before
1662
1664
  `trackStrayListeners()` has run, like the timer counter) and `describeStrayListeners()` — each
1663
1665
  stray's target, type, spec file and up to five frames, the list `onStrayListeners({ removed, listeners })`
1664
- 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.
1665
1673
  Under jsdom a listener registered with `{ once: true }` that already fired stays counted until
1666
1674
  something removes it: the wrapper cannot observe the firing without breaking identity-based
1667
1675
  `removeEventListener` from the code under test, and removing an already-fired listener is a no-op
@@ -2170,8 +2178,8 @@ an unconfigured call returns — a semantic switch, not a grade; the name was ta
2170
2178
  `unconfiguredReads`, its read side (survey with `onUnstubbedRead` before turning it on),
2171
2179
  `blockNetwork` (changes the code under test), `restoreMocks` (drops `beforeAll` spies), failing on
2172
2180
  stray-timer counts (the sweep fails the file from `afterAll`, and a callback scheduled after the
2173
- previous file's sweep is charged to the next — opt in with
2174
- `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
2175
2183
  `enableAngularDiagnostics()`, which lives in `/angular/diagnostics` — call it in the same setup file as the Angular half of strict.
2176
2184
 
2177
2185
  `misconfiguration: 'throw'` on its own makes the library's misuse reports — an `onlyMethodsToSpyOn`
package/CHANGELOG.md CHANGED
@@ -10,6 +10,45 @@ 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
+
13
52
  ## [5.30.0] - 2026-09-25
14
53
 
15
54
  ### Added
@@ -7890,7 +7929,8 @@ by hand there, in more than one place, by more than one person.
7890
7929
  `mockAccessorsProp`.
7891
7930
  - Dual ESM + CJS build with type declarations; 100% test coverage.
7892
7931
 
7893
- [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.30.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
7894
7934
  [5.30.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.29.0...v5.30.0
7895
7935
  [5.29.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.28.0...v5.29.0
7896
7936
  [5.28.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.27.0...v5.28.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)
@@ -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 |
@@ -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.29.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
  }
package/dist/index.js CHANGED
@@ -737,6 +737,9 @@ function serializeShape(value, context) {
737
737
  if (value instanceof RegExp) {
738
738
  return String(value);
739
739
  }
740
+ if (value instanceof URL) {
741
+ return `new URL(${quoteString(value.href)})`;
742
+ }
740
743
  if (value instanceof Error) {
741
744
  return serializeError(value, context);
742
745
  }
@@ -897,6 +900,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
897
900
  if (expected instanceof RegExp || actual instanceof RegExp) {
898
901
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
899
902
  }
903
+ if (expected instanceof URL || actual instanceof URL) {
904
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
905
+ }
900
906
  if (expected instanceof Error || actual instanceof Error) {
901
907
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
902
908
  }
package/dist/jasmine.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { enableJasmineCompat } from './chunk-3MRCVCRZ.js';
2
2
  export { enableJasmineCompat } from './chunk-3MRCVCRZ.js';
3
- import { createSpyFromClass } from './chunk-6FIKN2RJ.js';
4
- import { useVitestAdapter } from './chunk-2ISMAFNN.js';
5
- import './chunk-R7DIFC2L.js';
3
+ import { createSpyFromClass } from './chunk-VSWA6PQW.js';
4
+ import { useVitestAdapter } from './chunk-NFFBGS7E.js';
5
+ import './chunk-5FM2TZKG.js';
6
6
  import './chunk-YHDBRBGU.js';
7
7
  import './chunk-L6VPMLRJ.js';
8
8
  import './chunk-YZSBSAYZ.js';
9
9
  import './chunk-PC3FAZT3.js';
10
- import { createFunctionSpy, reportMisconfiguration, misconfigurationThrows } from './chunk-V4XBUP4D.js';
10
+ import { createFunctionSpy, reportMisconfiguration, misconfigurationThrows } from './chunk-64KOOW3H.js';
11
11
  import './chunk-7TGT2436.js';
12
12
  import './chunk-2XXGISYD.js';
13
13
  import './chunk-TZ7DRSRD.js';
package/dist/nestjs.js CHANGED
@@ -1,13 +1,13 @@
1
- import { createSpyForToken } from './chunk-IOBBADJP.js';
2
- export { trackInjections } from './chunk-IOBBADJP.js';
3
- import { createSpyFromClass } from './chunk-6FIKN2RJ.js';
4
- import { useVitestAdapter } from './chunk-2ISMAFNN.js';
5
- import './chunk-R7DIFC2L.js';
1
+ import { createSpyForToken } from './chunk-33JL4DF3.js';
2
+ export { trackInjections } from './chunk-33JL4DF3.js';
3
+ import { createSpyFromClass } from './chunk-VSWA6PQW.js';
4
+ import { useVitestAdapter } from './chunk-NFFBGS7E.js';
5
+ import './chunk-5FM2TZKG.js';
6
6
  import './chunk-YHDBRBGU.js';
7
7
  import './chunk-L6VPMLRJ.js';
8
8
  import './chunk-YZSBSAYZ.js';
9
9
  import './chunk-PC3FAZT3.js';
10
- import './chunk-V4XBUP4D.js';
10
+ import './chunk-64KOOW3H.js';
11
11
  import './chunk-7TGT2436.js';
12
12
  import { DOCS_LINKS } from './chunk-2XXGISYD.js';
13
13
  import { withDocs } from './chunk-TZ7DRSRD.js';
package/dist/node.cjs CHANGED
@@ -403,6 +403,9 @@ function serializeShape(value, context) {
403
403
  if (value instanceof RegExp) {
404
404
  return String(value);
405
405
  }
406
+ if (value instanceof URL) {
407
+ return `new URL(${quoteString(value.href)})`;
408
+ }
406
409
  if (value instanceof Error) {
407
410
  return serializeError(value, context);
408
411
  }
@@ -563,6 +566,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
563
566
  if (expected instanceof RegExp || actual instanceof RegExp) {
564
567
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
565
568
  }
569
+ if (expected instanceof URL || actual instanceof URL) {
570
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
571
+ }
566
572
  if (expected instanceof Error || actual instanceof Error) {
567
573
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
568
574
  }
package/dist/node.js CHANGED
@@ -324,6 +324,9 @@ function serializeShape(value, context) {
324
324
  if (value instanceof RegExp) {
325
325
  return String(value);
326
326
  }
327
+ if (value instanceof URL) {
328
+ return `new URL(${quoteString(value.href)})`;
329
+ }
327
330
  if (value instanceof Error) {
328
331
  return serializeError(value, context);
329
332
  }
@@ -484,6 +487,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
484
487
  if (expected instanceof RegExp || actual instanceof RegExp) {
485
488
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
486
489
  }
490
+ if (expected instanceof URL || actual instanceof URL) {
491
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
492
+ }
487
493
  if (expected instanceof Error || actual instanceof Error) {
488
494
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
489
495
  }
package/dist/react.js CHANGED
@@ -737,6 +737,9 @@ function serializeShape(value, context) {
737
737
  if (value instanceof RegExp) {
738
738
  return String(value);
739
739
  }
740
+ if (value instanceof URL) {
741
+ return `new URL(${quoteString(value.href)})`;
742
+ }
740
743
  if (value instanceof Error) {
741
744
  return serializeError(value, context);
742
745
  }
@@ -897,6 +900,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
897
900
  if (expected instanceof RegExp || actual instanceof RegExp) {
898
901
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
899
902
  }
903
+ if (expected instanceof URL || actual instanceof URL) {
904
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
905
+ }
900
906
  if (expected instanceof Error || actual instanceof Error) {
901
907
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
902
908
  }
package/dist/rstest.js CHANGED
@@ -1,12 +1,12 @@
1
- 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';
2
- export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-73FGLUVI.js';
3
- export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6FIKN2RJ.js';
1
+ 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';
2
+ export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-TBT4J2AX.js';
3
+ export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-VSWA6PQW.js';
4
4
  import './chunk-SOROJD3W.js';
5
- import { clearAllFastSpies, resetAllFastSpies, getSpyEngine, createFastSpy } from './chunk-R7DIFC2L.js';
5
+ import { clearAllFastSpies, resetAllFastSpies, getSpyEngine, createFastSpy } from './chunk-5FM2TZKG.js';
6
6
  import { guardAccessorSpies, spyOnAccessorByRedefine } from './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';
package/dist/setup.d.ts CHANGED
@@ -767,9 +767,12 @@ interface SetupAutoSpyOptions {
767
767
  * setupAutoSpy({ strayTimers: true, onStrayTimers: ({ cancelled }) => expect(cancelled).toBe(0) });
768
768
  * ```
769
769
  *
770
+ * `'throw'` does the same with a message that lists every stray's kind, delay, spec file and
771
+ * first frame.
772
+ *
770
773
  * Called only when something was actually cancelled, and only once per file.
771
774
  */
772
- onStrayTimers?: (info: StrayTimerReport) => void;
775
+ onStrayTimers?: 'throw' | ((info: StrayTimerReport) => void);
773
776
  /**
774
777
  * Fail the test a swallowed promise rejection surfaced in, instead of letting it scroll past in
775
778
  * stderr. Default `false`, because it needs zone.js loaded and claims a hook on it.
@@ -886,8 +889,10 @@ interface SetupAutoSpyOptions {
886
889
  * ```ts
887
890
  * setupAutoSpy({ strayListeners: true, onStrayListeners: ({ removed }) => expect(removed).toBe(0) });
888
891
  * ```
892
+ *
893
+ * `'throw'` fails the file with a message that lists every stray's type, target, spec file and first frame.
889
894
  */
890
- onStrayListeners?: (info: StrayListenerReport) => void;
895
+ onStrayListeners?: 'throw' | ((info: StrayListenerReport) => void);
891
896
  /**
892
897
  * Put every `globalThis` global a file changed back at the end of the file. Default `false`.
893
898
  *
package/dist/setup.js CHANGED
@@ -1072,6 +1072,31 @@ function storagePrototype() {
1072
1072
  return Object(Reflect.get(Storage, "prototype"));
1073
1073
  }
1074
1074
 
1075
+ // src/lib/stray-failure.ts
1076
+ function describeStrayTimer({ kind, delay, file, frames }) {
1077
+ const scheduled = delay === void 0 ? kind : `${kind} (${delay} ms)`;
1078
+ return `${scheduled} from ${file ?? "no spec file"} ${frames[0] ?? ""}`.trimEnd();
1079
+ }
1080
+ function describeStrayListener({ type, target, file, frames }) {
1081
+ return `${type} on ${target} from ${file ?? "no spec file"} ${frames[0] ?? ""}`.trimEnd();
1082
+ }
1083
+ function strayFailure(summary, lines) {
1084
+ return new Error(withDocs(`[vitest-auto-spy] ${summary}${lines.map((line) => `
1085
+ - ${line}`).join("")}`, DOCS_LINKS.setup));
1086
+ }
1087
+ function strayTimersError(cancelled, timers) {
1088
+ return strayFailure(
1089
+ `${cancelled} scheduled callback(s) outlived the spec file that scheduled them. setupAutoSpy cancelled them; onStrayTimers: 'throw' fails the file. Clear each one where it was scheduled:`,
1090
+ timers.map(describeStrayTimer)
1091
+ );
1092
+ }
1093
+ function strayListenersError(removed, listeners) {
1094
+ return strayFailure(
1095
+ `${removed} window/document listener(s) outlived the spec file that added them. setupAutoSpy removed them; onStrayListeners: 'throw' fails the file. Remove each one where it was added:`,
1096
+ listeners.map(describeStrayListener)
1097
+ );
1098
+ }
1099
+
1075
1100
  // src/lib/define-helper.ts
1076
1101
  function readDefiner(candidate) {
1077
1102
  if (typeof candidate !== "object" || candidate === null) {
@@ -1290,12 +1315,42 @@ function releaseLeftoverFakes() {
1290
1315
  }
1291
1316
  restoreTimerGlobals();
1292
1317
  }
1293
- function installFileBoundary(options) {
1318
+ function reportStrayListeners(removed, listeners, handler) {
1319
+ if (removed === 0) {
1320
+ return;
1321
+ }
1322
+ if (handler === "throw") {
1323
+ throw strayListenersError(removed, listeners);
1324
+ }
1325
+ handler?.({ removed, listeners });
1326
+ }
1327
+ function runFileBoundary(repairs) {
1328
+ const reports = repairs.map((repair) => repair()).filter((report4) => report4 !== void 0);
1329
+ const errors = [];
1330
+ for (const report4 of reports) {
1331
+ try {
1332
+ report4();
1333
+ } catch (error) {
1334
+ errors.push(error);
1335
+ }
1336
+ }
1337
+ if (errors.length === 1) {
1338
+ throw errors[0];
1339
+ }
1340
+ if (errors.length > 1) {
1341
+ const messages = errors.map((error) => `
1342
+ - ${error instanceof Error ? error.message : String(error)}`);
1343
+ throw new AggregateError(errors, `[vitest-auto-spy] ${errors.length} file-end reports failed:${messages.join("")}`);
1344
+ }
1345
+ }
1346
+ function installFileBoundary(options, sweeps = []) {
1294
1347
  const repairs = [];
1295
1348
  const restoresGlobals = options.restoreGlobals ?? false;
1296
- let report4 = () => void 0;
1297
1349
  if (restoresGlobals) {
1298
- repairs.push(releaseLeftoverFakes);
1350
+ repairs.push(() => {
1351
+ releaseLeftoverFakes();
1352
+ return void 0;
1353
+ });
1299
1354
  }
1300
1355
  if (options.strayListeners ?? false) {
1301
1356
  trackStrayListeners();
@@ -1305,27 +1360,27 @@ function installFileBoundary(options) {
1305
1360
  repairs.push(() => {
1306
1361
  const listeners = describeStrayListeners();
1307
1362
  const removed = removeStrayListeners();
1308
- report4 = () => {
1309
- if (removed > 0) {
1310
- options.onStrayListeners?.({ removed, listeners });
1311
- }
1363
+ return () => {
1364
+ reportStrayListeners(removed, listeners, options.onStrayListeners);
1312
1365
  };
1313
1366
  });
1314
1367
  }
1315
1368
  if (options.restoreStorageSpies ?? true) {
1316
1369
  repairs.push(() => {
1317
1370
  restoreStorageSpies();
1371
+ return void 0;
1318
1372
  });
1319
1373
  }
1320
1374
  if (restoresGlobals) {
1321
1375
  captureGlobalBaseline();
1322
1376
  repairs.push(() => {
1323
1377
  restoreGlobals();
1378
+ return void 0;
1324
1379
  });
1325
1380
  }
1381
+ repairs.push(...sweeps);
1326
1382
  afterAll(() => {
1327
- repairs.forEach((repair) => repair());
1328
- report4();
1383
+ runFileBoundary(repairs);
1329
1384
  });
1330
1385
  }
1331
1386
  var TIMEOUT_MESSAGE = /^(?:Test|Hook) timed out in \d+ms(?: while waiting for [^\n]*?)?\./;
@@ -2748,11 +2803,8 @@ function warnAboutSuppressedLeaks(cancelled, write = writeWarning, timers = [])
2748
2803
  );
2749
2804
  }
2750
2805
  function describeTimerOrigins(timers) {
2751
- const lines = timers.slice(0, 3).map(({ kind, delay, file, frames }) => {
2752
- const scheduled = delay === void 0 ? kind : `${kind} (${delay} ms)`;
2753
- return `
2754
- - ${scheduled} from ${file ?? "no spec file"} ${frames[0] ?? ""}`.trimEnd();
2755
- });
2806
+ const lines = timers.slice(0, 3).map((timer) => `
2807
+ - ${describeStrayTimer(timer)}`);
2756
2808
  return lines.length > 0 ? `
2757
2809
  Scheduled at:${lines.join("")}` : "";
2758
2810
  }
@@ -2760,6 +2812,9 @@ function reportStrayTimers(cancelled, handler, timers = []) {
2760
2812
  if (cancelled === 0) {
2761
2813
  return;
2762
2814
  }
2815
+ if (handler === "throw") {
2816
+ throw strayTimersError(cancelled, timers);
2817
+ }
2763
2818
  if (handler) {
2764
2819
  handler({ cancelled, timers });
2765
2820
  return;
@@ -3058,17 +3113,19 @@ function setupAutoSpy(input = {}) {
3058
3113
  beforeEach(beginPropEpoch);
3059
3114
  }
3060
3115
  const consoleGuard = watchStrayConsole(options.strayConsole);
3116
+ const sweeps = [];
3061
3117
  if (options.strayTimers ?? false) {
3062
3118
  trackStrayTimers();
3063
- afterAll(() => {
3119
+ sweeps.push(() => {
3064
3120
  const timers = describeStrayTimers();
3065
- reportStrayTimers(cancelStrayTimers(), options.onStrayTimers, timers);
3121
+ const cancelled = cancelStrayTimers();
3122
+ return () => reportStrayTimers(cancelled, options.onStrayTimers, timers);
3066
3123
  });
3067
3124
  }
3068
3125
  if (options.pruneMockRegistry ?? false) {
3069
3126
  trackMockRegistry();
3070
3127
  }
3071
- installFileBoundary(options);
3128
+ installFileBoundary(options, sweeps);
3072
3129
  armStrictMode(options);
3073
3130
  armUnconfiguredReads(options);
3074
3131
  armMisconfiguration(options.misconfiguration);
package/dist/svelte.js CHANGED
@@ -737,6 +737,9 @@ function serializeShape(value, context) {
737
737
  if (value instanceof RegExp) {
738
738
  return String(value);
739
739
  }
740
+ if (value instanceof URL) {
741
+ return `new URL(${quoteString(value.href)})`;
742
+ }
740
743
  if (value instanceof Error) {
741
744
  return serializeError(value, context);
742
745
  }
@@ -897,6 +900,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
897
900
  if (expected instanceof RegExp || actual instanceof RegExp) {
898
901
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
899
902
  }
903
+ if (expected instanceof URL || actual instanceof URL) {
904
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
905
+ }
900
906
  if (expected instanceof Error || actual instanceof Error) {
901
907
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
902
908
  }
package/dist/vue.js CHANGED
@@ -737,6 +737,9 @@ function serializeShape(value, context) {
737
737
  if (value instanceof RegExp) {
738
738
  return String(value);
739
739
  }
740
+ if (value instanceof URL) {
741
+ return `new URL(${quoteString(value.href)})`;
742
+ }
740
743
  if (value instanceof Error) {
741
744
  return serializeError(value, context);
742
745
  }
@@ -897,6 +900,9 @@ function sameSpecialObject(expected, actual, path, matchers) {
897
900
  if (expected instanceof RegExp || actual instanceof RegExp) {
898
901
  return expected instanceof RegExp && actual instanceof RegExp && String(expected) === String(actual);
899
902
  }
903
+ if (expected instanceof URL || actual instanceof URL) {
904
+ return expected instanceof URL && actual instanceof URL && expected.href === actual.href;
905
+ }
900
906
  if (expected instanceof Error || actual instanceof Error) {
901
907
  return expected instanceof Error && actual instanceof Error && expected.name === actual.name && expected.message === actual.message && sameEntries(expected, actual, path, matchers);
902
908
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-auto-spy",
3
- "version": "5.30.0",
3
+ "version": "5.31.0",
4
4
  "description": "Auto-generate fully-typed test spies from a class — across Vitest, Bun, node:test and Rstest, with Angular/NestJS/React/Vue/Svelte recipes. Drop-in replacement for jest-auto-spies and jasmine-auto-spies.",
5
5
  "keywords": [
6
6
  "auto-mock",
@@ -252,7 +252,7 @@ it('loads', async () => {
252
252
  | console output a test never asserted on (a `'warn'` from this library does not count) | `setupAutoSpy({ strayConsole: 'throw' })` fails that test; absorb with `installConsoleSpies()` in `beforeEach` |
253
253
  | every guard at its strictest grade in one line | `setupAutoSpy({ preset: 'strict' })` — plus `enableAngularDiagnostics()` from `/angular/diagnostics` for Angular |
254
254
  | an `onlyMethodsToSpyOn` typo or `injectSpy` on a real instance that only warned | `setupAutoSpy({ misconfiguration: 'throw' })` throws at the call |
255
- | which file and call scheduled a timer that outlived its file | `onStrayTimers: ({ timers }) => expect(timers).toEqual([])`, or `describeStrayTimers()` from `/setup` |
255
+ | which file and call scheduled a timer that outlived its file | `onStrayTimers: 'throw'` (each stray's kind, delay, file and first frame), or `describeStrayTimers()` from `/setup` |
256
256
  | stray timers charged to a file that only writes `localStorage` (jsdom) | `withoutStrayTimerTracking(() => seed())` from `/setup` — its timers are neither counted nor cancelled |
257
257
  | `import { consoleErrorSpy }` silencing other files under `isolate: false` | `installConsoleSpies()` in `beforeEach`, `restoreConsole()` in `afterEach` — the import installs once per worker |
258
258
  | `Cannot set base providers because it has already been called` | `setupAngularTestEnv({ zoneless, initZone, initZoneless })` |