vitest-auto-spy 5.32.2 → 5.34.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 +190 -176
- package/CHANGELOG.md +87 -1
- package/README.md +6 -5
- package/dist/angular-diagnostics.js +10 -10
- package/dist/angular-doubles.js +8 -8
- package/dist/angular-http.js +4 -4
- package/dist/angular-matchers.js +1 -1
- package/dist/angular-router.js +5 -5
- package/dist/angular.d.ts +2 -2
- package/dist/angular.js +5 -1
- package/dist/bun-angular.d.ts +2 -2
- package/dist/bun-angular.js +16 -16
- package/dist/bun.d.ts +1 -1
- package/dist/bun.js +9 -9
- package/dist/{chunk-XUPBHHJD.js → chunk-4AQIDYTD.js} +1 -1
- package/dist/{chunk-F2KBJC7P.js → chunk-4XDGO2IR.js} +1 -1
- package/dist/{chunk-JR55747M.js → chunk-4YZ7PIXM.js} +3 -3
- package/dist/{chunk-LAPHUX5G.js → chunk-7C6PVODW.js} +1 -1
- package/dist/{chunk-7WM3A4IB.js → chunk-ABJTCB5O.js} +2 -2
- package/dist/{chunk-YUGSITWJ.js → chunk-C5H7JCPE.js} +1 -1
- package/dist/{chunk-6JLBZHQ3.js → chunk-DMW7ROVM.js} +2 -2
- package/dist/{chunk-JOPCMFYN.js → chunk-DN4MV4FB.js} +2 -1
- package/dist/{chunk-GSMWYZ5A.js → chunk-GHP66ADY.js} +4 -4
- package/dist/{chunk-CLQUJX6E.js → chunk-HCBVNAMT.js} +1 -1
- package/dist/{chunk-6JQ7AFWM.js → chunk-IH7NDMVG.js} +8 -4
- package/dist/{chunk-72H6HNDI.js → chunk-LGGUCVT5.js} +2 -2
- package/dist/{chunk-DNXCZOYY.js → chunk-NVCLX43M.js} +1 -1
- package/dist/{chunk-24JTFFQL.js → chunk-ON4SQZQL.js} +1 -1
- package/dist/{chunk-XNXIHKVM.js → chunk-TQXPN6GV.js} +1 -1
- package/dist/{chunk-TMFV4DXT.js → chunk-TVVDNN3U.js} +45 -6
- package/dist/{chunk-YDPOBKST.js → chunk-UMBYWKKX.js} +3 -3
- package/dist/{chunk-2QEM4WP7.js → chunk-YVH6M22H.js} +1 -1
- package/dist/cli.js +2 -1
- package/dist/console.js +7 -7
- package/dist/dom-stubs.d.ts +21 -4
- package/dist/dom-stubs.js +19 -5
- package/dist/eslint-plugin.cjs +47 -12
- package/dist/eslint-plugin.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +45 -1
- package/dist/jasmine-compat.js +2 -2
- package/dist/jasmine.js +10 -10
- package/dist/nestjs.js +10 -10
- package/dist/node.cjs +45 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +45 -1
- package/dist/{prop-mock-DUcl1uMH.d.ts → prop-mock-8Ps9usRa.d.ts} +4 -0
- package/dist/react.d.ts +1 -1
- package/dist/react.js +45 -1
- package/dist/rstest.d.ts +1 -1
- package/dist/rstest.js +9 -9
- package/dist/rxjs.js +2 -2
- package/dist/setup.d.ts +1 -1
- package/dist/setup.js +5 -1
- package/dist/signal-forms.js +1 -1
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.js +45 -1
- package/dist/{track-signal-runs-BVbIBVS7.d.ts → track-signal-runs-BuJk_Yi8.d.ts} +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +45 -1
- package/dist/zone.js +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -201,7 +201,7 @@ three ways back compose — `restoreSpiedInstance(instance)` for one object mid-
|
|
|
201
201
|
`using spy = createSpyFromInstance(client)`, whose dispose **restores** rather than merely resets:
|
|
202
202
|
the only sense disposal can have for an object the consumer owns. A frozen or sealed instance, and a
|
|
203
203
|
member declared `configurable: false`, come back as this package's diagnostic rather than a bare
|
|
204
|
-
`TypeError` (§17). Nothing else in the field does this — `vi.mockObject` is Vitest-only,
|
|
204
|
+
`TypeError` (§17) — except a writable, enumerable one, whose value is simply replaced in place. Nothing else in the field does this — `vi.mockObject` is Vitest-only,
|
|
205
205
|
`sinon.createStubInstance` builds a new object from a constructor instead of patching the one you
|
|
206
206
|
hold, and `bun:test` and `node:test` have nothing.
|
|
207
207
|
|
|
@@ -230,12 +230,19 @@ core re-export, so those suites import it from the root; `spyOnVoidMethod` below
|
|
|
230
230
|
node's prototype chain, and past the component's own class that chain is the engine's: happy-dom's
|
|
231
231
|
`Node.removeChild` calls an internal Symbol-keyed method on the child, and once discovery has
|
|
232
232
|
patched it the strict guard refuses that call — the node cannot be removed from `document.body` at
|
|
233
|
-
all, and the leak then fails later tests in the file far from the cause.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
233
|
+
all, and the leak then fails later tests in the file far from the cause. Without `onlyMethodsToSpyOn`
|
|
234
|
+
on a live `Node`, the global `window` or another engine-provided event target (`XMLHttpRequest`,
|
|
235
|
+
`AbortSignal`), the call now reports this itself — a class of your own that extends `EventTarget` does
|
|
236
|
+
not count, before patching
|
|
237
|
+
anything — `warn` by default, or a throw right there under `setMisconfigurationReaction('throw')`.
|
|
238
|
+
The bare-array shorthand does not silence it: `createSpyFromInstance(el, ['addEventListener'])`
|
|
239
|
+
merges as `methodsToSpyOn`, the _additive_ list, so discovery still walks the whole node — only
|
|
240
|
+
`{ onlyMethodsToSpyOn: [...] }` skips it. For a still-attached element, spy one property with
|
|
241
|
+
`mockValueProp(el, 'addEventListener', vi.fn())` (§9) — the node stays otherwise real and removable.
|
|
242
|
+
For a native void method the handler is meant to call (`preventDefault`, `stopPropagation`, `focus`),
|
|
243
|
+
`spyOnVoidMethod(event, 'preventDefault')` packs the whitelist and the
|
|
244
|
+
`returns: { preventDefault: undefined }` seed a strict suite otherwise needs, naming the method once
|
|
245
|
+
instead of twice.
|
|
239
246
|
|
|
240
247
|
**`createFixture<T>(defaults, overrides?)` / `createFixtureFactory<T>(defaults)` are for the model
|
|
241
248
|
that more than one spec builds.** The difference from `createMock` is the `defaults` argument: it is
|
|
@@ -2486,9 +2493,14 @@ it('scrolls after the next frame', () => {
|
|
|
2486
2493
|
`stubAnimationFrame` stubs `cancelAnimationFrame` too, and hands both spies back as
|
|
2487
2494
|
`frames.requestAnimationFrame` / `frames.cancelAnimationFrame`. A frame requested from inside a
|
|
2488
2495
|
running frame is queued in either mode, so a loop that requests its own next frame advances one step
|
|
2489
|
-
per `flush()`.
|
|
2490
|
-
|
|
2491
|
-
|
|
2496
|
+
per `flush()`. A callback that throws stops `flush()` (or propagates out of `requestAnimationFrame`
|
|
2497
|
+
in `'immediate'` mode); pass `onError: (error) => { … }` to intercept it instead — rethrow from
|
|
2498
|
+
inside to keep the default for an error you did not mean to swallow. `stubElementRect` returns a real
|
|
2499
|
+
`DOMRect` per call, edges derived, plus the installed spy as `.getBoundingClientRect` for
|
|
2500
|
+
`expect(stub.getBoundingClientRect).toHaveBeenCalled()`, and the return value is still callable as the
|
|
2501
|
+
undo. The box is the spy's creation implementation, so `vi.resetAllMocks()` / `mockReset()` mid-test
|
|
2502
|
+
keeps it on both spy engines; Bun's `mockReset()` drops it (re-stub after a reset there). Both go through `mockValueProp`, so `restoreMockedProps()` (and `setupAutoSpy()` between tests)
|
|
2503
|
+
takes them off; `frames.restore()` does it sooner.
|
|
2492
2504
|
|
|
2493
2505
|
### A module mock that did nothing
|
|
2494
2506
|
|
|
@@ -4218,172 +4230,174 @@ packages, which a subpath export can never be.
|
|
|
4218
4230
|
|
|
4219
4231
|
## 17. Error → fix
|
|
4220
4232
|
|
|
4221
|
-
| Message contains | Cause
|
|
4222
|
-
| -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
4223
|
-
| `No mock adapter registered` | no runtime entry was imported, or the wrong one — or the setup file that imports it never ran: an `@angular/build:unit-test` / `@nx/angular:unit-test` target runs only the `setupFiles` it names (`doctor` reports `builder-setup-unreached`)
|
|
4224
|
-
| `No "X" export is defined on the "<m>" mock`, in a spec whose `vi.mock('<m>')` has no factory | another spec file mocked `<m>` with a factory, and under `isolate: false` Vitest hands that factory to a later automock or `{ spy: true }` mock of the same module (`doctor` reports `module-mock-leak`)
|
|
4225
|
-
| `Observable spies require rxjs` | the rxjs layer was never loaded
|
|
4226
|
-
| `… is not subscribable (…)` | the argument is not an observable — most often the value it emits, or a promise
|
|
4227
|
-
| `expectEmission(x): no value within N ms (0 received)` | nothing triggered the stream — or, when the message says timers are fake, the callbacks feeding it wait on a clock this watchdog never advances
|
|
4228
|
-
| ``… the `advance` callback threw: …`` | the `{ advance }` callback failed; the original is on `cause` and the subscription is torn down
|
|
4229
|
-
| `expectEmissions(source$, 0) can never succeed` | a count below 1 — usually `expectEmissions(s, expected.length)` with an empty expectation
|
|
4230
|
-
| `setEmissionTimeout(NaN) needs a non-negative number of milliseconds` | arithmetic on something unset reached the setter
|
|
4231
|
-
| `Type 'SubjectLike<T>' is not assignable to type 'Subject<T>'` | 4.0.0: `returnSubject()` is rxjs-typed only where `vitest-auto-spy/rxjs` is in the TypeScript program, and it is not in this one
|
|
4232
|
-
| `Cannot read properties of undefined (reading 'returnValue')` on `spy.m.and.…` | the jasmine namespaces are not installed — the spy was built before them, or nothing installed them at all
|
|
4233
|
-
| `spy.withArgs is not a function` | the same, seen from the argument-matching side
|
|
4234
|
-
| `withArgs(…).and.callFake() is not supported` | `callFake` / `callThrough` / `returnValues` install an implementation, which answers every call rather than one argument list
|
|
4235
|
-
| `jasmine is not defined` | jasmine's global is the runner's, and Vitest declares none
|
|
4236
|
-
| `done.fail is not a function` | Vitest passes a `TestContext`, not jasmine's `done`; the line usually sits in an `error` callback nobody awaits, so the run stays **green**
|
|
4237
|
-
| a `.withContext('…')` message that never appears in the failure output | Vitest's chai layer has an `@internal` `withContext(flags)`; handed a string it walks the character indices, sets nonsense flags and returns `this`
|
|
4238
|
-
| `onlyMethodsToSpyOn names 'x' (did you mean 'y'?), not a method of X` | a typo, or a method the constructor assigns (an arrow property, a `signal()` field, a `signalStore()` method)
|
|
4239
|
-
| `All declarations of 'Matchers' must have identical type parameters` | a custom matcher declares `interface Matchers<T = any>` (the Vitest 4 shape) while Vitest 5 declares `Matchers<R, T>`
|
|
4240
|
-
| `toHaveBeenCalledTimes` reads `0` for a call an earlier test made, after moving to Vitest 5 | `clearMocks` defaults to `true` on Vitest 5, so `vi.clearAllMocks()` runs before every test
|
|
4241
|
-
| `X.method is set up with mustBeCalledWith, and this call matches none of its configs` | the code called the spy with other arguments; with one config set up the line ends with the first that differs (`argument 2: expected 'eu', got 'us'`). `X.` appears on a strict double only
|
|
4242
|
-
| `extendWithAutoSpies needs Vitest 4.1 or newer` | the `test` handed in has only the object-form `extend` (Vitest ≤ 4.0); the builder form the helper is written against arrived in 4.1
|
|
4243
|
-
| `advanceTimers() requires fake timers` | no fake timers installed
|
|
4244
|
-
| `advanceTimers() found only the clock faked, not the timers` | `mockSystemTime()` installed `Date` alone, so there is nothing to advance and the call used to pass having done nothing
|
|
4245
|
-
| `X.method(…) was called; this strict double has nothing configured for it` | a strict double was asked for a method no line configured
|
|
4246
|
-
| `X.member was read N times on a strict double and nothing configured it` (or `was subscribed to N times on a strict double and never emitted`) | `setupAutoSpy({ unconfiguredReads })`, after the test — the code under test read a strict double's spied getter and got `undefined`, or subscribed to its observable property and nothing ever emitted
|
|
4247
|
-
| `[vitest-auto-spy] "…" wrote to console.<method> N time(s) and nothing absorbed it` | `setupAutoSpy({ strayConsole })` — the test printed, and nothing that does not call through stood on `console`: no `/console` spy installed for it, no `mockImplementation`. A bare `vi.spyOn(console, m)` calls through, and a `console.warn` from this library counts too
|
|
4248
|
-
| `… wrote to the console N time(s) outside any test` | output while the file was imported, in a `beforeAll` / `afterAll`, from a callback after its test ended, or from a test whose `afterEach` never ran — the frame names the line
|
|
4249
|
-
| `… wrote to console.<method> N time(s) while the file was being imported` | a module the file imports wrote while it was evaluated (a static block, a decorator, a top-level call), or a `describe` body did — before any hook, so no spy absorbs it; it lands on the first file of the worker to import that module
|
|
4250
|
-
| `It is reported at the end of b.spec.ts: the file-end check of a.spec.ts did not run.` | `a.spec.ts`'s own `afterAll` threw, so its file-end checks never ran and its console output was carried into the next file
|
|
4251
|
-
| `"…" made N call(s) a strict double had nothing configured for, and the throw never reached the test` | `setupAutoSpy({ strict: true })` — a strict double threw, and a `catch` in the code under test or an RxJS subscriber with no error callback swallowed it; each call is quoted with its arguments and the line that made it
|
|
4252
|
-
| `a.spec.ts left N timer(s) pending when it ended` | `onStrayTimers: 'throw'` — a timer outlived its file; each line names the test that scheduled it (or `while the file was imported`, `outside any test`), and it was cancelled
|
|
4253
|
-
| `a.spec.ts left N window/document listener(s) attached when it ended` | `onStrayListeners: 'throw'` — a listener outlived its file; each line names the test that added it, and it was removed
|
|
4254
|
-
| `N file-end checks failed when a.spec.ts ended` | several file-end reports failed together — stray timers, listeners, console output — and each numbered block is one of them
|
|
4255
|
-
| `fetch is stubbed in unit tests — GET <url>. The test "…" requested it` | `blockNetwork` refused a request the named test made (a blocked `XMLHttpRequest` carries the same marker on `statusText`)
|
|
4256
|
-
| `X.member.nextWithValues() ran after something subscribed to X.member` | `nextWithValues` on an observable property publishes a new stream, which the subscriber already holding the old one never sees; `X.` appears on a strict double only
|
|
4257
|
-
| `assertMocked(…): x is the real function — … did not apply` (or `no export is a mock`) | the module mock did not reach the code under test; the message names the cause that fits the run — `isolate: false` with the module already loaded, or the code importing it through another path
|
|
4258
|
-
| `setupAutoSpy({ strict: true })` has no effect — no double throws, a suite with it on stays green | before this release the default lived in module scope, and `/setup` and the factory bundles each carried a copy; a 1759-file consumer ran 12 717 tests green with it on
|
|
4259
|
-
| a seeded getter reads `undefined`: `provideAutoSpy(X, { overrides: { flagsConfig } })` next to `gettersToSpyOn` or a `registerAutoSpyDefaults` row | before this release the seed was assigned into the spied accessor's setter, and the getter kept answering `undefined`
|
|
4260
|
-
| `Cannot read properties of undefined (reading 'name')` on `value.constructor.name`, with `createAutoMock<T>()` | `constructor` answered `undefined` on an auto-mock
|
|
4261
|
-
| `Cannot redefine property: …` from a library accessor spy | the target is an ES module namespace a bundler inlined
|
|
4262
|
-
| `Cannot spy on this instance in place: it is not extensible` | `createSpyFromInstance` was handed a frozen or sealed object
|
|
4263
|
-
| `
|
|
4264
|
-
| `
|
|
4265
|
-
|
|
|
4266
|
-
|
|
|
4267
|
-
|
|
|
4268
|
-
|
|
|
4269
|
-
| `
|
|
4270
|
-
| `
|
|
4271
|
-
| `
|
|
4272
|
-
| `Cannot read properties of undefined
|
|
4273
|
-
| `
|
|
4274
|
-
| `
|
|
4275
|
-
| `
|
|
4276
|
-
| `
|
|
4277
|
-
| `
|
|
4278
|
-
| `
|
|
4279
|
-
| `
|
|
4280
|
-
|
|
|
4281
|
-
| `
|
|
4282
|
-
|
|
|
4283
|
-
|
|
|
4284
|
-
| `
|
|
4285
|
-
|
|
|
4286
|
-
| `
|
|
4287
|
-
|
|
|
4288
|
-
| `
|
|
4289
|
-
| `
|
|
4290
|
-
| `
|
|
4291
|
-
|
|
|
4292
|
-
|
|
|
4293
|
-
|
|
|
4294
|
-
|
|
|
4295
|
-
|
|
|
4296
|
-
| a
|
|
4297
|
-
|
|
|
4298
|
-
| `
|
|
4299
|
-
|
|
|
4300
|
-
| `
|
|
4301
|
-
| `
|
|
4302
|
-
| `
|
|
4303
|
-
| `
|
|
4304
|
-
| `
|
|
4305
|
-
| `
|
|
4306
|
-
| `
|
|
4307
|
-
| `
|
|
4308
|
-
| `
|
|
4309
|
-
| `is missing
|
|
4310
|
-
| `
|
|
4311
|
-
| `
|
|
4312
|
-
| `
|
|
4313
|
-
| `
|
|
4314
|
-
| `
|
|
4315
|
-
|
|
|
4316
|
-
|
|
|
4317
|
-
| `
|
|
4318
|
-
| `
|
|
4319
|
-
| `
|
|
4320
|
-
| `
|
|
4321
|
-
| `
|
|
4322
|
-
| `
|
|
4323
|
-
| `
|
|
4324
|
-
| `
|
|
4325
|
-
|
|
|
4326
|
-
|
|
|
4327
|
-
| a
|
|
4328
|
-
|
|
|
4329
|
-
|
|
|
4330
|
-
|
|
|
4331
|
-
| `
|
|
4332
|
-
| a
|
|
4333
|
-
|
|
|
4334
|
-
|
|
|
4335
|
-
| a
|
|
4336
|
-
| `
|
|
4337
|
-
|
|
|
4338
|
-
| `
|
|
4339
|
-
| `
|
|
4340
|
-
| `
|
|
4341
|
-
| `
|
|
4342
|
-
| `
|
|
4343
|
-
| `
|
|
4344
|
-
| `
|
|
4345
|
-
| `
|
|
4346
|
-
| `
|
|
4347
|
-
| `
|
|
4348
|
-
| `
|
|
4349
|
-
| `
|
|
4350
|
-
| `
|
|
4351
|
-
| `
|
|
4352
|
-
| `
|
|
4353
|
-
| `
|
|
4354
|
-
| `
|
|
4355
|
-
| `
|
|
4356
|
-
| `
|
|
4357
|
-
|
|
|
4358
|
-
| `
|
|
4359
|
-
|
|
|
4360
|
-
|
|
|
4361
|
-
| a
|
|
4362
|
-
| a
|
|
4363
|
-
|
|
|
4364
|
-
|
|
|
4365
|
-
| `
|
|
4366
|
-
| `createNestUnit(X):
|
|
4367
|
-
| `createNestUnit(X)
|
|
4368
|
-
| `createNestUnit(X)
|
|
4369
|
-
| `
|
|
4370
|
-
| `
|
|
4371
|
-
| `
|
|
4372
|
-
|
|
|
4373
|
-
|
|
|
4374
|
-
| `
|
|
4375
|
-
|
|
|
4376
|
-
| `expectRequest: no
|
|
4377
|
-
| `expectRequest: no
|
|
4378
|
-
| `
|
|
4379
|
-
| `
|
|
4380
|
-
| `
|
|
4381
|
-
| `
|
|
4382
|
-
| `
|
|
4383
|
-
| `
|
|
4384
|
-
| `
|
|
4385
|
-
| `
|
|
4386
|
-
| `
|
|
4233
|
+
| Message contains | Cause | Fix |
|
|
4234
|
+
| -------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
4235
|
+
| `No mock adapter registered` | no runtime entry was imported, or the wrong one — or the setup file that imports it never ran: an `@angular/build:unit-test` / `@nx/angular:unit-test` target runs only the `setupFiles` it names (`doctor` reports `builder-setup-unreached`) | the one import the message names — it detects the runner (Vitest, `bun:test`, `node:test`, Rstest) and links that runner's installation section; under the unit-test builder, name the setup file in the target's `setupFiles` |
|
|
4236
|
+
| `No "X" export is defined on the "<m>" mock`, in a spec whose `vi.mock('<m>')` has no factory | another spec file mocked `<m>` with a factory, and under `isolate: false` Vitest hands that factory to a later automock or `{ spy: true }` mock of the same module (`doctor` reports `module-mock-leak`) | mock it the same way in both files, or `vi.resetModules()` in this file before importing it |
|
|
4237
|
+
| `Observable spies require rxjs` | the rxjs layer was never loaded | `import 'vitest-auto-spy/rxjs';` once, in the setup file |
|
|
4238
|
+
| `… is not subscribable (…)` | the argument is not an observable — most often the value it emits, or a promise | pass the observable itself; `await` a promise directly (§8) |
|
|
4239
|
+
| `expectEmission(x): no value within N ms (0 received)` | nothing triggered the stream — or, when the message says timers are fake, the callbacks feeding it wait on a clock this watchdog never advances | check the call that should make it emit and the spy feeding it (`nextWith`); under fake timers pass `{ advance: () => vi.advanceTimersByTime(ms) }` (§8) |
|
|
4240
|
+
| ``… the `advance` callback threw: …`` | the `{ advance }` callback failed; the original is on `cause` and the subscription is torn down | fix the callback — a `vi.runAllTimers()` with no fake timers installed is the usual one (§8) |
|
|
4241
|
+
| `expectEmissions(source$, 0) can never succeed` | a count below 1 — usually `expectEmissions(s, expected.length)` with an empty expectation | `expectNoEmission(source$)`, which is the assertion that was meant (§8) |
|
|
4242
|
+
| `setEmissionTimeout(NaN) needs a non-negative number of milliseconds` | arithmetic on something unset reached the setter | pass a number, `0` or `Infinity` for no watchdog (§8) |
|
|
4243
|
+
| `Type 'SubjectLike<T>' is not assignable to type 'Subject<T>'` | 4.0.0: `returnSubject()` is rxjs-typed only where `vitest-auto-spy/rxjs` is in the TypeScript program, and it is not in this one | put `import 'vitest-auto-spy/rxjs';` in a file the spec `tsconfig` includes — a `setupFiles` entry outside `include` is the usual cause |
|
|
4244
|
+
| `Cannot read properties of undefined (reading 'returnValue')` on `spy.m.and.…` | the jasmine namespaces are not installed — the spy was built before them, or nothing installed them at all | import from `vitest-auto-spy/jasmine`; on Bun / `node:test`, `enableJasmineCompat()` in the setup file (§20) |
|
|
4245
|
+
| `spy.withArgs is not a function` | the same, seen from the argument-matching side | the same — or write `spy.m.calledWith(a).mockReturnValue(v)`, which needs no layer (§20) |
|
|
4246
|
+
| `withArgs(…).and.callFake() is not supported` | `callFake` / `callThrough` / `returnValues` install an implementation, which answers every call rather than one argument list | `.withArgs(…).and.returnValue(v)` / `.throwError(e)` / `.resolveTo(v)`, or take the whole spy with `spy.and.callFake(…)` (§20) |
|
|
4247
|
+
| `jasmine is not defined` | jasmine's global is the runner's, and Vitest declares none | `import { jasmine } from 'vitest-auto-spy/jasmine'`, then `codemod --from jasmine` to rewrite the members (§20) |
|
|
4248
|
+
| `done.fail is not a function` | Vitest passes a `TestContext`, not jasmine's `done`; the line usually sits in an `error` callback nobody awaits, so the run stays **green** | assert on the failure — `await expect(firstValueFrom(src$)).rejects.toMatchObject({ … })`, or `expect.fail(message)` |
|
|
4249
|
+
| a `.withContext('…')` message that never appears in the failure output | Vitest's chai layer has an `@internal` `withContext(flags)`; handed a string it walks the character indices, sets nonsense flags and returns `this` | `expect(actual, 'message').toBe(expected)` — the second argument of `expect` is the label. Nothing throws, so nothing warns (§20) |
|
|
4250
|
+
| `onlyMethodsToSpyOn names 'x' (did you mean 'y'?), not a method of X` | a typo, or a method the constructor assigns (an arrow property, a `signal()` field, a `signalStore()` method) | take the name the message suggests; with no suggestion it names `instanceMethodsToSpyOn: ['x']`, which adds to the discovered methods (§5) |
|
|
4251
|
+
| `All declarations of 'Matchers' must have identical type parameters` | a custom matcher declares `interface Matchers<T = any>` (the Vitest 4 shape) while Vitest 5 declares `Matchers<R, T>` | declare it on `Chai.Assertion` instead — that interface has no type parameters in either major, so one declaration merges on both (§10) |
|
|
4252
|
+
| `toHaveBeenCalledTimes` reads `0` for a call an earlier test made, after moving to Vitest 5 | `clearMocks` defaults to `true` on Vitest 5, so `vi.clearAllMocks()` runs before every test | count the calls in a plain variable instead of reading the spy, or set `clearMocks: false` (§10) |
|
|
4253
|
+
| `X.method is set up with mustBeCalledWith, and this call matches none of its configs` | the code called the spy with other arguments; with one config set up the line ends with the first that differs (`argument 2: expected 'eu', got 'us'`). `X.` appears on a strict double only | that is the assertion firing — fix the value the code under test passes, or configure that call too; relax to `calledWith` when other arguments are fine |
|
|
4254
|
+
| `extendWithAutoSpies needs Vitest 4.1 or newer` | the `test` handed in has only the object-form `extend` (Vitest ≤ 4.0); the builder form the helper is written against arrived in 4.1 | upgrade Vitest, or keep `provideAutoSpy` + `injectSpy` in a `beforeEach` until then |
|
|
4255
|
+
| `advanceTimers() requires fake timers` | no fake timers installed | `setupFakeTimers()` or `vi.useFakeTimers()` first |
|
|
4256
|
+
| `advanceTimers() found only the clock faked, not the timers` | `mockSystemTime()` installed `Date` alone, so there is nothing to advance and the call used to pass having done nothing | `setupFakeTimers()` (or `vi.useFakeTimers()`) in the test that drives timers (§11) |
|
|
4257
|
+
| `X.method(…) was called; this strict double has nothing configured for it` | a strict double was asked for a method no line configured | paste the call the `Configure it in the test:` line names (`calledWith(args).mockReturnValue(…)`, or `mockReturnValue(…)` for any); `Called from` is the calling line; or `{ strict: false }` on that double (§5) |
|
|
4258
|
+
| `X.member was read N times on a strict double and nothing configured it` (or `was subscribed to N times on a strict double and never emitted`) | `setupAutoSpy({ unconfiguredReads })`, after the test — the code under test read a strict double's spied getter and got `undefined`, or subscribed to its observable property and nothing ever emitted | the advice under each finding names the member: `accessorSpies.getters.url.mockReturnValue(…)` for a getter, `events.nextWith(…)` or `overrides: { events: new Subject() }` for a stream; `mockReturnValue(undefined)` when `undefined` is the answer meant (§5) |
|
|
4259
|
+
| `[vitest-auto-spy] "…" wrote to console.<method> N time(s) and nothing absorbed it` | `setupAutoSpy({ strayConsole })` — the test printed, and nothing that does not call through stood on `console`: no `/console` spy installed for it, no `mockImplementation`. A bare `vi.spyOn(console, m)` calls through, and a `console.warn` from this library counts too | the report names the spy to assert (`installConsoleSpies()` in a `beforeEach`, then `consoleErrorSpy`, …), or says the `vi.spyOn` calls through and needs `.mockImplementation(() => undefined)`; or fix the code that printed. Importing a spy installs nothing under the guard |
|
|
4260
|
+
| `… wrote to the console N time(s) outside any test` | output while the file was imported, in a `beforeAll` / `afterAll`, from a callback after its test ended, or from a test whose `afterEach` never ran — the frame names the line | move the work into a test and absorb it there; a callback firing late is a leak — clear it where it is scheduled |
|
|
4261
|
+
| `… wrote to console.<method> N time(s) while the file was being imported` | a module the file imports wrote while it was evaluated (a static block, a decorator, a top-level call), or a `describe` body did — before any hook, so no spy absorbs it; it lands on the first file of the worker to import that module | fix the line the report names, reading the `Likely cause:` block (`NG0912`: two copies of one component in the bundle — import it from one place); `strayConsole: { allow: [...] }` only for a line inside `node_modules`, which the report offers itself |
|
|
4262
|
+
| `It is reported at the end of b.spec.ts: the file-end check of a.spec.ts did not run.` | `a.spec.ts`'s own `afterAll` threw, so its file-end checks never ran and its console output was carried into the next file | fix that `afterAll` first — its error is in `a.spec.ts`'s output — then the output the report quotes, in the file it names |
|
|
4263
|
+
| `"…" made N call(s) a strict double had nothing configured for, and the throw never reached the test` | `setupAutoSpy({ strict: true })` — a strict double threw, and a `catch` in the code under test or an RxJS subscriber with no error callback swallowed it; each call is quoted with its arguments and the line that made it | configure that method (`.mockReturnValue`, `.calledWith` or `returns`), or drain it with `takeStrictViolations()` when the test provokes it on purpose (§5) |
|
|
4264
|
+
| `a.spec.ts left N timer(s) pending when it ended` | `onStrayTimers: 'throw'` — a timer outlived its file; each line names the test that scheduled it (or `while the file was imported`, `outside any test`), and it was cancelled | clear it in the test named — `clearTimeout`, unsubscribe, `fixture.destroy()` — or run it out with fake timers before the test ends (§10) |
|
|
4265
|
+
| `a.spec.ts left N window/document listener(s) attached when it ended` | `onStrayListeners: 'throw'` — a listener outlived its file; each line names the test that added it, and it was removed | remove it in that test — `removeEventListener` with the same capture flag, an `AbortSignal`, `fixture.destroy()` (§10) |
|
|
4266
|
+
| `N file-end checks failed when a.spec.ts ended` | several file-end reports failed together — stray timers, listeners, console output — and each numbered block is one of them | fix each block on its own; Vitest also lists every member error separately |
|
|
4267
|
+
| `fetch is stubbed in unit tests — GET <url>. The test "…" requested it` | `blockNetwork` refused a request the named test made (a blocked `XMLHttpRequest` carries the same marker on `statusText`) | answer it in that test — `vi.spyOn(globalThis, 'fetch').mockResolvedValue(stubResponse({ body: … }))` — or `blockNetwork({ xhr: 'empty' })` for an XHR nobody reads (§10) |
|
|
4268
|
+
| `X.member.nextWithValues() ran after something subscribed to X.member` | `nextWithValues` on an observable property publishes a new stream, which the subscriber already holding the old one never sees; `X.` appears on a strict double only | call it before the code under test subscribes, or push into the held stream with `nextWith()`; a throw under `setupAutoSpy({ misconfiguration: 'throw' })` |
|
|
4269
|
+
| `assertMocked(…): x is the real function — … did not apply` (or `no export is a mock`) | the module mock did not reach the code under test; the message names the cause that fits the run — `isolate: false` with the module already loaded, or the code importing it through another path | under `isolate: false` mock it in the earlier file too or run this file isolated; otherwise `vi.mock` the specifier the code imports, or inject the dependency |
|
|
4270
|
+
| `setupAutoSpy({ strict: true })` has no effect — no double throws, a suite with it on stays green | before this release the default lived in module scope, and `/setup` and the factory bundles each carried a copy; a 1759-file consumer ran 12 717 tests green with it on | upgrade — the default, `onUnstubbedCall` and `setSpyEngine()` now live on `globalThis` |
|
|
4271
|
+
| a seeded getter reads `undefined`: `provideAutoSpy(X, { overrides: { flagsConfig } })` next to `gettersToSpyOn` or a `registerAutoSpyDefaults` row | before this release the seed was assigned into the spied accessor's setter, and the getter kept answering `undefined` | upgrade — `overrides` now seeds the getter spy; a later `accessorSpies.getters.x.mockReturnValue(…)` still wins |
|
|
4272
|
+
| `Cannot read properties of undefined (reading 'name')` on `value.constructor.name`, with `createAutoMock<T>()` | `constructor` answered `undefined` on an auto-mock | upgrade — it answers `Object`, as every other double does; or seed it: `createAutoMock<T>({ constructor: … })` |
|
|
4273
|
+
| `Cannot redefine property: …` from a library accessor spy | the target is an ES module namespace a bundler inlined | no spy library can win this — give the code a real seam (inject it, pass it in) and spy on that |
|
|
4274
|
+
| `Cannot spy on this instance in place: it is not extensible` | `createSpyFromInstance` was handed a frozen or sealed object | spy it before it is frozen, or build a separate double with `createSpyFromClass` (§2) |
|
|
4275
|
+
| `createSpyFromInstance(X): no onlyMethodsToSpyOn was given for a live DOM/BOM object` | discovery is about to walk the whole prototype chain of a live `Node`, `window` or other engine-provided event target (not a user class extending `EventTarget`), engine internals included — the bare-array shorthand does not avoid this, since it merges as `methodsToSpyOn`, not `onlyMethodsToSpyOn` | list the methods the test needs: `{ onlyMethodsToSpyOn: [...] }`; for one method on a node that must keep living a DOM life, `mockValueProp` / `spyOnVoidMethod` instead (§2, live DOM node) |
|
|
4276
|
+
| `Cannot mock the property 'X': it is not configurable` | the member was defined with `configurable: false`, so it cannot be redefined | members replaced before it are still restorable — `restoreSpiedInstance(instance)` or `restoreMockedProps()` |
|
|
4277
|
+
| `createSpyFromInstance`: `Cannot spy on 'X' in place: it is a non-configurable, non-enumerable own property` | the value can be rewritten but not made enumerable, so `resetAutoSpy` would never find the spy | spy it alone with `mockValueProp(instance, 'X', vi.fn())`, or build a double with `createSpyFromClass` |
|
|
4278
|
+
| `overrideComponentProvider(…): the override did not apply — C resolved T to …` | the component injects a different token, or something configured the token again after the call; the message says whether the real service or a different double won | pass the token the component actually injects (a base class, an `InjectionToken`), and override after nothing else re-configures |
|
|
4279
|
+
| `.value() was read while the resource is in the error state: …` | `mockResourceProp`'s double after `fail(reason)`, as a real `ResourceRef` behaves; the reason is on `cause` | branch on `hasValue()` / `status()` first, or assert with `toHaveResourceError()` (§13) |
|
|
4280
|
+
| `@angular/core <version> no longer carries …, which this package reads` | an Angular internal this package reads has moved; checked once per worker | nothing is fixable from a spec — report the version in the message and pin the previous Angular until a release reads the new shape (§13) |
|
|
4281
|
+
| `provideHttpTesting(): globalThis.__vitest_worker__ is not there` | the runner does not say which test is running, so the end-of-test check cannot arm — `bun:test`, `node:test` | call `verifyNoPendingRequests()` yourself (§13) |
|
|
4282
|
+
| `ngModuleScopes: X is imported into the testing module but contributes nothing` | `enableAngularDiagnostics({ ngModuleScopes })` — an AOT test bundle stripped `ɵɵsetNgModuleScope`, so the directives it exports are missing (`NG0303` / `NG0304`) | import the directives it exports directly, or declare them in the TestBed (§13) |
|
|
4283
|
+
| `assertNgModuleScopes(): X has an empty runtime scope` | the same stripped `ɵɵsetNgModuleScope`, found by the manual check; a module with providers of its own may be providers-only, and the message says so | declare what the spec needs in the TestBed module directly; leave a providers-only module out of the call (§13) |
|
|
4284
|
+
| `Cannot read properties of undefined`, stack inside the component's own constructor or a field initializer | a member the double must **hold** rather than spy on is read while the component is being constructed, and the `mockReadonlyProp` that seeds it is written _below_ `TestBed.createComponent` — so it has not run yet, and never will | seed it **before** construction: `provideAutoSpy(X, { overrides: { paymentParams: … } })`, or `provideAutoSpyForToken(TOKEN, { … })`. No later call can repair this — the throw happens inside `createComponent`, so the helper is not reached and cannot say so; the stack names the component (§9, §13) |
|
|
4285
|
+
| `arr.map(asInstance)` infers `unknown[]` | `asInstance` is overloaded, and passing it **by reference** resolves against the `DeepMockProxy<T>` overload, from which `T` cannot be inferred | `arr.map((spy) => asInstance(spy))` — the arrow gives each call its own inference. For a fixed set, `asInstances(a, b, c)` keeps the tuple types (§6) |
|
|
4286
|
+
| `Cannot read properties of undefined (reading 'provide')`, stack inside `render3/di_setup` | a barrel chunk had not run when the component's definition was built, so a provider slot is `undefined` | `assertComponentDefIntact(Cmp)` before `createComponent` — it names the list and the index (§13) |
|
|
4287
|
+
| `assertComponentDefIntact(): argument N is undefined, which carries no ɵcmp or ɵdir` | the class reference itself never arrived — the `Cannot read properties of undefined (reading 'ɵcmp')` case | the same split barrel; import the component from its own module, not the barrel (§13) |
|
|
4288
|
+
| `TS1117: An object literal cannot have multiple properties with the same name`, in a fixture | a hundred-line model literal copied into eight specs and edited independently | one `createFixtureFactory<T>(defaults)`; note the runtime keeps the **second** key, so do not auto-fix by dropping one (§12) |
|
|
4289
|
+
| `configureTestingModule was given N schema(s) that can never apply` | `enableAngularDiagnostics({ deadSchemas })` — `schemas` next to a standalone component, with `declarations` empty | drop the `schemas` entry and put the missing directive/pipe in the component's own `imports`, or use `createDirectiveHost` (§13) |
|
|
4290
|
+
| `injectSpy(X): got a real X` (or `got a plain value, not an auto-spy` for an `InjectionToken`) | nothing in the testing module provides a double; a `console.warn` once per token and spec file, a **throw** under `enableAngularDiagnostics({ unspiedProviders })` or `setupAutoSpy({ misconfiguration: 'throw' })` | the fix the message names: `provideAutoSpy(X)` in `providers`, or `{ provide: TOKEN, useValue: createAutoMock<T>() }` for a token; `TestBed.inject(X)` if the real thing is what the spec wants |
|
|
4291
|
+
| `trackInjections(...).get(X): that token is not tracked by this log` | `get` only answers for tokens whose providers the log created | add the token to the `trackInjections([...])` list, or read it from the injector directly (§13) |
|
|
4292
|
+
| `Spread syntax requires ...iterable[Symbol.iterator] to be a function`, at load time | a module-scope spread of an imported binding, inside a bundle | build the array in a function or a getter — `no-import-time-spread` (§16) |
|
|
4293
|
+
| `the timers APIs are not mocked` in a nested `describe`'s `beforeAll` | fakes armed in `beforeEach` only; Jest armed them for the whole file | `setupFakeTimers(cfg, { betweenTests: true })` / `setupAutoSpy({ globalFakeTimers: true })` |
|
|
4294
|
+
| setup-file hooks reaching only the first spec file of a worker | the setup module stayed cached (Angular unit-test builder + coverage) | run coverage with `--isolate`, or call `setupAutoSpy()` from a per-file module |
|
|
4295
|
+
| `no DOM could be installed` | `bun-angular` preload with no DOM package | `bun add -d @happy-dom/global-registrator` (or `jsdom`) |
|
|
4296
|
+
| `cannot read "…" referenced by …: ENOENT at …` | a `templateUrl` / `styleUrl` path does not resolve; the errno (`ENOENT`, `EACCES`) and the resolved path say why | fix the path, relative to the component file |
|
|
4297
|
+
| duplicate-copy report from `setupAutoSpy()` | two installs, or one loaded as both ESM and CJS | dedupe the dependency; `setupAutoSpy({ duplicateCopies: 'warn' })` to downgrade. A setup file that initialises the Angular test environment before the library loads splits Angular the same way — two copies, a second `TestBed`, and `No mock adapter registered` or overrides that never apply: `resolve.dedupe: ['@angular/core', '@angular/common', '@angular/platform-browser', '@angular/compiler', 'rxjs']` plus `test.server.deps.inline: ['vitest-auto-spy']` (Vitest 1 and up) leaves one copy of each |
|
|
4298
|
+
| `Type 'Spy<T>' is not assignable to type 'T'` | `Spy<T>` drops private members — by design | declare as `Spy<T>`, or use `asInstance()` / `asSpy()` (§6) |
|
|
4299
|
+
| a spy is never called, no warning | the method is an instance field, not on the prototype | `instanceMethodsToSpyOn`, or `createAutoMock<T>()` |
|
|
4300
|
+
| `Cannot access '__vi_import_N__' before initialization` | `vi.mock()` on `@angular/core` or a relative path | you cannot mock it — the specs are bundled. Assert the result instead |
|
|
4301
|
+
| `AggregateError at Object.dispatchError`, for a request nothing asserts on | jsdom really served an `XMLHttpRequest` — `blockNetwork` used to cover only `fetch` | `setupAutoSpy({ blockNetwork: true })`, or `{ xhr: 'empty' }` for tracker pings (§10) |
|
|
4302
|
+
| `localStorage.setItem is not a function`, or `localStorage` undefined | Node's own Web Storage made Vitest's global filter skip the environment's — Node 25 and up, jsdom and happy-dom alike | on by default in `setupAutoSpy()`; `restoreWebStorage()` on its own (§10) |
|
|
4303
|
+
| `Schedulers cannot synchronously execute watches while scheduling` | a timer from a **previous** file, under `isolate: false` | track and cancel pending timers/frames in the setup file (§10) |
|
|
4304
|
+
| `signal read during notification phase` | same — a stray `requestAnimationFrame` callback | same |
|
|
4305
|
+
| an assertion error printed to stderr, every test green and the run exiting 0 | zone.js swallowed a rejection nobody handled | `setupAutoSpy({ strayRejections: true })` fails the test it surfaced in (§10) |
|
|
4306
|
+
| an `expect()` inside a `.then()` that never seems to run | nothing awaits the chain, so the test ended first | `await` the promise and assert the settled value — `no-floating-assertion` (§16) |
|
|
4307
|
+
| `trackStrayRejections() found no zone.js on the host` | `strayRejections` turned on where zone.js is not loaded | `import 'zone.js';` in the setup file, or drop the option |
|
|
4308
|
+
| a spy on a storage method still answering after `vi.restoreAllMocks()` probed green | happy-dom's Storage proxy deletes only stored items, so the restore behind `mockRestore()` never lands; a later spec's `vi.spyOn` gets the same mock with the old calls in it | on by default — `setupAutoSpy()` repairs it at the file boundary; `restoreStorageSpies()` on its own, or `restoreStorageSpies: false` for a worker-lifetime spy (§10) |
|
|
4309
|
+
| a listener callback running against mocks and a DOM it was never written for, in a file that never added it | a `window`/`document` listener a previous file left registered, under `isolate: false` | `setupAutoSpy({ strayListeners: true })` — module-graph registrations stay, per-file ones go at the boundary (§10) |
|
|
4310
|
+
| a global a previous file patched (`ResizeObserver` answering a stub) with no file named | a raw assignment no registry tracks — not `vi.stubGlobal`, not `vi.spyOn` | `setupAutoSpy({ restoreGlobals: true })` puts the worker's baseline back at every file boundary; `guardGlobals` for the non-configurable case (§10) |
|
|
4311
|
+
| `… .destroy is not a function` | an ngrx `rxMethod` replaced with a bare mock | `Object.assign(vi.fn(), { destroy: vi.fn() })` |
|
|
4312
|
+
| `NullInjectorError` for a service you did provide | it is a component-level provider, not a module one | `asSpy(fixture.debugElement.injector.get(X))`, not `injectSpy(X)` |
|
|
4313
|
+
| `runEffect(): … not an EffectRef returned by effect()` | passed the callback, a signal, or an unassigned field | pass what `effect()` returned; a field may need its lifecycle hook to run first |
|
|
4314
|
+
| `runEffect(): this effect has been destroyed` | the fixture was destroyed, or effectRef.destroy() ran | move the call above `fixture.destroy()`, or assert what the teardown left behind |
|
|
4315
|
+
| `trackRecomputations(): this signal keeps no computation` | a plain `signal()`, which holds a value rather than computing one | track the `computed()` that reads it, or `trackEffectRuns()` the effect that does |
|
|
4316
|
+
| `mockSignalProp: '…' is an input() signal` | an `input()` replaced instead of set | `fixture.componentRef.setInput(name, value)`, or `renderShallow(C, { inputs: { … } })` |
|
|
4317
|
+
| `mockSignalProp: '…' is a computed() something has already read` | a `computed()` member swapped after the first render — a `signal().asReadonly()` member is written through instead and is never refused | patch before the first `detectChanges()` / `stable(fixture)`, or expose the member as a writable `signal()` |
|
|
4318
|
+
| `expected a signal (a zero-argument getter), received a spy` | `toHaveSignalValue` was handed a spied method instead of a signal — usually a typo, or a signal member spied as a method | assert the spy itself with `toHaveBeenCalled`, or put a real signal on the property with `mockSignalProp`; the matcher refuses it rather than calling it |
|
|
4319
|
+
| `X is not a constructor`, stack in production code | a `vi.fn(() => …)` where the code does `new X()` | `mockConstructor` / `stubConstructor` / `createSpyClass` (§12) |
|
|
4320
|
+
| `Date is not a constructor` | `vi.spyOn(globalThis, 'Date')` — the fakes own it | `mockSystemTime(date)` / `vi.setSystemTime` |
|
|
4321
|
+
| `TS2352: … 'accessorSpies' is missing in type 'X'` | `TestBed.inject(X) as Spy<X>` | `asSpy(TestBed.inject(X))` — never a double assertion (§6) |
|
|
4322
|
+
| `TS2739` / `TS2740` / `TS2345` with `Spy<X>` on the left | a spy handed to an API typed against the class | `asInstance(spy)` (§6) |
|
|
4323
|
+
| `is missing the following properties: _private, …` | declared as Vitest's `Mocked<T>` | declare `Spy<T>` (§6) |
|
|
4324
|
+
| `AddPromiseSpyMethods<unknown>` vs `WithMockReturnValue<…>` | a generic class inferred as `Service<any>` | `asSpy<Service>(…)` / `injectSpy<Service>(…)` (§6) |
|
|
4325
|
+
| `createComponentStub(): X carries no ɵcmp, ɵdir or ɵpipe to copy` | the class is not an Angular declaration, or the import resolved to `undefined` (a barrel split across chunks) | pass the `@Component` / `@Directive` / `@Pipe` class, imported from its own file (§13) |
|
|
4326
|
+
| `'isKeyEnabled' does not exist in type 'MethodReturns<{ flagsConfig: any; }>'` | generic class: `createSpyFromClass(Config, { gettersToSpyOn: ['flagsConfig'], returns: { … } })` reads `T` back from the list, because the generic class argument is checked after the configuration | generic class: spell out the type argument — `createSpyFromClass<Config>(Config, …)`; `provideAutoSpy` from `/angular` infers it (§6) |
|
|
4327
|
+
| `'addEventListener' called on an object that is not a valid instance of EventTarget` | Node's `AbortSignal` under jsdom + zone.js | `stubAbortController()` (§12) |
|
|
4328
|
+
| `vi.requireMock is not a function` | a mechanical `jest.` → `vi.` rename | there is no equivalent — provide the double through the TestBed instead |
|
|
4329
|
+
| a `vi.mock()` factory that never applies, only sometimes | under `isolate: false` the module was already in the worker's graph | do not mock it; inject the dependency, or `vi.hoisted()` + a real seam |
|
|
4330
|
+
| a `vi.mock()` of a workspace alias that never applies at all | a bundler inlined the module before the mock could be installed | `assertMocked(ns, { specifier })` to prove it, then inject instead of mocking |
|
|
4331
|
+
| `No "default" export is defined on the mock`, thrown inside a dependency | a factory returning bare named exports; the dep probes `default` | `vi.mock('x', () => moduleNamespace({ … }))` |
|
|
4332
|
+
| `adoptMock() needs a mock that can report its implementation` | a `node:test` `mock.fn()` handed to `adoptMock` | build the double with `createFunctionSpy()` and pass that to the module mock |
|
|
4333
|
+
| `Cannot spy on export "x". Module namespace is not configurable in ESM.` | `vi.spyOn(namespace, 'x')` under Vitest browser mode or a native ESM loader — the namespace is sealed | spy the class / prototype, or `vi.mock(path, { spy: true })` / `moduleNamespace(await importOriginal(), { passthrough: true })` |
|
|
4334
|
+
| `[Function] is not a spy or a call to a spy!` in a Storybook `play` | `expect` from `storybook/test` wraps a function with no own enumerable keys, and an auto-spy keeps its `mock*` methods on a shared prototype | import `expect` from `vitest` in that story file, or `setSpyEngine('runner')` from `/setup` |
|
|
4335
|
+
| `object is not iterable` destructuring a mocked hook tuple | an auto-mock stands for an object, and a Proxy double is not iterable | write the tuple — `mockReturnValue([data, false, null])`; auto-mocks are for the object a hook returns |
|
|
4336
|
+
| `The property "x" is not defined on the object` from `vi.spyOn(Class.prototype, 'x')` | `x` is an instance field (arrow function, signal), not a prototype method | `createSpyFromClass(C, { instanceMethodsToSpyOn: ['x'] })` |
|
|
4337
|
+
| `Not implemented: HTMLMediaElement.play`, or `duration` is `NaN` and cannot be set | jsdom implements the media elements as a shell | `stubMediaElement({ duration })`, then `media.set(el, …)` to fire the events |
|
|
4338
|
+
| `Cannot set base providers because it has already been called` | zone and zoneless spec files sharing one worker | `setupAngularTestEnv({ zoneless, initZone, initZoneless })` (§13) |
|
|
4339
|
+
| a stub that works in the first test of the file and in no other | installed at `describe` level or in `beforeAll`, then restored away | install it in `beforeEach`, or `installPerTest(() => stub…())` |
|
|
4340
|
+
| a third-party library failing every other run, no test named | a test sealed a global with `Object.defineProperty` (non-configurable) | `setupAutoSpy({ guardGlobals: 'throw' })` names the test; then the `mock*Prop` helper the message names |
|
|
4341
|
+
| a spec green alone that fails only in a full run, on something it reads off `<body>` / `<html>` (`querySelector('[data-…]')`, a class) | an earlier file in the worker left an attribute on the shared document | `setupAutoSpy({ documentPollution: 'throw' })` (in `preset: 'strict'`) names the test; take the attribute off in `ngOnDestroy` / `DestroyRef.onDestroy` or an `afterEach` |
|
|
4342
|
+
| `A metric with the name … has already been registered` as a failed suite with 0 failed tests, only in a full run | under `@angular/build:unit-test` with `isolate: false` a workspace module can run its module scope once **per spec file**, while an external package such as `prom-client` keeps one default registry per worker | not something a hook can catch — it throws at import. Look the metric up before creating it: `register.getSingleMetric(name) ?? new Histogram({ name, … })`, or give the module its own `new Registry()` |
|
|
4343
|
+
| `NotSupportedError: This name has already been registered in the registry` at import | the same per-spec-file evaluation reaching a module-scope `customElements.define` — the registry belongs to the worker's document | `if (!customElements.get(name)) customElements.define(name, Element)`; a definition cannot be undone, so nothing can sweep it |
|
|
4344
|
+
| a block of files reported as failed suites with no stack, and zero failing tests | a test left an own enumerable key on `Object.prototype`; `mergeHooks` spreads it and collection dies | `setupAutoSpy()` guards it by default; `prototypePollution` tunes the reaction |
|
|
4345
|
+
| `expected [ { at: 1, …(5) }, …(8) ] to deeply equal [ { …(6) }, … ]` | one field moved in every element — usually a frozen clock or an id | `expect(diffByField(actual, expected)).toBeUndefined()` — a `Date`, `Map`, `Set` or class instance is compared whole and reported as `the element`, where it used to have no string keys and so read as "no difference" |
|
|
4346
|
+
| a hand-tuned number of turns waiting for a `resource()` to load | a resource needs a change-detection **tick**, not event-loop turns; `flushEventLoopUntil` never ticks and the resource never even issues its request | `flushEffects()`, flush the request, then `await settleResource(r, { label })` |
|
|
4347
|
+
| a `resource()` assertion that passes but reads the **default** value | the spec asserted before the resource left `loading` | `await settleResource(r, { label })` — it fails loudly instead |
|
|
4348
|
+
| `settleResource: … never started — its status is 'idle'` | the `params()` / `request()` computation returned `undefined`, so the loader never ran and `value()` is still the default | set the signal that computation reads, `flushEffects()`, then await again — or `{ allowIdle: true }` when idle is the state under assertion |
|
|
4349
|
+
| a spec dying on the runner's 5 s file timeout right after `await stable(fixture)` | the fixture never stabilised — an unflushed request, a real `setInterval` | `stable` now fails at 2000 ms naming the cause; raise `{ timeout }` only once neither is true |
|
|
4350
|
+
| `flushEventLoopUntil` timing out on the **first** such test only, the rest green | a cold dynamic `import()` outran the turn budget; later tests hit the module cache | `await settleDynamicImport(() => import('…'))` — await the module, do not count turns |
|
|
4351
|
+
| `Expected to be running in 'ProxyZone', but it was not found` | `zone.js/testing` patches jasmine/mocha/jest, not Vitest | `import 'vitest-auto-spy/zone'` after zone.js, with `globals: true` (§14) |
|
|
4352
|
+
| `nextWith` demanding `HttpEvent<T>` on a generated API client | `Parameters`/`ReturnType` read the **last** overload | `asSpy<Client, { overload: 'first' }>(…)`, or `Overload<M, 0>` — never `@ts-expect-error`, which `no-ts-expect-error-on-double` reports (§16) |
|
|
4353
|
+
| `NG0303` / `NG0304` / nothing at all, from a directive spec | the host is `standalone: false`, or the module is in the TestBed | `createDirectiveHost({ template, scope: [Module] })` (§13) |
|
|
4354
|
+
| `setInputs: … declares no input named …` (with a `Did you mean` for a near typo) | the key is not an input of that component — a typo, an input renamed since, or one of its own fields | take the suggestion, or set a name the message lists; a signal the component owns is moved through the signal (§13) |
|
|
4355
|
+
| `setInputs: X carries no ɵcmp, so there are no inputs to set` (or `the component class is undefined`, `X is a @Pipe`) | the fixture's `componentType` is not a compiled `@Component` — a `@Pipe`, a class Angular never compiled, or `undefined` from a barrel split across chunks | pass the `@Component` class the fixture was created from; call a pipe's `transform()` directly; for `undefined` import the class from its own file (§13) |
|
|
4356
|
+
| `TypeError: dependencies is not a function`, from `renderShallow({ keepTemplate: true })` | the compiled `ɵcmp.dependencies` is the flat array AOT emits when no cycle forced a factory, and the trim called it | upgrade — all three shapes (array, factory, `null`) are read; nothing to change in the spec |
|
|
4357
|
+
| `renderShallow(X, { keepTemplate: true }): … is declared by Module, not standalone` (or `by an NgModule`) | an AOT dependency list: ngtsc flattened an imported `NgModule`'s exported declarations into it, and Angular takes only standalone declarations and `NgModule`s in `imports` | name that module in `keepModules: [Module]` and it is put back whole — the message names it when the spec imports it; or drop `keepTemplate` when the spec reads TypeScript state only |
|
|
4358
|
+
| `TS2540: Cannot assign to 'X' because it is a read-only property` | a `readonly` field of an object under test | `mockValueProp(obj, 'X', value)` — on a class **getter**, `mockReadonlyProp` |
|
|
4359
|
+
| `TypeError: Cannot read properties of undefined (reading 'mockReturnValue')` | the member is an **instance field**, not on the prototype — `Router.currentNavigation` since Angular 20 | `provideAutoSpy(Router, { instanceMethodsToSpyOn: ['currentNavigation'] })` (§5) |
|
|
4360
|
+
| `throwWith` reaching the success branch first, with the previous test's value | the spy's `ReplaySubject(1)` outlived the test that filled it | upgrade; and `resetAutoSpy(spy)` in `beforeEach` when the TestBed is built in `beforeAll` |
|
|
4361
|
+
| `TS2540` on a `Spy<T>` / `createAutoMock` member, which the runtime writes fine | `Spy<T>` is homomorphic and keeps the `readonly` of the source member — deliberately: on a member replaced by a **spied accessor** the assignment reaches the setter spy and the getter still answers `undefined`, so the type error is the loud version of a silent no-op | `mockValueProp(spy, 'X', value)` — it defines rather than assigns, so it works in both cases; `Mutable<Spy<T>>` is the opt-in for plain data members, and `Reflect.set` is **not** a way round it |
|
|
4362
|
+
| `TS2345` from `mockReturnValue` / `mockImplementation` / `mockResolvedValue` on a double that used to compile | the mock surface is `MockInstance<Method>`, so the stub is now checked against the method's own return type | stub with what the method returns; if the double is meant to answer something else, the method's type or the spec's expectation is wrong |
|
|
4363
|
+
| `TS2345: Argument of type 'Spy<X>' is not assignable to parameter of type 'X'` on `mockReturnValue(double)` | 5.1.0: the stub is checked against the method, and a double of the return type is a `Spy<X>`, not an `X` | `mockReturnValue(asInstance(double))` (§6) |
|
|
4364
|
+
| `with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties` on a stub | the stub's type spells an optional member `?: T` where the method's spells `?: T \| undefined` (or the reverse), or a fixture writes `key: undefined`; a `Subject` is invariant, so its type argument has to match exactly | `method.returnSubject()` for a subject typed from the method; omit the key instead of writing `undefined` |
|
|
4365
|
+
| `Types of parameters 'x' and 'y' are incompatible` on `mockImplementation(…)` | 5.1.0: the implementation is checked against the method's parameters, and an annotation in it disagrees | drop the parameter annotations and let the method type them; narrow inside the body |
|
|
4366
|
+
| `TS4111` / `TS2375` / `TS2322` inside a `mockImplementation` body that used to compile | before 5.1.0 the implementation's parameters were `any`, so nothing in its body was checked | fix the body — the error is ordinary once its parameters are typed |
|
|
4367
|
+
| `TS2349: This expression is not callable` on a value read from `spy.mock.calls` | 5.1.0 types `mock.calls` from the method; a listener taken from `addEventListener`'s calls is `EventListenerOrEventListenerObject` | narrow before calling: `if (typeof listener === 'function') listener(event)` |
|
|
4368
|
+
| `is not assignable to parameter of type 'RxMethod<…>'` (or another member type) on `mockReadonlyProp(x, 'm', vi.fn(impl))` | `vi.fn` infers its type from the member the helper replaces, so `impl` must return what the member returns | return the member's type — `Object.assign(vi.fn(), { destroy: vi.fn() })` for an `rxMethod` |
|
|
4369
|
+
| `Argument of type '() => A \| null' is not assignable to parameter of type '(() => A) \| (() => null)'` | the member is a union of call signatures — `@ngrx/signals`' `DeepSignal<A> \| Signal<null>` for a nullable slice — and 5.1.0–5.24.0 typed its stub as the union of both halves | upgrade past 5.24.0, which types the stub as one signature returning the union |
|
|
4370
|
+
| `delete mock.optionalMethod` leaving the member present and truthy | the Proxy had no `deleteProperty` trap before 3.5.0 | upgrade; before that, `mock.optionalMethod = undefined` |
|
|
4371
|
+
| half a double's methods reaching the real implementation after `Object.assign` | `ownKeys` on a type-driven Proxy lists only the keys already read | `createSpyFromClass(X)` — a real object, with enumerable method keys |
|
|
4372
|
+
| `let s: MockInstance<() => unknown>` not matching anything | `MockInstance<F>` is invariant in `F`; Jest's `SpyInstance` was not | `MockInstance<T['method']>`, or better `injectSpy(X).method` |
|
|
4373
|
+
| two runs with the same totals, one of them missing a suite | a lost `describe` and a fixed flake cancel out in the counters | `compareTestRuns(before, after)` — compare the set of names, not the numbers; `TestRunSummary.counts` carries the multiplicity, so a duplicate name that dropped from two to one reads `name (×2 → ×1)` instead of vanishing from both sides |
|
|
4374
|
+
| a 30 s timeout, in a different file each run | module-level `vi.fn()` in a fixture shared by files | make the fixture a factory (§10) |
|
|
4375
|
+
| a component's `afterNextRender` state is empty | `detectChanges()` does not run the after-render phase | `await stable(fixture)` (§11) |
|
|
4376
|
+
| a green test whose only line about a call is `spy.m.calledWith(1);` | that is a **stub**, not an assertion — chai's `expect(fn).to.have.been.calledWith(x)` is the one that checks | continue the chain, or `expect(spy.m).toHaveBeenCalledWith(1)` — `no-bare-called-with` (§16) |
|
|
4377
|
+
| `--detect-async-leaks` reporting no leaks in a suite that visibly leaks timers | `setupAutoSpy({ strayTimers: true })` cancelled them before Vitest collected | the stderr report names the file, the first three timers and the test that scheduled each; `onStrayTimers` gets every one in `timers` (§10) |
|
|
4378
|
+
| `createNestUnit(X): parameter #n of Y is typed as \`Object\``(or`undefined — usually a circular import`) | the compiler emitted no runtime class for that parameter — interface, union, primitive, or a circular import | `@Inject(TOKEN)` plus a `providers` entry, or `@Optional()` to receive `undefined`; `@Inject(forwardRef(() => X))` for the import cycle |
|
|
4379
|
+
| `createNestUnit(X): Y declares n constructor parameter(s) but carries no design:paramtypes metadata` | no `emitDecoratorMetadata` (esbuild / Vite), or `reflect-metadata` loaded after the class | tsc or SWC with `decoratorMetadata`, `@Injectable()`, `reflect-metadata` first; or `@Inject(X)` on every parameter |
|
|
4380
|
+
| `createNestUnit(X): A -> B -> A is a cycle among the classes built for real` | two exposed / `useClass` classes depend on each other; the helper does not resolve `forwardRef` cycles | expose one side less, or provide it |
|
|
4381
|
+
| `createNestUnit(X).spies.get(Y): the unit never asked for that token` | same guard as `createWithAutoSpies` — the spy would not be the one the unit uses | stub the token the unit actually injects (the message lists the auto-spied ones) |
|
|
4382
|
+
| `createNestUnit(X).spies.get(Y): Y is in \`expose\`, so the unit got a real instance` | an exposed class is real, not a spy | read the spies of its own collaborators, or drop it from `expose` |
|
|
4383
|
+
| `expect(component.ngOnInit).toHaveBeenCalled()` fails after `fixture.detectChanges()`, or a hook's `.mockImplementation` never runs | the spy was put on the **instance**; a view calls the hook it read off the class prototype when the component was created | `vi.spyOn(Cls.prototype, 'ngOnInit')` before `TestBed.createComponent`, or assert what the hook does — `no-instance-lifecycle-spy` (§16) |
|
|
4384
|
+
| `TS2345: Argument of type 'InjectionToken<X>' is not assignable to parameter of type 'ClassType<unknown>'`, on `registerAutoSpyDefaults` | the core entry's `registerAutoSpyDefaults` takes a class only — it may not name Angular's token type | import `registerAutoSpyDefaults` (and `clearAutoSpyDefaults`) from `vitest-auto-spy/angular`, which also takes an `InjectionToken` (§5) |
|
|
4385
|
+
| `returns names 'x', not a method of X` (or `which onlyMethodsToSpyOn left out`) | the name is not a method of the double — a typo, or a restricting `onlyMethodsToSpyOn` left it out; on a type-driven double, `then` and `constructor` are never spies; a method the constructor assigns (an ngrx `rxMethod`) is not on the prototype | the message names the fix: the close method it meant, adding it to `onlyMethodsToSpyOn`, or `instanceMethodsToSpyOn` for a constructor-assigned method; the value is silently never returned otherwise (§5) |
|
|
4386
|
+
| a spec green over a `useValue` fixture whose key the code never reads — `queryParams$` on an `ActivatedRoute` | `useValue` is `any`, so a renamed or misspelled key of an object literal compiles | the member's real name — `no-unknown-use-value-key` (§16), with type information; or `provideAutoSpy(X, { overrides })`, which the compiler checks |
|
|
4387
|
+
| a spec runs down the "browser" (or any flag-on) branch whatever its `useValue` says | `{ provide: IS_BROWSER, useValue: {} }` for an `InjectionToken<boolean>` — `useValue` is `any`, and an object is truthy | a value of the token's type (`useValue: false`) — `no-mistyped-use-value` (§16), with type information |
|
|
4388
|
+
| `expectRequest: no request matched … Made instead: …` | the URL or predicate describes nothing the code under test sent | compare with the requests listed — they are the ones actually made; then fix the URL or the predicate (§13) |
|
|
4389
|
+
| `expectRequest: no POST … — but GET … was made` | only the verb differs | pass `{ method }` for the verb the code sends, or fix the verb it sends (§13) |
|
|
4390
|
+
| `expectRequest: no GET …?page=2 — but GET …?page=3 was made; the query differs` | the same path, another query string | name the query the code sends, or match the path alone: `expectRequest('/api/products')` (§13) |
|
|
4391
|
+
| `expectRequest: no request matched … — nothing was requested at all` | an `httpResource()` whose `request()` returned no URL yet, or an `HttpClient` call nothing subscribed to | set the signal the resource reads, or subscribe to the call (§13) |
|
|
4392
|
+
| `this TestBed has no HttpTestingController` | `expectRequest` / `expectNoRequest` on a module that never got the testing backend | `TestBed.configureTestingModule({ providers: [...provideHttpTesting()] })` from `vitest-auto-spy/angular-http` (§13) |
|
|
4393
|
+
| `X was never answered (end of "…")` / `N requests were never answered` | `provideHttpTesting({ verifyOnTeardown })` or `enableAngularDiagnostics({ pendingRequests })` — the test left a request open; the message names its URL and the test | answer it with the line the message prints (`await expectRequest(url).flush(body)`, `controller.expectOne(url).flush(body)` under diagnostics), or assert its absence (`expectNoRequest(url)`); a cancelled one is forgiven with the `ignoreCancelled` opt-in the message names (§13) |
|
|
4394
|
+
| `injectActivatedRoute(): nothing provides ActivatedRoute here` | no `ActivatedRoute` provider in the injector it read | `provideActivatedRoute({ … })` from `vitest-auto-spy/angular-router` in `providers`; `injectActivatedRoute(fixture.debugElement.injector)` for a component-level one (§13) |
|
|
4395
|
+
| `the ActivatedRoute here is … not one provideActivatedRoute() built` | a later provider of `ActivatedRoute` won — `provideRouter()`, `RouterModule`, a `useValue`, `provideAutoSpy(ActivatedRoute)` | list `provideActivatedRoute()` last, or drop the other provider (§13) |
|
|
4396
|
+
| `provideActivatedRoute: @angular/router <version> does not wire ActivatedRoute …` | a router major builds `ActivatedRoute` with different internal constructors | report it with the `@angular/router` version; provide the route by hand until then (§13) |
|
|
4397
|
+
| `provideActivatedRoute({ title }): @angular/router <version> keeps the route title under a key …` | that router version stores the resolved title under a key this helper could not find | leave `title` out of the init for now, and report it with the `@angular/router` version (§13) |
|
|
4398
|
+
| `provideRouterDouble: the Router double has no …` | the code under test reached for a `Router` member the double does not cover — `isActive`, `resetConfig`, `lastSuccessfulNavigation` | the double covers `url`, `events`, `navigate`, `navigateByUrl`, `createUrlTree`, `serializeUrl`, `parseUrl`, `routerState` and `currentNavigation` / `getCurrentNavigation()`; past that, a real `provideRouter([])` with `RouterTestingHarness` (§13) |
|
|
4399
|
+
| `injectRouterDouble(): the Router here is Angular's own …` | `Router` is `providedIn: 'root'`, so a `TestBed` without the double hands out a real one | add `provideRouterDouble({ … })` from `vitest-auto-spy/angular-router` to `providers` (§13) |
|
|
4400
|
+
| `collectRouterEvents().expect(): the events differ at #N` (or `#N … never came`, `#N … was not expected`) | the recorded navigation events part from the expected ones there; the message prints both sequences under it | read the `Expected:` / `Recorded:` lines under it, then fix the expectation or the navigation the test drives (§13) |
|
|
4387
4401
|
|
|
4388
4402
|
**Seven of these are library defects, not spec ones.** On anything below 3.8.0, upgrade and change
|
|
4389
4403
|
nothing in the spec: `of(double)` never emitting; `accessorSpies.setters.X` still `undefined` after
|