vitest-auto-spy 5.63.0 → 5.66.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 +12 -0
- package/CHANGELOG.md +42 -1
- package/README.md +65 -3
- package/agent-docs/adapters.md +9 -0
- package/agent-docs/doubles.md +102 -2
- package/agent-docs/observables.md +37 -0
- package/dist/angular-diagnostics.js +11 -10
- package/dist/angular-doubles.d.ts +30 -2
- package/dist/angular-doubles.js +318 -14
- package/dist/angular-http.js +5 -4
- package/dist/angular-matchers.js +1 -1
- package/dist/angular-router.js +6 -6
- package/dist/angular.d.ts +3 -3
- package/dist/angular.js +1 -1
- package/dist/bun-angular.d.ts +2 -2
- package/dist/bun-angular.js +19 -19
- package/dist/bun.d.ts +1 -1
- package/dist/bun.js +11 -11
- package/dist/{chunk-TXC3L3FO.js → chunk-2CWSOIBW.js} +1 -1
- package/dist/{chunk-RQLUH6RE.js → chunk-5GKIQX65.js} +3 -3
- package/dist/{chunk-6KS7F4YM.js → chunk-7GOVSGXB.js} +2 -2
- package/dist/{chunk-IATDAQMO.js → chunk-7WU53KRS.js} +4 -1
- package/dist/{chunk-VLEU3CWT.js → chunk-A2X7O5EP.js} +2 -2
- package/dist/{chunk-JCTHGJTY.js → chunk-C7K75NLS.js} +1 -31
- package/dist/{chunk-RHGDQQNC.js → chunk-DCCURN7I.js} +1 -1
- package/dist/{chunk-MXKNUVYR.js → chunk-DWMIQ7VO.js} +1 -1
- package/dist/{chunk-75WPOZKE.js → chunk-EZKDQ4WO.js} +1 -1
- package/dist/{chunk-ZTT2QLMJ.js → chunk-EZTP5VUF.js} +4 -4
- package/dist/{chunk-UH2Q7RTQ.js → chunk-HIGHZ4BW.js} +2 -2
- package/dist/{chunk-JFROAGGY.js → chunk-IXARK3B6.js} +2 -2
- package/dist/{chunk-EFUZ44HT.js → chunk-KCQOZSNA.js} +75 -7
- package/dist/{chunk-XZ5JUXKT.js → chunk-NMXLXBXH.js} +2 -2
- package/dist/chunk-OIHOH2RY.js +34 -0
- package/dist/{chunk-OWZPZBJI.js → chunk-OXE6FCQX.js} +4 -4
- package/dist/{chunk-3OEYMUV3.js → chunk-PS6UQC4C.js} +1 -1
- package/dist/{chunk-F7UPX6YV.js → chunk-QATP6Q3G.js} +1 -1
- package/dist/{chunk-R43PMWFH.js → chunk-TRRI7TXE.js} +1 -1
- package/dist/{chunk-BCT7C6DQ.js → chunk-XLKBJSYQ.js} +3 -3
- package/dist/{chunk-4JY7KIJG.js → chunk-XZS56XV5.js} +1 -1
- package/dist/cli.js +20 -1
- package/dist/console.js +8 -8
- package/dist/core.d.ts +1 -1
- package/dist/dom-stubs.d.ts +41 -87
- package/dist/dom-stubs.js +76 -8
- package/dist/element-stub-D3kchFNq.d.ts +97 -0
- package/dist/{emission-sync-ByzgYsbj.d.ts → emission-positive-sync-BrSc2lb-.d.ts} +20 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +70 -2
- package/dist/jasmine-compat.js +2 -2
- package/dist/jasmine.js +12 -12
- package/dist/nestjs.d.ts +65 -1
- package/dist/nestjs.js +93 -12
- package/dist/node.cjs +70 -0
- package/dist/node.d.cts +2 -0
- package/dist/node.d.ts +1 -1
- package/dist/node.js +69 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/rstest.d.ts +1 -1
- package/dist/rstest.js +10 -10
- package/dist/rxjs.js +2 -2
- package/dist/signal-forms.js +1 -1
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.js +1 -1
- package/dist/{track-signal-runs-D1Vr9BdG.d.ts → track-signal-runs-DLvVp9iI.d.ts} +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1 -1
- package/dist/zone.js +1 -1
- package/package.json +1 -1
- package/skills/vitest-auto-spy/SKILL.md +12 -1
package/AGENTS.md
CHANGED
|
@@ -154,6 +154,11 @@ In [`agent-docs/factories.md`](./agent-docs/factories.md). Read it before writin
|
|
|
154
154
|
|
|
155
155
|
## 3. The 90% recipe
|
|
156
156
|
|
|
157
|
+
Direct handler tests: `/dom-stubs` supplies `createDomEvent`, `createInputEvent`, `createPasteEvent`
|
|
158
|
+
and `createDropEvent`. `/angular/doubles` supplies `mockElementRefProp` for an element signal query
|
|
159
|
+
(§12). For synchronous outputs, `expectEmissionSync` / `expectEmissionsSync` from core or `/angular`
|
|
160
|
+
check exact counts around `advance` and unsubscribe (§8). Async work needs the awaited helpers.
|
|
161
|
+
|
|
157
162
|
In an Angular app the spy almost always arrives through DI: `provideAutoSpy` in the providers,
|
|
158
163
|
`injectSpy` to read it. Write that shape first.
|
|
159
164
|
|
|
@@ -387,6 +392,7 @@ In [`agent-docs/observables.md`](./agent-docs/observables.md). Read it when asse
|
|
|
387
392
|
|
|
388
393
|
<!-- agents-outline: agent-docs/observables.md -->
|
|
389
394
|
|
|
395
|
+
- Synchronous outputs without subscriptions
|
|
390
396
|
- `createLog()` — the order between the spies
|
|
391
397
|
|
|
392
398
|
<!-- /agents-outline -->
|
|
@@ -448,6 +454,9 @@ In [`agent-docs/doubles.md`](./agent-docs/doubles.md). Read it when production c
|
|
|
448
454
|
- `localStorage` and `sessionStorage`
|
|
449
455
|
- Animation frames and element boxes
|
|
450
456
|
- An element for `ElementRef` — `createElementStub`
|
|
457
|
+
- `mockElementRefProp` — an element for a signal query
|
|
458
|
+
- Events for direct handler calls
|
|
459
|
+
- Text paste and drop events
|
|
451
460
|
- The members the DOM environment leaves out — `fillMissingDomApis`
|
|
452
461
|
- A module mock that did nothing
|
|
453
462
|
|
|
@@ -527,6 +536,9 @@ file, and `globals: true`.
|
|
|
527
536
|
|
|
528
537
|
In [`agent-docs/adapters.md`](./agent-docs/adapters.md). Read it for NestJS, Vue, React, Svelte, `bun test`, `node:test`, Rstest and the console entry.
|
|
529
538
|
|
|
539
|
+
Nest HTTP tests: `createHttpExecutionContext` supplies the context; `invokeNestParamDecorator`
|
|
540
|
+
calls a custom parameter factory by index with its recorded data. Both come from `/nestjs` (§15).
|
|
541
|
+
|
|
530
542
|
<!-- agents-outline: agent-docs/adapters.md -->
|
|
531
543
|
|
|
532
544
|
- `trackNodeMocks` for `node:test` memory
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,44 @@ The latest released version here must always match the one published on
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [5.66.0] - 2026-10-28
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `/nestjs`: `createHttpExecutionContext` supplies an HTTP context for guards, interceptors,
|
|
18
|
+
exception filters and parameter decorators. Request, response and argument accessors share the
|
|
19
|
+
same values; missing handler/class metadata and non-HTTP transports produce explicit errors.
|
|
20
|
+
- `/nestjs`: `invokeNestParamDecorator` runs a custom parameter decorator's recorded factory by
|
|
21
|
+
parameter index and forwards its stored data. It refuses missing or ambiguous factories and
|
|
22
|
+
parameter pipes or schemas that need Nest's request pipeline.
|
|
23
|
+
- **Bundle size:** `/nestjs` grows from 20.06 kB to 20.85 kB min+gzip (+0.79 kB, +3.9%) for
|
|
24
|
+
the HTTP context and parameter metadata helpers, without importing NestJS or Vitest. The root
|
|
25
|
+
entry does not re-export these helpers.
|
|
26
|
+
|
|
27
|
+
## [5.65.0] - 2026-10-26
|
|
28
|
+
|
|
29
|
+
## [5.64.0] - 2026-10-23
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `createElementStub({ elementClass: HTMLInputElement })` in `/dom-stubs` infers the element type
|
|
34
|
+
and supports `instanceof` checks without creating a DOM element. Missing members of the selected
|
|
35
|
+
class keep the stub's named error; supply their implementation in `overrides`.
|
|
36
|
+
- `/dom-stubs`: `createDomEvent` supplies readonly targets for direct handler calls;
|
|
37
|
+
`createInputEvent` supplies a typed input target and value; `createPasteEvent` and `createDropEvent`
|
|
38
|
+
supply text transfers and native cancellation without browser transfer constructors.
|
|
39
|
+
- `/angular/doubles`: `mockElementRefProp(component, 'trigger')` installs an inferred element
|
|
40
|
+
stub on an `ElementRef` signal query and returns the element spies, reference and writable query.
|
|
41
|
+
These DOM/query helpers add code only to their narrow entries.
|
|
42
|
+
- The root entry and `/angular`: `expectEmissionSync` and `expectEmissionsSync` replace manual
|
|
43
|
+
subscriptions and arrays with exact synchronous emission counts. They keep listening during
|
|
44
|
+
`advance` to catch extra emissions and tear down before returning or throwing.
|
|
45
|
+
- **Bundle size:** `/dom-stubs` grows by 491 B min+gzip over 5.63.0 for element prototypes and
|
|
46
|
+
handler events; `/angular/doubles` grows by 3.77 kB for the typed query/stub composition and its
|
|
47
|
+
existing signal-patching machinery. Shared bundle modules also change the import graph of
|
|
48
|
+
`/angular/diagnostics`, `/angular/matchers` and `/angular-http`; the recorded graph and sizes
|
|
49
|
+
include this reuse.
|
|
50
|
+
|
|
13
51
|
## [5.63.0] - 2026-10-21
|
|
14
52
|
|
|
15
53
|
### Added
|
|
@@ -6864,7 +6902,10 @@ moved under 1 %: `/angular` +192 B (+1.0 %) for the override queue and the HTTP
|
|
|
6864
6902
|
This copy ships with the package and carries 5.x only. Releases before 5.0.0 are in the
|
|
6865
6903
|
[full changelog](https://github.com/ASDAlexey/vitest-auto-spy/blob/master/CHANGELOG.md).
|
|
6866
6904
|
|
|
6867
|
-
[Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.
|
|
6905
|
+
[Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.66.0...HEAD
|
|
6906
|
+
[5.66.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.65.0...v5.66.0
|
|
6907
|
+
[5.65.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.64.0...v5.65.0
|
|
6908
|
+
[5.64.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.63.0...v5.64.0
|
|
6868
6909
|
[5.63.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.62.0...v5.63.0
|
|
6869
6910
|
[5.62.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.61.0...v5.62.0
|
|
6870
6911
|
[5.61.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.60.0...v5.61.0
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ replacement for [`jest-auto-spies`](https://www.npmjs.com/package/jest-auto-spie
|
|
|
15
15
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
16
16
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
17
17
|
[](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
|
|
18
|
-
[](#install)
|
|
19
19
|
[](https://www.npmjs.com/package/vitest-auto-spy)
|
|
20
20
|
[](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
|
|
21
21
|
[](./LICENSE)
|
|
@@ -46,6 +46,9 @@ replacement for [`jest-auto-spies`](https://www.npmjs.com/package/jest-auto-spie
|
|
|
46
46
|
- **Answers per argument list**: `calledWith(1).mockReturnValue(...)`.
|
|
47
47
|
- **A spy from a type alone**: `createAutoMock<T>()` and `mockDeep<T>()`.
|
|
48
48
|
- **Angular `TestBed` in one line**: `provideAutoSpy(ApiService)`, then `injectSpy(ApiService)`.
|
|
49
|
+
- **Short handler tests**: typed input/paste/drop events, element query stubs, and exact synchronous output assertions.
|
|
50
|
+
- **Nest HTTP tests without starting the app**: `createHttpExecutionContext` supplies the context;
|
|
51
|
+
`invokeNestParamDecorator` runs a custom parameter decorator with its recorded data.
|
|
49
52
|
- **One API on every runner**: Vitest, Bun, `node:test` and Rstest; helpers for Angular, NestJS,
|
|
50
53
|
React, Vue / Pinia and Svelte.
|
|
51
54
|
- **Checks that make silent tests fail**: strict mode, Observable assertions, cleanup between tests,
|
|
@@ -2932,6 +2935,25 @@ Pass `{ expose: [Dependency] }` to keep a collaborator real, and `providers` to
|
|
|
2932
2935
|
`vitest`. On `node --test`, Bun or Rstest, import the runtime entry first. `createNestUnit` is also
|
|
2933
2936
|
exported from `vitest-auto-spy/node` and `vitest-auto-spy/bun`.
|
|
2934
2937
|
|
|
2938
|
+
Test a custom parameter decorator without starting Nest or reading its metadata by hand.
|
|
2939
|
+
Here `ProfileController.profile` has `@CurrentUser('id')` on its first parameter:
|
|
2940
|
+
|
|
2941
|
+
```ts
|
|
2942
|
+
import 'reflect-metadata';
|
|
2943
|
+
|
|
2944
|
+
import { expect } from 'vitest';
|
|
2945
|
+
import { createHttpExecutionContext, invokeNestParamDecorator } from 'vitest-auto-spy/nestjs';
|
|
2946
|
+
|
|
2947
|
+
import { ProfileController } from './profile.controller';
|
|
2948
|
+
|
|
2949
|
+
const context = createHttpExecutionContext({ request: { user: { id: 'user-7' } } });
|
|
2950
|
+
expect(invokeNestParamDecorator(ProfileController, 'profile', 0, context)).toBe('user-7');
|
|
2951
|
+
```
|
|
2952
|
+
|
|
2953
|
+
The parameter index starts at zero. The helper runs the recorded factory with its decorator data;
|
|
2954
|
+
pipes and schemas require Nest's validation pipeline and are refused.
|
|
2955
|
+
Use the same context helper for guards, interceptors and exception filters.
|
|
2956
|
+
|
|
2935
2957
|
Full page: [NestJS](https://asdalexey.github.io/vitest-auto-spy/adapters/nestjs).
|
|
2936
2958
|
|
|
2937
2959
|
#### `httpResource()` and `HttpClient` — `vitest-auto-spy/angular-http`
|
|
@@ -3082,8 +3104,29 @@ two thousand tests add about 0.02 s to the run. Numbers:
|
|
|
3082
3104
|
Besides the spy factories, the package has small standalone helpers. Each does one job; pick up
|
|
3083
3105
|
only the ones you need. Every helper, with its signature: [API](https://asdalexey.github.io/vitest-auto-spy/api).
|
|
3084
3106
|
|
|
3107
|
+
For direct handler calls, replace local event factories and query setup with these helpers:
|
|
3108
|
+
|
|
3109
|
+
```ts
|
|
3110
|
+
import { mockElementRefProp } from 'vitest-auto-spy/angular/doubles';
|
|
3111
|
+
import { createInputEvent } from 'vitest-auto-spy/dom-stubs';
|
|
3112
|
+
|
|
3113
|
+
const trigger = mockElementRefProp(component, 'triggerButton');
|
|
3114
|
+
component.store.open(0, 0);
|
|
3115
|
+
component.onMinutesChange(createInputEvent('15'));
|
|
3116
|
+
component.confirm();
|
|
3117
|
+
expect(trigger.focus).toHaveBeenCalledOnce();
|
|
3118
|
+
```
|
|
3119
|
+
|
|
3120
|
+
`mockElementRefProp` infers the element type from the signal query. Set `elementClass` for runtime
|
|
3121
|
+
`instanceof` checks. Patch before a live consumer reads the query; `setupAutoSpy()` restores replaced
|
|
3122
|
+
properties. Events with supplied targets are for direct handler calls. Paste/drop support text reads
|
|
3123
|
+
only. Full contracts: [element and event stubs](https://asdalexey.github.io/vitest-auto-spy/utilities/element-stub).
|
|
3124
|
+
|
|
3085
3125
|
| Utility | Entry point | What it's for |
|
|
3086
3126
|
| ----------------------------------------------------------------------------------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3127
|
+
| `createDomEvent(type, init?)` / `createInputEvent(value, init?)` | `/dom-stubs` | Native events for direct handlers, with readonly targets or an input value |
|
|
3128
|
+
| `createPasteEvent(text, init?)` / `createDropEvent(text, init?)` | `/dom-stubs` | Text transfers with native `defaultPrevented`; `null` represents absent transfer data |
|
|
3129
|
+
| `mockElementRefProp(component, key, opts?)` | `/angular/doubles` | Inferred element spies, `ref` and writable `query`, installed together |
|
|
3087
3130
|
| `injectSpy(token)` / `injectSpy(moduleRef, token)` | `/angular`, `/nestjs` | Pull a provided spy out of the DI container, already typed as `Spy<T>` — no casting |
|
|
3088
3131
|
| `provideAutoSpy(Class, config?)` | `/angular`, `/nestjs`, `/vue` | One-liner `{ provide, useValue }` (or Vue `global.provide`) that builds the spy for you |
|
|
3089
3132
|
| `createFunctionSpy(name)` | core | A single standalone function spy with the full helper set (`calledWith`, `resolveWith`, `nextWith`, …) — no class needed |
|
|
@@ -3112,7 +3155,7 @@ only the ones you need. Every helper, with its signature: [API](https://asdalexe
|
|
|
3112
3155
|
| `stubWorker(opts?)` | `/dom-stubs` | A `Worker` whose script is the spec — listeners stack, replies arrive on a microtask, `emit()` / `fail()` from the worker's side ([details](#how-to-mock-a-web-worker)) |
|
|
3113
3156
|
| `stubAnimationFrame(opts?)` | `/dom-stubs` | `requestAnimationFrame` / `cancelAnimationFrame` run on the spot or on `flush(timestamp?)`; a frame requested inside a frame waits for the next flush; `onError` intercepts a throwing callback; `lastHandle` is the latest handle issued (they start above 2^30) |
|
|
3114
3157
|
| `stubElementRect(el, rect?)` | `/dom-stubs` | `getBoundingClientRect()` answering a real `DOMRect` built from a partial `DOMRectInit`; returns the undo, plus the installed spy as `.getBoundingClientRect` |
|
|
3115
|
-
| `createElementStub(opts?)` | `/dom-stubs` | A typed
|
|
3158
|
+
| `createElementStub(opts?)` | `/dom-stubs` | A typed element for `ElementRef`; `elementClass` enables `instanceof` checks and infers the type. Spies keep state; unconfigured DOM members require `overrides` |
|
|
3116
3159
|
| `fillMissingDomApis(opts?)` | `/dom-stubs` | For the setup file: `PointerEvent`, a no-op `ResizeObserver`, no-op scrolling and `document.doctype`, only where missing; `{ cheapComputedStyle: true }` |
|
|
3117
3160
|
| `flushEventLoop(turns?)` / `settleDynamicImport(load, turns?)` | core | Real event-loop turns while the timers are faked — for a dynamic `import()` or native `async` in a dependency |
|
|
3118
3161
|
| `flushEventLoopUntil(isDone, opts?)` | core | Real turns until a condition holds — a `resource()` leaving `loading` — with a budget instead of a hang |
|
|
@@ -3332,6 +3375,25 @@ Full page: [explainSpy](https://asdalexey.github.io/vitest-auto-spy/utilities/ex
|
|
|
3332
3375
|
|
|
3333
3376
|
## Observable assertions
|
|
3334
3377
|
|
|
3378
|
+
For a synchronous handler, check the exact output count without managing a subscription:
|
|
3379
|
+
|
|
3380
|
+
```ts
|
|
3381
|
+
import { expectEmissionSync, expectEmissionsSync } from 'vitest-auto-spy';
|
|
3382
|
+
|
|
3383
|
+
expect(expectEmissionSync(component.page, { advance: () => component.next() })).toBe(3);
|
|
3384
|
+
expect(
|
|
3385
|
+
expectEmissionsSync(component.page, 2, {
|
|
3386
|
+
advance: () => {
|
|
3387
|
+
component.next();
|
|
3388
|
+
component.next();
|
|
3389
|
+
},
|
|
3390
|
+
}),
|
|
3391
|
+
).toEqual([4, 5]);
|
|
3392
|
+
```
|
|
3393
|
+
|
|
3394
|
+
Both helpers unsubscribe before returning and fail on missing or extra synchronous values.
|
|
3395
|
+
For timers, promises or other asynchronous work, use the awaited helpers below.
|
|
3396
|
+
|
|
3335
3397
|
These helpers make the assertion an `await`, so a stream that never emits fails the test. An
|
|
3336
3398
|
`expect` inside `subscribe()` never runs when the stream stays silent, and the test passes.
|
|
3337
3399
|
|
|
@@ -3766,7 +3828,7 @@ Every export, one line each. Signatures, options and types: [API](https://asdale
|
|
|
3766
3828
|
| `stubWorker(opts?)` _(`/dom-stubs`)_ | A `Worker` a spec drives from the worker's side: `respond` per message, `messages` / `terminated` to assert, `emit()` / `fail()`; returns `WorkerStub<TIn, TOut>` |
|
|
3767
3829
|
| `stubAnimationFrame(opts?)` _(`/dom-stubs`)_ | Frames on the spec's schedule: `'immediate'` or `'queued'` + `flush()`, `pending`, `lastHandle`, both globals as spies; returns `AnimationFrameStub` |
|
|
3768
3830
|
| `stubElementRect(el, rect?)` _(`/dom-stubs`)_ | A box for `getBoundingClientRect()` — missing fields `0`, edges derived; returns `ElementRectRestore` (callable undo plus `.getBoundingClientRect`) |
|
|
3769
|
-
| `createElementStub(opts?)` / `fillMissingDomApis(opts?)` _(`/dom-stubs`)_ | A typed stub
|
|
3831
|
+
| `createElementStub(opts?)` / `fillMissingDomApis(opts?)` _(`/dom-stubs`)_ | A typed stub for `ElementRef`, with optional `elementClass` for `instanceof`; missing DOM APIs filled once in the setup file |
|
|
3770
3832
|
| `createComponentStub(Class, overrides?, opts?)` _(`/angular`)_ | A standalone stand-in for a child component, directive or pipe, built from its compiled definition so the selector cannot drift |
|
|
3771
3833
|
| `flushEventLoop(turns?)` / `settleDynamicImport(load, turns?)` | Real event-loop turns under fake timers; wait for a dynamic `import()` |
|
|
3772
3834
|
| `autoMocked<T>(overrides?, config?)` | `createAutoMock` typed as `T & Spy<T>`; `AutoMocked<T>` names it for a `let` |
|
package/agent-docs/adapters.md
CHANGED
|
@@ -28,6 +28,15 @@ mount(Greeting, { global: { provide } });
|
|
|
28
28
|
import { createSpyFromClass } from 'vitest-auto-spy/react';
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
**Nest HTTP tests.** `createHttpExecutionContext({ request, response, handler, class: Controller })`
|
|
32
|
+
from `/nestjs` supplies an HTTP `ExecutionContext` / `ArgumentsHost` without starting Nest. Omit
|
|
33
|
+
the options you do not need; `getClass()` / `getHandler()` throw if their option is missing.
|
|
34
|
+
`invokeNestParamDecorator(Controller, 'method', parameterIndex, context)` runs a custom parameter
|
|
35
|
+
factory by zero-based index and forwards its recorded `data`. Import `reflect-metadata` before
|
|
36
|
+
the controller. The result is `unknown`; async factories return their promise unchanged. Native
|
|
37
|
+
parameter decorators, pipes and schemas require Nest's pipeline and are refused. Examples:
|
|
38
|
+
[Nest HTTP helpers](https://asdalexey.github.io/vitest-auto-spy/adapters/nestjs#createhttpexecutioncontext).
|
|
39
|
+
|
|
31
40
|
**Types without Vitest.** `/node`, `/bun`, `/bun-angular`, `/rstest`, `/jasmine-compat`,
|
|
32
41
|
`/angular-router`, `/console`, `/nestjs`, `/observer-spy` and `/rxjs` type-check with no Vitest
|
|
33
42
|
installed and `skipLibCheck: false`. `Spy<T>` is one type on every entry: once the program imports an
|
package/agent-docs/doubles.md
CHANGED
|
@@ -189,9 +189,109 @@ expect(host.classes()).toEqual(['card', 'highlighted']); // attributes(), styles
|
|
|
189
189
|
host.emit('mouseleave'); // fires the listeners; records nothing on dispatchEvent
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
+
For `instanceof` checks, pass `elementClass`:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const input = createElementStub({ elementClass: HTMLInputElement, tagName: 'input', overrides: { value: '15' } });
|
|
196
|
+
|
|
197
|
+
expect(input.element).toBeInstanceOf(HTMLInputElement);
|
|
198
|
+
expect(input.element.value).toBe('15'); // inferred as HTMLInputElement
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`elementClass?: { readonly prototype: T }` defaults to none and infers `T` from the class.
|
|
202
|
+
It uses the prototype without calling the constructor. `tagName` remains independent and defaults to `'div'`.
|
|
203
|
+
The supplied class adds no implementations. Configure missing properties and methods, such as `value` or `select`, in `overrides`.
|
|
204
|
+
Existing stub methods, such as `focus`, remain usable. Reading an unconfigured class member throws with its name.
|
|
205
|
+
|
|
206
|
+
### `mockElementRefProp` — an element for a signal query
|
|
207
|
+
|
|
208
|
+
Replace an optional or required `ElementRef` signal query and get the element spies in one call.
|
|
209
|
+
For example, `component.dateTrigger` has type `Signal<ElementRef<HTMLButtonElement> | undefined>`.
|
|
210
|
+
Its `focusTrigger()` method calls `focus()` on the queried element.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { mockElementRefProp } from 'vitest-auto-spy/angular/doubles';
|
|
214
|
+
|
|
215
|
+
const trigger = mockElementRefProp(component, 'dateTrigger', {
|
|
216
|
+
elementClass: HTMLButtonElement,
|
|
217
|
+
tagName: 'button',
|
|
218
|
+
});
|
|
219
|
+
component.focusTrigger();
|
|
220
|
+
expect(trigger.focus).toHaveBeenCalledExactlyOnceWith();
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
This replaces a local element factory followed by `mockSignalProp(component, 'dateTrigger', new ElementRef(element))`.
|
|
224
|
+
The query determines the element type. Options are those of `createElementStub` and cannot change that type.
|
|
225
|
+
The handle also returns `ref` (the installed `ElementRef`) and `query` (a writable test signal).
|
|
226
|
+
Use `trigger.query.set(undefined)` to represent a missing optional query; required queries reject `undefined` in TypeScript.
|
|
227
|
+
Queries returning component or directive instances, and `viewChildren`, need `mockSignalProp` instead.
|
|
228
|
+
|
|
229
|
+
Patch before rendering a template, effect, or `computed` that consumes the original query.
|
|
230
|
+
Patching an already consumed query throws. This helper creates no rendered element and does not resolve Angular queries.
|
|
231
|
+
`setupAutoSpy()` restores the original query after each test. Without it, add cleanup:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { afterEach } from 'vitest';
|
|
235
|
+
import { restoreMockedProps } from 'vitest-auto-spy';
|
|
236
|
+
|
|
237
|
+
afterEach(() => restoreMockedProps());
|
|
238
|
+
```
|
|
239
|
+
|
|
192
240
|
Reading an `HTMLElement` member the stub does not implement throws with the member's name — pass it
|
|
193
|
-
in `overrides: { offsetWidth: 120, querySelector: vi.fn() }`.
|
|
194
|
-
|
|
241
|
+
in `overrides: { offsetWidth: 120, querySelector: vi.fn() }`. `createElementStub` itself patches nothing and needs no cleanup.
|
|
242
|
+
|
|
243
|
+
### Events for direct handler calls
|
|
244
|
+
|
|
245
|
+
Use `createDomEvent` to supply readonly targets without a cast or `Object.defineProperty` in each test.
|
|
246
|
+
Here, `component.onBlur()` reads `currentTarget` and removes the `active` class.
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
import { createDomEvent, createElementStub, createInputEvent } from 'vitest-auto-spy/dom-stubs';
|
|
250
|
+
|
|
251
|
+
const input = createElementStub({ tagName: 'input', classes: ['active'] });
|
|
252
|
+
component.onBlur(createDomEvent('blur', { currentTarget: input.element }));
|
|
253
|
+
expect(input.classes()).toEqual([]);
|
|
254
|
+
|
|
255
|
+
component.onInput(createInputEvent('15'));
|
|
256
|
+
expect(component.value()).toBe('15');
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`createDomEvent(type, init?)` returns a native `Event`. `bubbles` and `cancelable` default to `true`.
|
|
260
|
+
The optional `target` and `currentTarget` stay fixed. For propagation tests, omit them and dispatch on a real DOM element.
|
|
261
|
+
|
|
262
|
+
`createInputEvent(value, init?)` returns an `Event` of type `'input'` with an input stub as `target`.
|
|
263
|
+
It supports `instanceof HTMLInputElement` when that class exists. The supplied value wins over `init.element.overrides.value`.
|
|
264
|
+
Pass stub options through `element`, for example `{ element: { overrides: { disabled: true } } }`.
|
|
265
|
+
Pass other native event flags directly in `init`.
|
|
266
|
+
|
|
267
|
+
**Common mistake:** expecting `data`, `inputType`, or a browser input event constructor check to work.
|
|
268
|
+
This helper returns `Event`, not `InputEvent`. Use a native `InputEvent` when testing those browser features.
|
|
269
|
+
|
|
270
|
+
### Text paste and drop events
|
|
271
|
+
|
|
272
|
+
Replace local clipboard and drag event factories when a handler only reads plain text.
|
|
273
|
+
Here, `onPaste` and `onDrop` read the text and cancel the event.
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import { createDropEvent, createPasteEvent } from 'vitest-auto-spy/dom-stubs';
|
|
277
|
+
|
|
278
|
+
const paste = createPasteEvent('15');
|
|
279
|
+
component.onPaste(paste);
|
|
280
|
+
expect(paste.defaultPrevented).toBe(true);
|
|
281
|
+
|
|
282
|
+
component.onDrop(createDropEvent('20'));
|
|
283
|
+
expect(component.value()).toBe('20');
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Both accept `(text: string | null, init?: EventInit)` and default to bubbling, cancelable events.
|
|
287
|
+
`null` gives `clipboardData: null` or `dataTransfer: null`, so you can test absent data.
|
|
288
|
+
`getData('text')` and `getData('text/plain')` return the supplied text, ignoring case; other formats return `''`.
|
|
289
|
+
`types` is a readonly `['text/plain']` array. These events can also be dispatched on DOM elements.
|
|
290
|
+
|
|
291
|
+
The transfer supports only `getData()` and `types`. Reading `files`, `items`, `setData`, or any other transfer member throws.
|
|
292
|
+
These are native `Event` instances with the text transfer property added.
|
|
293
|
+
They need no `ClipboardEvent`, `DragEvent`, or `DataTransfer` constructor and do not pass those constructor checks.
|
|
294
|
+
For files, coordinates, transfer writes, or browser drag behavior, supply your own event.
|
|
195
295
|
|
|
196
296
|
### The members the DOM environment leaves out — `fillMissingDomApis`
|
|
197
297
|
|
|
@@ -35,6 +35,43 @@ store.dispatch(noop());
|
|
|
35
35
|
expectNoEmissionSync(store.saved$, { skip: 1 }); // skip the replayed value
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
### Synchronous outputs without subscriptions
|
|
39
|
+
|
|
40
|
+
Use `expectEmissionSync` for exactly one synchronous emission, or `expectEmissionsSync` for an exact count.
|
|
41
|
+
They return values immediately, so you need no listener spy, collection array, manual unsubscribe, or `await`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { expectEmissionSync, expectEmissionsSync } from 'vitest-auto-spy';
|
|
45
|
+
|
|
46
|
+
expect(
|
|
47
|
+
expectEmissionSync(component.closed, {
|
|
48
|
+
advance: () => component.close(),
|
|
49
|
+
}),
|
|
50
|
+
).toBeUndefined();
|
|
51
|
+
|
|
52
|
+
expect(
|
|
53
|
+
expectEmissionsSync(component.selected, 2, {
|
|
54
|
+
advance: () => {
|
|
55
|
+
component.select(15);
|
|
56
|
+
component.select(20);
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
).toEqual([15, 20]);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The helper subscribes first, runs `advance` once, then unsubscribes before returning or throwing.
|
|
63
|
+
Values emitted during subscription count too. Use `{ skip: 1 }` to ignore a replayed initial value.
|
|
64
|
+
`until` filters accepted values; `label` names the source in failures. These are the only other options: there is no `timeout`.
|
|
65
|
+
Both helpers also come from `vitest-auto-spy/angular` and accept Angular outputs or observable-like sources.
|
|
66
|
+
|
|
67
|
+
A missing or extra accepted value fails immediately. Unlike `expectEmission`, which stops at the first value,
|
|
68
|
+
`expectEmissionSync` checks everything emitted during subscription and the synchronous action.
|
|
69
|
+
`expectEmissionsSync` requires a positive integer count; use `expectNoEmissionSync` for zero.
|
|
70
|
+
Source errors and thrown callbacks fail the assertion and close the subscription.
|
|
71
|
+
|
|
72
|
+
**Common mistake:** using this for a timer or microtask emission. The subscription is already closed when that value arrives.
|
|
73
|
+
Use `expectEmission` or `expectEmissions` with `await` for asynchronous work.
|
|
74
|
+
|
|
38
75
|
A failure that counts emissions also shows the first five values, then `… N more`:
|
|
39
76
|
`the stream completed after 7 emissions (1, 2, 3, 4, 5, … 2 more), expected 9`,
|
|
40
77
|
`did not complete within 20 ms (3 emissions received: 1, 2, 3)`.
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { pendingRequestsReport,
|
|
2
|
-
export { disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, reportSpecTiming } from './chunk-
|
|
3
|
-
import {
|
|
1
|
+
import { pendingRequestsReport, instrumentTestBed, onTestingModuleConfigured, onComponentCreated, HTTP_TESTING_BRAND, beforeTestBedReset, verifyOnTeardown } from './chunk-C7K75NLS.js';
|
|
2
|
+
export { disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, reportSpecTiming } from './chunk-C7K75NLS.js';
|
|
3
|
+
import { assertAngularInternals } from './chunk-OIHOH2RY.js';
|
|
4
|
+
import { failOnUnspiedProvider, onTestBedFileEnd, isLazyDoubleFactory } from './chunk-OXE6FCQX.js';
|
|
4
5
|
import './chunk-T5MQSNRX.js';
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
6
|
+
import './chunk-XZS56XV5.js';
|
|
7
|
+
import './chunk-5GKIQX65.js';
|
|
8
|
+
import './chunk-XLKBJSYQ.js';
|
|
9
|
+
import './chunk-QATP6Q3G.js';
|
|
9
10
|
import './chunk-PC3FAZT3.js';
|
|
10
|
-
import './chunk-
|
|
11
|
-
import { isAutoSpyLike } from './chunk-
|
|
11
|
+
import './chunk-HIGHZ4BW.js';
|
|
12
|
+
import { isAutoSpyLike } from './chunk-2CWSOIBW.js';
|
|
12
13
|
import { count, sourceClassName, taskName } from './chunk-DYAS4OK4.js';
|
|
13
|
-
import { angularPendingRequests, angularShadowedProviders, angularDeadSchemas, angularNgModuleScopesAuto } from './chunk-
|
|
14
|
+
import { angularPendingRequests, angularShadowedProviders, angularDeadSchemas, angularNgModuleScopesAuto } from './chunk-7WU53KRS.js';
|
|
14
15
|
import { withDocs } from './chunk-ENCEEH23.js';
|
|
15
16
|
import { getTestBed } from '@angular/core/testing';
|
|
16
17
|
import { beforeEach, afterEach } from 'vitest';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import './vitest-mock-types-B17-xaWt.js';
|
|
2
|
-
import { InjectionToken, AbstractType, Injector, ValueProvider, FactoryProvider, ProviderToken, ChangeDetectorRef } from '@angular/core';
|
|
2
|
+
import { InjectionToken, AbstractType, Injector, ValueProvider, FactoryProvider, ProviderToken, ChangeDetectorRef, ElementRef, WritableSignal, Signal } from '@angular/core';
|
|
3
3
|
import { h as AddSpyMethodsByReturnTypes, S as Spy, F as Func, p as FunctionSpy } from './types-BdYUK_Zv.js';
|
|
4
4
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
5
|
+
import { E as ElementStub, a as ElementStubOptions } from './element-stub-D3kchFNq.js';
|
|
5
6
|
import 'vitest';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -501,4 +502,31 @@ type ValidSelection<T, Selection> = Selection extends readonly unknown[] ? reado
|
|
|
501
502
|
*/
|
|
502
503
|
declare function createWindowSpies<const Selection extends WindowSpySelection>(selection: Selection & ValidSelection<Window, Selection>): WindowSpies<Window, Selection>;
|
|
503
504
|
|
|
504
|
-
|
|
505
|
+
type QueryValue<T> = T extends Signal<infer V> ? V : never;
|
|
506
|
+
type QueryElement<T> = [Exclude<QueryValue<T>, undefined>] extends [never] ? never : Exclude<QueryValue<T>, undefined> extends ElementRef<infer E extends HTMLElement> ? E : never;
|
|
507
|
+
type ElementQueryKey<T> = {
|
|
508
|
+
[K in keyof T]-?: [QueryElement<T[K]>] extends [never] ? never : K;
|
|
509
|
+
}[keyof T];
|
|
510
|
+
/** Element spies together with the reference installed on the query and its writable test handle. */
|
|
511
|
+
type ElementRefPropStub<T extends HTMLElement, V = ElementRef<T> | undefined> = ElementStub<T> & {
|
|
512
|
+
readonly ref: ElementRef<T>;
|
|
513
|
+
readonly query: WritableSignal<V>;
|
|
514
|
+
};
|
|
515
|
+
/**
|
|
516
|
+
* Replace an ElementRef-valued signal query with a DOM stub and return its spies.
|
|
517
|
+
*
|
|
518
|
+
* ```ts
|
|
519
|
+
* const trigger = mockElementRefProp(component, 'dateTrigger');
|
|
520
|
+
* component.close();
|
|
521
|
+
* expect(trigger.focus).toHaveBeenCalledExactlyOnceWith();
|
|
522
|
+
* ```
|
|
523
|
+
*
|
|
524
|
+
* The queried element type is inferred from the property. Options are those of `createElementStub`;
|
|
525
|
+
* they do not infer a different element type. `ref` is the installed `ElementRef`; `query` can drive
|
|
526
|
+
* a later reference, or `undefined` for an optional query. Patch before rendering a live consumer.
|
|
527
|
+
* Like `mockSignalProp`, replacement patches are undone by `restoreMockedProps()` / `setupAutoSpy()`.
|
|
528
|
+
* This does not render a DOM element or cause Angular to resolve a view query.
|
|
529
|
+
*/
|
|
530
|
+
declare function mockElementRefProp<T, K extends ElementQueryKey<T> & keyof T>(object: T, property: K, options?: ElementStubOptions<NoInfer<QueryElement<T[K]>>>): ElementRefPropStub<QueryElement<T[K]>, QueryValue<T[K]>>;
|
|
531
|
+
|
|
532
|
+
export { type AttachedComponent, type DialogComponent, type DialogDataOf, type DialogRefLike, type DialogResult, type ElementRefPropStub, type MatDialogRefDouble, type MatDialogRefInit, type OverlayDouble, type OverlayDoubleInit, type OverlayLike, type OverlayRefDouble, type OverlayRefStub, type PlatformFlagTokens, type PlatformName, type PlatformOverrides, type PositionCall, type WindowSpies, type WindowSpySelection, createChangeDetectorRefDouble, createDocumentDouble, createDomSanitizerDouble, createMatDialogRef, createOverlayDouble, createWindowDouble, createWindowSpies, injectMatDialogRef, injectOverlayDouble, mockElementRefProp, provideChangeDetectorRefDouble, provideDocumentDouble, provideDomSanitizerDouble, provideMatDialogData, provideMatDialogRef, provideOverlayDouble, providePlatform, provideWindowDouble };
|