vitest-auto-spy 5.43.0 → 5.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +190 -1
  3. package/README.md +187 -173
  4. package/agent-docs/angular.md +30 -3
  5. package/agent-docs/checklist.md +7 -1
  6. package/agent-docs/errors.md +2 -1
  7. package/agent-docs/eslint.md +1 -1
  8. package/agent-docs/factories.md +11 -0
  9. package/agent-docs/setup.md +38 -3
  10. package/dist/angular-diagnostics.js +17 -6
  11. package/dist/angular-doubles.d.ts +1 -1
  12. package/dist/angular-doubles.js +3 -3
  13. package/dist/angular-http.d.ts +17 -5
  14. package/dist/angular-http.js +10 -4
  15. package/dist/angular-router.d.ts +1 -1
  16. package/dist/angular-router.js +1 -1
  17. package/dist/angular.d.ts +7 -7
  18. package/dist/bun-angular.d.ts +5 -5
  19. package/dist/bun-angular.js +6 -6
  20. package/dist/bun.d.ts +5 -5
  21. package/dist/bun.js +3 -3
  22. package/dist/{chunk-JFOJFCVQ.js → chunk-3JL2YWIG.js} +2 -1
  23. package/dist/{chunk-MHN6GMXP.js → chunk-FQ6NT2IN.js} +1 -1
  24. package/dist/{chunk-EYXARTWD.js → chunk-I6CB4CNT.js} +24 -4
  25. package/dist/{chunk-J4IJCTHT.js → chunk-IB72SVKT.js} +1 -1
  26. package/dist/{chunk-RYEBG2KB.js → chunk-M5H32F4Q.js} +2 -2
  27. package/dist/{chunk-XXAGPAZR.js → chunk-NGZYYSEA.js} +1 -1
  28. package/dist/{chunk-CENALW7R.js → chunk-PUUSCWDD.js} +1 -1
  29. package/dist/{chunk-J2C3KRTC.js → chunk-QGLUX55Q.js} +1 -1
  30. package/dist/cli.js +360 -207
  31. package/dist/console.d.ts +18 -2
  32. package/dist/console.js +26 -4
  33. package/dist/dom-stubs.d.ts +2 -2
  34. package/dist/eslint-plugin.cjs +142 -5
  35. package/dist/{expect-emission-D7DaPI5H.d.ts → expect-emission-DMQZF5QR.d.ts} +1 -1
  36. package/dist/index.d.ts +4 -4
  37. package/dist/index.js +24 -4
  38. package/dist/jasmine-compat.d.ts +1 -1
  39. package/dist/jasmine.d.ts +2 -2
  40. package/dist/jasmine.js +4 -4
  41. package/dist/nestjs.d.ts +2 -2
  42. package/dist/nestjs.js +6 -6
  43. package/dist/node.cjs +24 -4
  44. package/dist/node.d.ts +4 -4
  45. package/dist/node.js +24 -4
  46. package/dist/{package-identity-C362z4w-.d.ts → package-identity-5kYzh3ad.d.ts} +3 -1
  47. package/dist/perf-reporter.d.ts +5 -0
  48. package/dist/perf-reporter.js +28 -3
  49. package/dist/{prop-mock-e7qpfqY1.d.ts → prop-mock-WOpRQPUc.d.ts} +1 -1
  50. package/dist/react.d.ts +4 -4
  51. package/dist/rstest.d.ts +4 -4
  52. package/dist/rstest.js +4 -4
  53. package/dist/rxjs.d.ts +2 -2
  54. package/dist/setup.d.ts +63 -6
  55. package/dist/setup.js +203 -22
  56. package/dist/svelte.d.ts +4 -4
  57. package/dist/{track-injections-CkVuJHr_.d.ts → track-injections-CYQKc3M8.d.ts} +1 -1
  58. package/dist/{track-signal-runs-B3noexlc.d.ts → track-signal-runs-CyPA-p4I.d.ts} +3 -3
  59. package/dist/{types-CaGn5uvo.d.ts → types-Dxw-oWfr.d.ts} +5 -1
  60. package/dist/vue.d.ts +5 -5
  61. package/package.json +2 -1
  62. package/skills/vitest-auto-spy/SKILL.md +141 -135
package/AGENTS.md CHANGED
@@ -81,7 +81,7 @@ Add-ons, orthogonal to the runner:
81
81
  | --- | --- | --- |
82
82
  | Observable spies | `import 'vitest-auto-spy/rxjs'` | `nextWith` & friends. **Side-effect import, once**, in a setup file, a spec, or a `.d.ts` the `tsconfig` includes (§4) |
83
83
  | observer-spy shim | `vitest-auto-spy/observer-spy` | `subscribeSpyTo` — the `@hirez_io/observer-spy` surface (§20). Its own entry so `/rxjs` does not carry it |
84
- | Console spies | `vitest-auto-spy/console` | silent typed spies over the global `console` — `installConsoleSpies()` per test, `restoreConsole()` after |
84
+ | Console spies | `vitest-auto-spy/console` | silent typed spies over the global `console` — `installConsoleSpies()` per test, `restoreConsole()` after; `consoleOutput()` is everything logged, keyed by channel |
85
85
  | DOM stubs | `vitest-auto-spy/dom-stubs` | `stubIntersectionObserver` / `stubResizeObserver` / `stubMutationObserver` / `stubObserver`, `stubMediaElement`, `stubAbortController`, `stubWebStorage` (§12), `stubAnimationFrame`, `stubElementRect`, `intersectionEntry` / `resizeEntry` / `mutationRecord`. **Moved off the root in 4.0.0** |
86
86
  | Run diagnostics | `vitest-auto-spy/diagnostics` | `compareTestRuns`, `summarizeTestRun`, `formatTestRunComparison`, `diffByField`. **Moved off the root in 4.0.0** |
87
87
  | Angular HTTP | `vitest-auto-spy/angular-http` | `provideHttpTesting`, `expectRequest` — `httpResource()` / `HttpClient` (§13). Optional `@angular/common` peer, this entry only |
package/CHANGELOG.md CHANGED
@@ -10,6 +10,193 @@ The latest released version here must always match the one published on
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [5.45.0] - 2026-09-27
14
+
15
+ ### Added
16
+
17
+ - **`no-redundant-mock-reset` takes `configFlags`: the flags a factory-built `configFile` sets
18
+ beyond its text.** The rule reads `configFile` as text, so a config such as
19
+ `export default createProjectConfig(…)` that sets `clearMocks: true` inside the factory showed no
20
+ flag. The only way to state it was the inline `clearMocks: true`, which the Angular unit-test
21
+ builder check does not narrow. On Vitest 4, with an `@angular/build:unit-test` /
22
+ `@nx/angular:unit-test` target that names no `runnerConfig`, that reported a clear the builder
23
+ run still needs. `{ configFile, configFlags: { clearMocks?, mockReset?, restoreMocks? } }` reads
24
+ those flags as if the file wrote them: they override its text and apply only to the runs that
25
+ load that file (plain `vitest run`, and a target whose `runnerConfig` resolves to it). A target
26
+ without `runnerConfig` still runs on Vitest's defaults. `configFlags` without `configFile` is a
27
+ configuration error. Inline flags still win and are still not narrowed. The fix line of `doctor`'s
28
+ `mock-reset-config-unread` now suggests `{ configFile, configFlags: { clearMocks: true } }`.
29
+
30
+ ### Fixed
31
+
32
+ - **`pendingRequests` answers with `expectRequest` in a suite built on `provideHttpTesting()`.**
33
+ An unanswered request in such a suite is usually reported by `enableAngularDiagnostics({
34
+ pendingRequests })` / `assertNoPendingRequests()`, whose fix line read "Answer it in the spec:
35
+ `controller.expectOne('/api/unflushed').flush(body)`" — a controller these specs never inject. The
36
+ line is now `await expectRequest('/api/unflushed').flush(body)` (with `, { method: 'POST' }` when
37
+ two open requests share a URL), the same one `provideHttpTesting()`'s own teardown check gives.
38
+ `provideHttpTesting()` registers a marker provider the diagnostics entry reads from the
39
+ configuration, so `vitest-auto-spy/angular/diagnostics` still does not import `@angular/common`;
40
+ a module configured with `provideHttpClientTesting()` or `HttpClientTestingModule` keeps the
41
+ `controller.expectOne(...)` line.
42
+
43
+ ### Documentation
44
+
45
+ - **The `provideHttpTesting({ interceptors })` example in `agent-docs/angular.md` no longer fails
46
+ under `strayTimers`.** It answered `error(401)` to a bare `.subscribe()`, which rxjs rethrows as
47
+ an unhandled Observable error, and 5.44.0 fails the test on that. The example now subscribes with
48
+ an error callback and asserts what it received.
49
+ - **`flushUnhandledObservableErrors()` returns `{ error, outsideTest }` for a rethrow scheduled
50
+ outside a test**, beside `{ error, test }`; the README, the setup page and `agent-docs/setup.md`
51
+ named only the second. `agent-docs/errors.md` also lists the file-level forms of the message
52
+ (`Unhandled Observable errors`, `outside any test`, `while the file was imported`).
53
+ - **The 5.44.0 entry on `strayConsole` routing called `'throw'` the `setupAutoSpy` default.** The
54
+ default is `'off'`; `preset: 'strict'` sets `'throw'`. `agent-docs/setup.md` now also says both
55
+ environment lines get a `Likely cause:`, how `allow` lets one through, and that routing is off
56
+ under `disableConsoleIntercept`.
57
+ - `StrayTimersOptions` is named in `agent-docs/setup.md`; `consoleOutput()` is listed with the
58
+ `/console` entry in the README; `runner-dom-differs-from-builder` names `vite.config.*` too.
59
+ - The skill gains a row for an interceptor under test (`provideHttpTesting({ interceptors, features })`
60
+ instead of `provideHttpClient(withInterceptors([...]))` + `provideHttpClientTesting()`) and names
61
+ the two runner-parity checks in its `doctor` paragraph.
62
+
63
+ ### Internal
64
+
65
+ - **`undici` is a devDependency.** The `strayTimers` spec that fetches through the `undici` package
66
+ loaded jsdom's copy with `createRequire(import.meta.resolve('jsdom'))`, so a jsdom release that
67
+ dropped or moved the dependency would have broken the suite with nothing in `package.json` saying
68
+ why. It is now declared at the version the lockfile already held (8.10.2), and imported after the
69
+ `Symbol.dispose` shim it needs on Node 22.
70
+
71
+ ## [5.44.0] - 2026-09-27
72
+
73
+ ### Added
74
+
75
+ - **`doctor` warns when `vitest run` and the Angular builder test on different DOMs.**
76
+ `runner-dom-differs-from-builder` (warning): a `vitest.config.*` / `vite.config.*` that sets
77
+ `environment: 'jsdom'` beside an `@angular/build:unit-test` / `@nx/angular:unit-test` target that
78
+ runs happy-dom (both installed; the builder picks happy-dom whenever it resolves). `nx test` and the
79
+ IDE then run the same specs on two DOMs, and doctor said nothing — `angular-build-happy-dom` stays
80
+ quiet once happy-dom is installed. The fix aligns on happy-dom; a jsdom-only spec keeps
81
+ `// @vitest-environment jsdom`. On a 48-file Angular suite the switch took Duration from 1.37 s to
82
+ 1.10 s (−20 %).
83
+ - **`doctor` warns when Analog's `setupTestBed()` is laxer than the builder's TestBed.**
84
+ `analog-testbed-laxer-than-builder` (warning): `setupTestBed()` from
85
+ `@analogjs/vitest-angular/setup-testbed` leaves `errorOnUnknownElements` /
86
+ `errorOnUnknownProperties` off, while `@angular/build:unit-test` (20.x and 22.x checked) turns both
87
+ on, so a template typo only logs under `vitest run` and fails under `nx test`. The fix gives the
88
+ call: `setupTestBed({ errorOnUnknownElements: true, errorOnUnknownProperties: true })`. A flag
89
+ written with any value, and options passed as a variable, are left alone.
90
+ - **`consoleOutput()` from `vitest-auto-spy/console`: everything a test logged, as one value.**
91
+ Pinning a CLI's exact output meant asserting every spy at once, so each suite wrote its own
92
+ `logged()` over `consoleErrorSpy` / `consoleWarnSpy` / `consoleInfoSpy`; in one consumer that exact
93
+ form found a `console.warn` a test had passed over with `toHaveBeenCalledWith` for months.
94
+ `consoleOutput()` returns the argument lists of every recorded call keyed by channel (`debug`,
95
+ `error`, `info`, `log`, `trace`, `warn`), only the channels written to, so
96
+ `expect(consoleOutput()).toStrictEqual({ info: [['done']] })` pins the whole output with a full diff
97
+ and `{}` means silence. It throws while no spy is on `console`, rather than report silence it did
98
+ not hear. A function, not a `toHaveLogged` matcher: `toStrictEqual` already gives the diff, and the
99
+ matcher would have doubled the growth and registered `expect.extend` on every import. `/console` is
100
+ +208 B min+gzip (9973 → 10181 B, +2.1 %).
101
+ - **`strayTimers: { ignore: [...] }`.** The object form turns the sweep on and leaves alone every
102
+ timer whose scheduling stack contains one of the substrings or matches one of the RegExps — never
103
+ counted, reported or cancelled, since its owner still holds the handle. `trackStrayTimers(host,
104
+ { ignore })` takes the same list; the latest call's list is in force. The type is exported from
105
+ `/setup` as `StrayTimersOptions`. For a dependency's housekeeping no spec can reach, which until now
106
+ could only be silenced by turning `strayTimers` off for the whole project.
107
+ - **An Observable error nothing handled fails the test that raised it.** rxjs rethrows such an error
108
+ from `setTimeout(() => { throw error })`, which fails no test: it fired after the test, or the sweep
109
+ cancelled it at the end of the file and all that was left was a stray `setTimeout 0 ms, scheduled
110
+ in "<test>" at TestRequest.error` — the real error gone. With `strayTimers` on, the `afterEach` now
111
+ runs that pending rethrow early and fails the test with `Unhandled Observable error in "<test>"`,
112
+ quoting the error and carrying it as `cause`; a rethrow scheduled outside a test fails the file at
113
+ its sweep. It reads the fake clock as well while one is installed (`globalFakeTimers`), and a
114
+ rethrow `config.onUnhandledError` takes reports nothing, as in rxjs. `flushUnhandledObservableErrors()`
115
+ in `/setup` is the same check by hand. On by default with `strayTimers`, because without the sweep
116
+ the rethrow is an uncaught exception that fails the run anyway: the sweep was what hid it. The
117
+ scheduler wrappers' hot path is unchanged: a tracked `setTimeout` + `clearTimeout` pair measured
118
+ 2.13–2.20 µs before and 2.13–2.17 µs after on a stand-in host, 2.50–2.55 µs both ways on Node's real
119
+ timers, interleaved runs.
120
+ - **`provideHttpTesting({ interceptors, features })`.** A suite whose interceptor was under test had
121
+ to write `provideHttpClient(withInterceptors([...]))` + `provideHttpClientTesting()` itself, which
122
+ lost the end-of-test check and meant an `afterEach(() => verifyNoPendingRequests())` by hand.
123
+ `interceptors` takes functional interceptors and `features` any other `provideHttpClient()`
124
+ feature (`withInterceptorsFromDi()`, `withXsrfConfiguration()`); both go into one
125
+ `provideHttpClient()` call, before `provideHttpClientTesting()`, and the teardown check stays armed.
126
+ `interceptors` run in array order, before those `features` brings. `/angular-http` is +52 B
127
+ min+gzip (3652 → 3704 B, +1.4 %).
128
+
129
+ ### Fixed
130
+
131
+ - **`strayConsole` sees what the DOM environment writes — a suite under `'throw'` can newly fail.**
132
+ happy-dom's page console and jsdom's virtual console hold the worker's own console, captured when
133
+ the environment was built, before Vitest swapped `globalThis.console`; so happy-dom's
134
+ `NotSupportedError: Failed to load iframe page … Iframe page loading is disabled` and jsdom's
135
+ `Not implemented: navigation`
136
+ reached stderr of a green run, past the guard and past every console spy. The guard now routes that
137
+ console into the one it watches: the line fails the test that caused it at the spec's frame, a
138
+ `/console` spy or `vi.spyOn(…).mockImplementation` absorbs it (and can assert it), and both lines
139
+ get a `Likely cause:`. A suite under `strayConsole: 'throw'` (set by `preset: 'strict'`) that had
140
+ such lines on stderr now fails on them — that output is what the guard promises to catch. Fix the
141
+ cause (stub the API, mock the navigation, absorb it with a console spy), or let a line through with
142
+ `strayConsole: { allow: ['Not implemented: navigation'] }`. Routing is off when Vitest does not
143
+ intercept the console (`disableConsoleIntercept`).
144
+ - **`no-redundant-mock-reset` no longer calls a reset dead on a flag the Angular unit-test builder
145
+ never reads.** `@angular/build:unit-test` and `@nx/angular:unit-test` hand Vitest `config: false`
146
+ unless the target names a `runnerConfig`, so a `restoreMocks: true` / `mockReset: true` in the
147
+ `vitest.config.ts` the rule read (found or `configFile`) did not apply under `ng test` / `nx test`,
148
+ and deleting the reported line broke that run. The rule now finds the unit-test targets whose
149
+ project root holds the spec (`angular.json` / `workspace.json` / `project.json`, executors from
150
+ `nx.json` `targetDefaults`), resolves each target's and configuration's `runnerConfig` as the
151
+ builder does, and reports a reset only where every run performs it. A clear stays reported on
152
+ Vitest 5, whose default clears under the builder too. Workspaces without such a target, and flags
153
+ passed inline as options, are read as before. `/eslint-plugin` is +825 B min+gzip (42269 →
154
+ 43094 B, +2.0 %): the workspace reader.
155
+ - **A function in `overrides` for a method is a spy now, as `Spy<T>` says.** `provideAutoSpy(DomSanitizer,
156
+ { overrides: { sanitize: (_c, v) => String(v) } })` stored the function as written, so
157
+ `expect(injectSpy(DomSanitizer).sanitize).toHaveBeenCalledOnce()` compiled and threw
158
+ `[Function sanitize] is not a spy`. On `createSpyFromClass` / `provideAutoSpy` a plain function seeded
159
+ on a method (a prototype method, a name in `methodsToSpyOn` / `instanceMethodsToSpyOn` /
160
+ `onlyMethodsToSpyOn`, any member of the abstract-class fallback or a `fillMissing` double) becomes that
161
+ method's spy with the function as its implementation: calls, `mock.calls` and `calledWith` work, the
162
+ function runs with the double as `this` until the test configures the spy, it counts as configured
163
+ under `strict` (framework hooks such as `ngOnDestroy` included), and `resetAutoSpy` brings it back.
164
+ Kept exactly as seeded: values, getter seeds, a function on a non-method field, a class, and any
165
+ callable with its own API — a `vi.fn()`, a library spy, a signal — so a held `vi.fn()` keeps its
166
+ identity. The seed still wins over `returns` / `selfReturning` for the same key. `createAutoMock`,
167
+ `provideAutoSpyForToken` and `createSpyFromInstance` are unchanged. Cost: one spy per seeded method,
168
+ created at build instead of on first read (+0.5 µs per seeded method, `bench` case "createSpyFromClass
169
+ with overrides"); the root entry is +191 B min+gzip (27636 → 27827 B, +0.7 %), and the entries
170
+ built on it +182–216 B each.
171
+ - **`perf-heap` no longer calls the first load of a module a leak.** Under `isolate: false` a worker
172
+ evaluates a module once and keeps it, so the first file in a lane to import `@sentry/angular` or a
173
+ zod-heavy barrel showed its +8–10 MB as heap the spec left behind, and two runs over the same files
174
+ named different files. The reporter now records, per file, the modules the worker evaluated for the
175
+ first time (keys of Vitest's import durations the lane's previous file did not have), and `perf`
176
+ lists growth that comes with a first load of 50 ms or more in a second note, "first load of
177
+ `@sentry/angular` in this worker (+8 MB), not retained by the spec". When several lanes first-loaded
178
+ the same module, a file at more than twice the middle reading keeps the rest in the leak list
179
+ ("+21 MB beyond the first load of …"); a file that loaded nothing new is reported as before. A
180
+ measured run under `isolate: false` asks Vitest for 30 import durations instead of 10, because the
181
+ worker's table keeps every earlier spec. The report gains an optional `firstLoads` per file (format
182
+ version unchanged; an older report reads as before). `/perf-reporter` is +242 B min+gzip (1736 →
183
+ 1978 B, +13.9 %) and +1.4 kB to import (8599 → 9967 B): the lane walk that finds the first loads.
184
+ - **`strayTimers` no longer charges undici's timers to the spec.** Node's global `fetch()` runs on
185
+ undici, which keeps a 499 ms tick and a keep-alive timeout per pooled connection. A file that
186
+ fetched from a server it could not close failed `onStrayTimers: 'throw'` with `setTimeout 499 ms …
187
+ at new Promise (<anonymous>)` and `setTimeout 3000 ms … at Parser.setTimeout (…/undici/lib/…)`,
188
+ nothing a spec could fix. A timer whose scheduling call's nearest frame outside this package and
189
+ zone.js is undici (`node:internal/deps/undici`, or the `undici` package) is now neither counted,
190
+ reported nor cancelled — cancelling it would stall undici's timeouts for the rest of the worker. A
191
+ spec callback undici calls synchronously (a `MockAgent` reply) still has its own timers charged.
192
+
193
+ ### Size
194
+
195
+ `/setup` **27760 → 29187 B** min+gzip (+1427 B, +5.1 %) and +7.7 kB to import (157520 → 165233 B):
196
+ about 1.0 kB of it is the unhandled-Observable check and `strayTimers: { ignore }` with the undici
197
+ filter, about 0.4 kB the environment-console routing and its two `Likely cause:` lines (an esbuild
198
+ bundle of the sources before and after each, 31133 → 31544 → 32607 B).
199
+
13
200
  ## [5.43.0] - 2026-09-27
14
201
 
15
202
  ### Added
@@ -5735,7 +5922,9 @@ moved under 1 %: `/angular` +192 B (+1.0 %) for the override queue and the HTTP
5735
5922
  This copy ships with the package and carries 5.x only. Releases before 5.0.0 are in the
5736
5923
  [full changelog](https://github.com/ASDAlexey/vitest-auto-spy/blob/master/CHANGELOG.md).
5737
5924
 
5738
- [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.43.0...HEAD
5925
+ [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.45.0...HEAD
5926
+ [5.45.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.44.0...v5.45.0
5927
+ [5.44.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.43.0...v5.44.0
5739
5928
  [5.43.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.42.0...v5.43.0
5740
5929
  [5.42.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.41.0...v5.42.0
5741
5930
  [5.41.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.40.1...v5.41.0