vitest-auto-spy 5.36.0 → 5.38.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/CHANGELOG.md +112 -1
- package/README.md +36 -29
- package/agent-docs/angular.md +31 -1
- package/agent-docs/checklist.md +3 -1
- package/agent-docs/errors.md +3 -3
- package/agent-docs/eslint.md +1 -1
- package/agent-docs/setup.md +3 -1
- package/dist/angular-diagnostics.js +3 -3
- package/dist/angular-doubles.js +3 -3
- package/dist/angular-matchers.js +8 -5
- package/dist/angular-router.js +1 -1
- package/dist/angular.d.ts +1 -1
- package/dist/bun-angular.d.ts +1 -1
- package/dist/bun-angular.js +6 -6
- package/dist/bun.js +3 -3
- package/dist/{chunk-VWNFNWTG.js → chunk-2KBRDNIB.js} +1 -1
- package/dist/{chunk-464WKNEQ.js → chunk-2TZCJ3MM.js} +1 -1
- package/dist/{chunk-GAE5EGO7.js → chunk-5TYNQH5Q.js} +6 -3
- package/dist/{chunk-F4URI3UE.js → chunk-6KP5QMMV.js} +1 -1
- package/dist/{chunk-GTDJ22IQ.js → chunk-B6C3K27C.js} +1 -1
- package/dist/{chunk-LA2CMIPM.js → chunk-RYFF55PV.js} +5 -1
- package/dist/{chunk-YWSOJH5C.js → chunk-YNXQ2WFH.js} +1 -1
- package/dist/cli.js +81 -11
- package/dist/console.js +3 -3
- package/dist/eslint-plugin.d.cts +1 -0
- package/dist/eslint-plugin.d.ts +15 -3
- package/dist/index.js +9 -2
- package/dist/jasmine.js +4 -4
- package/dist/nestjs.js +6 -6
- package/dist/node.cjs +9 -2
- package/dist/node.js +9 -2
- package/dist/rstest.js +4 -4
- package/dist/setup.js +18 -3
- package/dist/{track-signal-runs-BuJk_Yi8.d.ts → track-signal-runs-C7SrW3Ub.d.ts} +3 -1
- package/package.json +1 -1
- package/skills/vitest-auto-spy/SKILL.md +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,115 @@ The latest released version here must always match the one published on
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [5.38.0] - 2026-09-26
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`doctor` notes `mock-reset-config-unread`.** A `no-redundant-mock-reset` entry whose options name
|
|
18
|
+
a `configFile` and no flag beside it, where that file's default export is a call to anything but
|
|
19
|
+
`defineConfig` / `defineProject` — a project factory such as `createProjectConfig({ alias })`, or
|
|
20
|
+
`mergeConfig(base, …)`. The rule reads the file as text, so it never sees the flags that call sets:
|
|
21
|
+
up to Vitest 4 it stays silent on every redundant reset, from Vitest 5 it assumes `clearMocks` on
|
|
22
|
+
even where the factory turns it off, and nothing says so. The note names the callee and the fix —
|
|
23
|
+
write the flags beside `configFile`, which win over the file. Only a literal `configFile` is read,
|
|
24
|
+
resolved against the repository root. The rule itself still reports nothing about its config.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **The block `init` writes into `AGENTS.md` / `CLAUDE.md` / `GEMINI.md` follows the 5.35.0 split.**
|
|
29
|
+
It called the package's `AGENTS.md` "the authoritative reference"; since 5.35.0 that file is a short
|
|
30
|
+
map and the reference is `agent-docs/*.md`. The block now says what the skill stub already did: read
|
|
31
|
+
the map whole, then only the topic files it names, and look a failure up with
|
|
32
|
+
`grep -n -F '<error text>' node_modules/vitest-auto-spy/agent-docs/errors.md`. The rxjs line names
|
|
33
|
+
the setup file "or a module / `.d.ts` it loads", since under `@angular/build:unit-test` 22.2 the
|
|
34
|
+
import may sit in a shared module the setup file reaches and the types in a `.d.ts`. Both land in
|
|
35
|
+
one change, so the block's `sha=` moves once: **`init --check` reports the root stubs as changed
|
|
36
|
+
until `npx vitest-auto-spy init` runs again**, and that run rewrites only the block. The pointer in
|
|
37
|
+
the glob-scoped rule files and the skill stub are unchanged. The hand-written snippets on the agents
|
|
38
|
+
page and in the README say the same as the block.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **`createSpyFromInstance` recognises happy-dom's `MediaQueryList` as a live DOM/BOM object.** What
|
|
43
|
+
`matchMedia()` returns belongs to a class no global names, built on happy-dom's private
|
|
44
|
+
`EventTarget`, so discovery ran unrestricted over it without the warning that asks for
|
|
45
|
+
`onlyMethodsToSpyOn`. An event target built on the `EventTarget` the engine built `Node` on now
|
|
46
|
+
counts too; a user class over the global `EventTarget`, or over a polyfill's, still does not.
|
|
47
|
+
|
|
48
|
+
### Docs
|
|
49
|
+
|
|
50
|
+
- **`no-redundant-mock-reset`: only the runner's flags count.** `AGENTS.md` §16, the README and the
|
|
51
|
+
skill now say what the rule reference already did: `setupAutoSpy({ restoreMocks: true })` restores
|
|
52
|
+
in an `afterEach`, after the test, and is not the runner's `restoreMocks`, so it is never a reason
|
|
53
|
+
to pass the rule `{ restoreMocks: true }`. The README also names the factory / `mergeConfig` case,
|
|
54
|
+
and the Russian rule page gains both paragraphs.
|
|
55
|
+
- **`TestBed.createDirective` on the Angular page.** The zoneless-waiting, `hostElement` and
|
|
56
|
+
directive-host sections say that `stable`, `hostElement` and `toHaveDirectiveApplied` take Angular
|
|
57
|
+
22.2's `DirectiveFixture`, and the `toHaveDirectiveApplied` section that the fixture's root element
|
|
58
|
+
is searched too, so a `hostDirectives` entry of the component under test counts. `AGENTS.md` §13
|
|
59
|
+
already said so; the site did not.
|
|
60
|
+
- **What `vitest-auto-spy/angular` re-exports from the core.** The Angular page, `AGENTS.md` §13, the
|
|
61
|
+
skill and the README say it outright: the `Spy<T>` type (5.35.0), the `mock*Prop` helpers with
|
|
62
|
+
`restoreMockedProps` / `countMockedProps`, the `expectEmission` family and `registerAutoSpyDefaults`
|
|
63
|
+
/ `clearAutoSpyDefaults` — and nothing else. `createSpyFromClass`, `createMock`, `createAutoMock`,
|
|
64
|
+
`spyOnVoidMethod`, `spyOnOwnMethod`, `stubConstructor`, `asInstance` and the rest stay on
|
|
65
|
+
`vitest-auto-spy`, so a spec that needs one keeps a second import line rather than folding it into
|
|
66
|
+
the `/angular` one. The `/angular-http` pages no longer say every other subpath re-exports the core.
|
|
67
|
+
- **`toHaveDirectiveApplied` as the guard for a `hostDirectives` attribute.** `AGENTS.md` §13 and the
|
|
68
|
+
Angular page (English and Russian) show the matcher asserting the host directive itself, with no
|
|
69
|
+
selector, next to the attribute check that stays green when the entry is dropped and the attribute
|
|
70
|
+
is also written statically — and that it exists only after `registerDirectiveMatchers()` from
|
|
71
|
+
`vitest-auto-spy/angular/matchers` runs in the setup file.
|
|
72
|
+
- **The `createSpyFromInstance` refusal of a non-configurable, non-enumerable member** (`AGENTS.md`
|
|
73
|
+
§17) says that members the same call replaced before it stay spied until `restoreSpiedInstance` or
|
|
74
|
+
the `setupAutoSpy()` sweep puts them back.
|
|
75
|
+
|
|
76
|
+
## [5.37.0] - 2026-09-26
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- **`stable()` takes Angular 22.2's `TestBed.createDirective` fixture.** It only ever awaited
|
|
81
|
+
`whenStable()`, but was typed on `ComponentFixture`, so `await stable(TestBed.createDirective(Dir,
|
|
82
|
+
{ tagName }))` failed with `TS2345` and specs fell back to `detectChanges()`, which flushes no
|
|
83
|
+
effects. It now accepts any fixture with `whenStable()`; nothing in the signature names
|
|
84
|
+
`DirectiveFixture`, so Angular 20 and 21 compile as before.
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- **`toHaveDirectiveApplied` finds a directive on the element a fixture is rooted at.** It searched
|
|
89
|
+
with `queryAll`, which never returns the root, so on a `TestBed.createDirective` fixture — rooted at
|
|
90
|
+
the element that carries the directive — it failed with `it is not on any element of this fixture`
|
|
91
|
+
and advised `createDirectiveHost`. The root is searched too; on a `ComponentFixture` that also counts
|
|
92
|
+
a `hostDirectives` entry of the component under test.
|
|
93
|
+
- **`vitest-auto-spy/eslint-plugin` is assignable to ESLint's own `Plugin` and flat-config types.**
|
|
94
|
+
`plugins: { 'vitest-auto-spy': autoSpy }` in a typed `eslint.config.ts`, or in
|
|
95
|
+
`new Linter().verify(code, [...])`, failed with `TS2322` / `TS2769`: `configs.*.plugins` was
|
|
96
|
+
`Record<string, unknown>` and each rule's `create` was typed on the library's own context. The
|
|
97
|
+
configs now name the plugin type, and a published rule is typed the way ESLint calls it. The plugin
|
|
98
|
+
still imports nothing from ESLint.
|
|
99
|
+
- **`strayListeners` no longer blames a spec file for jsdom's own wiring, and no longer strips it.**
|
|
100
|
+
Under Vitest 5, assigning a window global in jsdom or happy-dom also writes it to the environment's
|
|
101
|
+
real window, so the tracking wrapper sat where jsdom's internals call it too. The first
|
|
102
|
+
`querySelectorAll`, `matches` or `getComputedStyle` on a document makes jsdom's selector engine
|
|
103
|
+
register nine focus, keyboard and mouse listeners on the window, once; the file that happened to
|
|
104
|
+
run it failed under `onStrayListeners: 'throw'` with `left 9 window/document listeners attached`,
|
|
105
|
+
and the sweep took them off, which broke `:focus` and `:hover` matching for every later file in
|
|
106
|
+
the worker. The same held under a VM pool (`vmThreads`, the Analog default) on any Vitest version.
|
|
107
|
+
A registration whose first caller frame is inside `jsdom`, `happy-dom` or `@asamuzakjp/*` is now
|
|
108
|
+
the environment's and is neither counted nor swept — which also covers the `resize` listener
|
|
109
|
+
happy-dom's `matchMedia` adds per `change` listener. A `document.querySelectorAll('*')` warm-up
|
|
110
|
+
placed before `setupAutoSpy()` to work around this can go.
|
|
111
|
+
- **Stray timer and listener reports quote the caller instead of `__VITEST_HELPER__`.** When every
|
|
112
|
+
frame of a registration was inside dependencies, the first one shown was the `vi.defineHelper`
|
|
113
|
+
wrapper around the tracker. It is now skipped like the library's own frames.
|
|
114
|
+
|
|
115
|
+
### Docs
|
|
116
|
+
|
|
117
|
+
- **`no-redundant-mock-reset` says what it cannot read.** A runner config assembled by a factory or
|
|
118
|
+
a `mergeConfig` from another module sets `clearMocks` in a file the rule never opens; the docs now
|
|
119
|
+
say to write the flag beside `configFile`. The Vitest 5 default for a config that leaves it out
|
|
120
|
+
arrived in 5.35.0.
|
|
121
|
+
|
|
13
122
|
## [5.36.0] - 2026-09-26
|
|
14
123
|
|
|
15
124
|
**Why upgrade.** Eleven entries that crashed on import under `bun:test` load now, and every spec
|
|
@@ -5374,7 +5483,9 @@ moved under 1 %: `/angular` +192 B (+1.0 %) for the override queue and the HTTP
|
|
|
5374
5483
|
This copy ships with the package and carries 5.x only. Releases before 5.0.0 are in the
|
|
5375
5484
|
[full changelog](https://github.com/ASDAlexey/vitest-auto-spy/blob/master/CHANGELOG.md).
|
|
5376
5485
|
|
|
5377
|
-
[Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.
|
|
5486
|
+
[Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.38.0...HEAD
|
|
5487
|
+
[5.38.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.37.0...v5.38.0
|
|
5488
|
+
[5.37.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.36.0...v5.37.0
|
|
5378
5489
|
[5.36.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.35.0...v5.36.0
|
|
5379
5490
|
[5.35.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.34.0...v5.35.0
|
|
5380
5491
|
[5.34.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.33.0...v5.34.0
|
package/README.md
CHANGED
|
@@ -1035,29 +1035,30 @@ error tsconfig-glob-matches-nothing libs/users/tsconfig.spec.json
|
|
|
1035
1035
|
3 errors, 4 warnings, 1 note
|
|
1036
1036
|
```
|
|
1037
1037
|
|
|
1038
|
-
| Check | What it finds
|
|
1039
|
-
| ----------------------------------- |
|
|
1040
|
-
| `tsconfig-glob-matches-nothing` | An `include` pattern that matches no file — so it type-checks nothing; `info` when nothing beside the config is there to miss yet
|
|
1041
|
-
| `tsconfig-file-missing` | A `files` entry naming a file that is gone
|
|
1042
|
-
| `spec-imported-by-non-spec` | A production module importing a `*.spec.ts`
|
|
1043
|
-
| `spec-exports-fixture` | A spec importing another spec, whose hooks then run in a foreign file
|
|
1044
|
-
| `foreign-runner-pragma` | `@jest-environment` left in a spec, which Vitest never reads
|
|
1045
|
-
| `dead-runner-config` | `jest.config.*` / `karma.conf.*` for a runner that is not installed
|
|
1046
|
-
| `orphan-runner-file` | A setup file only that dead config referenced
|
|
1047
|
-
| `angular-build-splitting-off` | `@angular/build` in `[22.1.5, 22.1.7)` — the OOM under `--coverage`
|
|
1048
|
-
| `analog-behind-angular-build` | `@analogjs/vite-plugin-angular` below 2.7.5 next to `@angular/build` 22.2+ — `TypeError: cache.has is not a function` at startup
|
|
1049
|
-
| `coverage-all-removed` | `coverage.all` in a config, on a Vitest that stopped reading the key
|
|
1050
|
-
| `coverage-include-misses-bundle` | A `coverage.include` of sources only, in a runner config over a bundle
|
|
1051
|
-
| `coverage-include-recompiles-globs` | A coverage scope large enough that `picomatch` recompiling it per file costs more than the coverage. Info
|
|
1052
|
-
| `vitest-5-removed` | What Vitest 5 removed — `vitest/reporters`-style imports, `.sequential`, `--outputJson`/`--compare`; error on 5, note on 4. Also `poolOptions` (warning, ignored since 4)
|
|
1053
|
-
| `vitest-5-deprecated` | `experimental_clearCache` / `experimental_parseSpecifications` on Vitest 5, which nothing warns about at run time. Info
|
|
1054
|
-
| `vitest-5-clear-mocks` | `clearMocks: true` restating the Vitest 5 default, or a Vitest 4 suite that never decided and will have mocks cleared after the upgrade. Info
|
|
1055
|
-
| `
|
|
1056
|
-
| `
|
|
1057
|
-
| `
|
|
1058
|
-
| `
|
|
1059
|
-
| `
|
|
1060
|
-
| `
|
|
1038
|
+
| Check | What it finds |
|
|
1039
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1040
|
+
| `tsconfig-glob-matches-nothing` | An `include` pattern that matches no file — so it type-checks nothing; `info` when nothing beside the config is there to miss yet |
|
|
1041
|
+
| `tsconfig-file-missing` | A `files` entry naming a file that is gone |
|
|
1042
|
+
| `spec-imported-by-non-spec` | A production module importing a `*.spec.ts` |
|
|
1043
|
+
| `spec-exports-fixture` | A spec importing another spec, whose hooks then run in a foreign file |
|
|
1044
|
+
| `foreign-runner-pragma` | `@jest-environment` left in a spec, which Vitest never reads |
|
|
1045
|
+
| `dead-runner-config` | `jest.config.*` / `karma.conf.*` for a runner that is not installed |
|
|
1046
|
+
| `orphan-runner-file` | A setup file only that dead config referenced |
|
|
1047
|
+
| `angular-build-splitting-off` | `@angular/build` in `[22.1.5, 22.1.7)` — the OOM under `--coverage` |
|
|
1048
|
+
| `analog-behind-angular-build` | `@analogjs/vite-plugin-angular` below 2.7.5 next to `@angular/build` 22.2+ — `TypeError: cache.has is not a function` at startup |
|
|
1049
|
+
| `coverage-all-removed` | `coverage.all` in a config, on a Vitest that stopped reading the key |
|
|
1050
|
+
| `coverage-include-misses-bundle` | A `coverage.include` of sources only, in a runner config over a bundle |
|
|
1051
|
+
| `coverage-include-recompiles-globs` | A coverage scope large enough that `picomatch` recompiling it per file costs more than the coverage. Info |
|
|
1052
|
+
| `vitest-5-removed` | What Vitest 5 removed — `vitest/reporters`-style imports, `.sequential`, `--outputJson`/`--compare`; error on 5, note on 4. Also `poolOptions` (warning, ignored since 4) |
|
|
1053
|
+
| `vitest-5-deprecated` | `experimental_clearCache` / `experimental_parseSpecifications` on Vitest 5, which nothing warns about at run time. Info |
|
|
1054
|
+
| `vitest-5-clear-mocks` | `clearMocks: true` restating the Vitest 5 default, or a Vitest 4 suite that never decided and will have mocks cleared after the upgrade. Info |
|
|
1055
|
+
| `mock-reset-config-unread` | `no-redundant-mock-reset` given a `configFile` whose default export is a factory or `mergeConfig` call and no flag beside it — the rule reads none of the flags that call sets. Info |
|
|
1056
|
+
| `vitest-5-available` | Vitest 4 with nothing holding back 5 — what it buys (−46 % v8 / −35.5 % istanbul on a 700-file Angular suite with coverage) — or what holds it back. Info |
|
|
1057
|
+
| `fs-module-cache-not-persisted` | `fsModuleCache` on, and no CI config caches its directory — every CI run starts cold |
|
|
1058
|
+
| `jasmine-era-project` | `jasmine-core`, `@types/jasmine`, `karma.conf.*` or `@hirez_io/observer-spy` still installed. Info, not an error |
|
|
1059
|
+
| `no-agent-instructions` | No instruction file names the package. A note, not an error |
|
|
1060
|
+
| `helper-from-wrong-entry` | A named import taken from an entry that does not export it — `provideAutoSpy` from the root |
|
|
1061
|
+
| `no-unawaited-helper` | An `expectEmission` / `stable` / `flushEventLoop` call dropped as a bare statement, so nothing awaits it |
|
|
1061
1062
|
|
|
1062
1063
|
The check that motivated the tool: a spec showing `Cannot find name 'vi'` in the editor while
|
|
1063
1064
|
`tsc --noEmit` reported zero errors. A migration codemod editing `include` had eaten a `/**`,
|
|
@@ -1293,8 +1294,8 @@ Add this to the instruction file your agent actually reads — the table below s
|
|
|
1293
1294
|
|
|
1294
1295
|
```md
|
|
1295
1296
|
When writing or fixing tests that use `vitest-auto-spy`, first read
|
|
1296
|
-
`node_modules/vitest-auto-spy/AGENTS.md
|
|
1297
|
-
|
|
1297
|
+
`node_modules/vitest-auto-spy/AGENTS.md` whole — a short map — then only the topic files in
|
|
1298
|
+
`agent-docs/` it names for the task.
|
|
1298
1299
|
```
|
|
1299
1300
|
|
|
1300
1301
|
The text is the same everywhere; only the filename changes. **Two files cover the whole field: a
|
|
@@ -1344,8 +1345,8 @@ cat >> AGENTS.md <<'MD'
|
|
|
1344
1345
|
## Tests that use `vitest-auto-spy`
|
|
1345
1346
|
|
|
1346
1347
|
When writing or fixing tests that use `vitest-auto-spy`, first read
|
|
1347
|
-
`node_modules/vitest-auto-spy/AGENTS.md
|
|
1348
|
-
|
|
1348
|
+
`node_modules/vitest-auto-spy/AGENTS.md` whole — a short map — then only the topic files in
|
|
1349
|
+
`agent-docs/` it names for the task.
|
|
1349
1350
|
MD
|
|
1350
1351
|
|
|
1351
1352
|
# 2 — CLAUDE.md: Claude Code, and GLM / Kimi running inside it. One line, no second copy to maintain
|
|
@@ -1588,6 +1589,12 @@ Node / Bun / React / Vue project pulls **neither rxjs nor Angular into its runti
|
|
|
1588
1589
|
> `@nestjs/*`, `react`, `vue`/`pinia` and `svelte` stay your own (already-present) dev dependencies and
|
|
1589
1590
|
> never reach this package's runtime bundle.
|
|
1590
1591
|
|
|
1592
|
+
> **`vitest-auto-spy/angular` is a companion to the root, not a copy of it.** Of the core it
|
|
1593
|
+
> re-exports only the `Spy<T>` type, the `mock*Prop` helpers with `restoreMockedProps`, the
|
|
1594
|
+
> `expectEmission` family and `registerAutoSpyDefaults`. `createSpyFromClass`, `createMock`,
|
|
1595
|
+
> `createAutoMock`, `spyOnVoidMethod`, `spyOnOwnMethod`, `stubConstructor`, `asInstance` and the rest
|
|
1596
|
+
> stay on `vitest-auto-spy`, so an Angular spec that needs one imports from both.
|
|
1597
|
+
|
|
1591
1598
|
> **The two entries every suite loads are shipped as one module each.** Importing an entry costs
|
|
1592
1599
|
> per-module loader work rather than per-byte work, and every consumer imports the root on every spec
|
|
1593
1600
|
> file while every Angular consumer imports `/angular` alongside it. The root now reaches the loader
|
|
@@ -3097,7 +3104,7 @@ off, and `verifyNoPendingRequests()` runs the same check by hand.
|
|
|
3097
3104
|
|
|
3098
3105
|
It is a separate entry because it is the only part of the package that imports `@angular/common` —
|
|
3099
3106
|
an **optional** peer, so `vitest-auto-spy/angular` keeps loading in a project that does not have it.
|
|
3100
|
-
Like `/angular-router
|
|
3107
|
+
Like `/angular-router`, it does not re-export the core; it is a companion to
|
|
3101
3108
|
`vitest-auto-spy/angular`, not a replacement.
|
|
3102
3109
|
|
|
3103
3110
|
### React (Testing Library)
|
|
@@ -3972,7 +3979,7 @@ export can never be.
|
|
|
3972
3979
|
| `prefer-settle-dynamic-import` | `error` | suggest | `await import('./thing')` — or `import('./thing').then(…)` — written in a test body or a hook to settle a module the code under test lazy-loads → `await settleDynamicImport(() => import('./thing'))`. Awaiting the specifier waits for the **module**; the handler's own continuation, the lines after _its_ `await`, is still queued behind it, so the assertion reads the state one turn early. The suggestion wraps the `import()` and imports the helper. Reported only where the innermost enclosing function is the runner's own callback, which is what exempts a `vi.mock` factory, a lazy route's `loadComponent` and a callback the spec hands to production code |
|
|
3973
3980
|
| `prefer-create-mock` | `warn` | suggest | an object literal under `as SomeType` — `{ id: '1', isOffline: false } as Device`, and the `<Device>{ … }` spelling → `createMock<Device>({ … })`, which takes a `DeepPartial<Device>` and answers a `Device`. A cast asks whether the two types overlap, so it passes a key the type does not declare **and** a required field the fixture never sets; both type gates stay silent and the fixture is then spread into an expected payload. Silent on `as const`, on `as unknown` / `as any` and the double cast built from them, on a cast of anything that is not a literal, and on a literal inside one of this library's own factories. `warn`, not `error`: the repair makes a drifted fixture red on the next type-check, which is the finding and also a migration taken file by file |
|
|
3974
3981
|
| `no-mock-cast` | `error` | suggest | `TestBed.inject(S).m as Mock` — a cast to Vitest's `Mock` / `MockInstance` over a **member access** → `injectSpy(S).m`, which the suggestion writes when the token is in view. `Mock` with no parameters is `Mock<any>`, so `mockReturnValue` takes anything and `toHaveBeenCalledWith` stops comparing arguments; the worse form, `(spy.m.mockReturnValue as Mock)(…)`, gets a message of its own because the cast sits on the member that installs the answer. The name has to resolve to a runner's import, so a domain `Mock` is never reported |
|
|
3975
|
-
| `no-redundant-mock-reset` | `error` | `--fix` / suggest | a mock reset **the runner already performs** — `vi.clearAllMocks()` / `resetAllMocks()` / `restoreAllMocks()`, `x.mockClear()` / `mockReset()` / `mockRestore()` —
|
|
3982
|
+
| `no-redundant-mock-reset` | `error` | `--fix` / suggest | a mock reset **the runner already performs** — `vi.clearAllMocks()` / `resetAllMocks()` / `restoreAllMocks()`, `x.mockClear()` / `mockReset()` / `mockRestore()` — first in a `beforeEach` no other `beforeEach` precedes, or a clear closing an `afterEach` → delete it. **Silent until** the runner's flags are known: `['error', { clearMocks: true }]` and siblings, `{ configFile }`, or a `vitest.config.*` / `vite.config.*` above the file, read as text; a factory or `mergeConfig` in another module is not read through, and `setupAutoSpy({ restoreMocks })` is not the runner's flag. The flag has to match the call: `restoreMocks` never reaches a plain `vi.fn()`. `--fix` only where it is the file's only before-hook, a suggestion elsewhere, **never** in a test body |
|
|
3976
3983
|
| `no-unasserted-argument` | `warn` | — | a bare `expect(spy).toHaveBeenCalled()` where the file itself says the arguments are the point: the same subject is pinned with `toHaveBeenCalledWith(…)` in another test of the file, or the test's title says `with` and its body asserts nothing else → name the arguments. Narrower than `vitest/prefer-called-with` on purpose — 175 findings against its 1941 on the same suite |
|
|
3977
3984
|
| `no-compile-components` | `error` | suggest | `compileComponents()` under a builder that inlines `templateUrl` / `styleUrls` — a promise already settled; **silent** until `{ builder: 'inline-resources' }` says so, because a JIT setup that loads resources at run time needs the call. One exception the rule cannot see: a component whose template holds a `@defer` block ships async class metadata, so the call stays load-bearing there |
|
|
3978
3985
|
| `no-sync-testbed-await` | `error` | suggest | `await` on a TestBed call that answers the TestBed or a fixture — `configureTestingModule`, every `override*`, `resetTestingModule`, `createComponent`, `getLastFixture`; none of them is a promise, so the `await` waits for nothing and the `async` it forced on the hook awaits nothing either. The suggestion drops both. Reads no types, so it reports without `parserOptions.project` |
|
package/agent-docs/angular.md
CHANGED
|
@@ -26,6 +26,14 @@ helper a suite names once in a setup file must not ride along with every `provid
|
|
|
26
26
|
the diagnostics, doubles and matcher registrars left on that rule (`trackInjections` stays —
|
|
27
27
|
`createWithAutoSpies` needs its module).
|
|
28
28
|
|
|
29
|
+
**`/angular` is not a second copy of the core.** Of the root entry it re-exports only the `Spy<T>`
|
|
30
|
+
type (5.35.0), the `mock*Prop` family with `restoreMockedProps` / `countMockedProps`, the
|
|
31
|
+
`expectEmission` family and `registerAutoSpyDefaults` / `clearAutoSpyDefaults`. Every other runtime
|
|
32
|
+
name — `createSpyFromClass`, `createMock`, `createAutoMock`, `createSpyFromInstance`,
|
|
33
|
+
`spyOnVoidMethod`, `spyOnOwnMethod`, `stubConstructor`, `asInstance`, `asSpy` — stays on
|
|
34
|
+
`vitest-auto-spy`, so a spec that needs one keeps a second import line; do not fold it into the
|
|
35
|
+
`/angular` import. `/bun-angular` differs: a runner entry, it re-exports the whole core.
|
|
36
|
+
|
|
29
37
|
### The same thing as fixtures — `extendWithAutoSpies` (Vitest 4.1+)
|
|
30
38
|
|
|
31
39
|
The block above, written once instead of once per dependency, with the types inferred rather than
|
|
@@ -476,7 +484,7 @@ and the next line reads the settled value.
|
|
|
476
484
|
|
|
477
485
|
Three things to know before reaching for it:
|
|
478
486
|
|
|
479
|
-
- **It does not re-export the core** — nor does `/angular-router
|
|
487
|
+
- **It does not re-export the core** — nor does `/angular-router`, and `/angular` only a few names (§13). It is a
|
|
480
488
|
companion to `vitest-auto-spy/angular`, which stays the import for spies, `TestBed` helpers and
|
|
481
489
|
`settleResource`.
|
|
482
490
|
Staying narrow is what keeps `@angular/common` — an **optional** peer — out of every other entry.
|
|
@@ -977,6 +985,7 @@ spies.get(PricingService).total.mockReturnValue(100);
|
|
|
977
985
|
// zoneless waiting
|
|
978
986
|
await stable(fixture); // flush effects, then await the fixture; fails at 2000 ms naming the cause
|
|
979
987
|
await stable(fixture, { timeout: 5000, label: 'the products fixture' });
|
|
988
|
+
await stable(TestBed.createDirective(TooltipDirective, { tagName: 'button' })); // any fixture with whenStable()
|
|
980
989
|
flushEffects(); // the no-fixture half: services, stores, runInInjectionContext
|
|
981
990
|
|
|
982
991
|
// resources — one wait for httpResource(), resource() and rxResource()
|
|
@@ -1177,6 +1186,27 @@ _is_ declared; `NG0304` calls a missing directive a missing component; a bare at
|
|
|
1177
1186
|
nothing at all). `schemas: [NO_ERRORS_SCHEMA]` next to a standalone component is a dead entry —
|
|
1178
1187
|
schemas apply to a testing module's `declarations` only.
|
|
1179
1188
|
|
|
1189
|
+
It is also the guard for an attribute a `hostDirectives` entry puts on the component under test. An
|
|
1190
|
+
assertion on the attribute alone stays green when the entry is dropped and the attribute is also
|
|
1191
|
+
written statically, or set by something else; the fixture's root element is searched, so the entry
|
|
1192
|
+
itself can be asserted with no selector:
|
|
1193
|
+
|
|
1194
|
+
```ts
|
|
1195
|
+
import { registerDirectiveMatchers } from 'vitest-auto-spy/angular/matchers';
|
|
1196
|
+
|
|
1197
|
+
registerDirectiveMatchers(); // once, in the setup file; nothing registers the matcher for you
|
|
1198
|
+
|
|
1199
|
+
const fixture = TestBed.createComponent(CardComponent); // hostDirectives: [TestIdDirective]
|
|
1200
|
+
|
|
1201
|
+
expect(fixture).toHaveDirectiveApplied(TestIdDirective);
|
|
1202
|
+
expect(hostElement(fixture).getAttribute('data-testid')).toBe('card');
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
Angular ≥ 22.2: when the directive needs no static host attribute, no `TemplateRef` (structural) and
|
|
1206
|
+
no sibling markup, `TestBed.createDirective(Dir, { tagName, bindings })` builds the host itself.
|
|
1207
|
+
`stable(fixture)`, `hostElement(fixture)` and `toHaveDirectiveApplied` take its `DirectiveFixture`;
|
|
1208
|
+
`setInputs` does not (no `componentRef`) — bind a signal with `inputBinding` and set it.
|
|
1209
|
+
|
|
1180
1210
|
### A stand-in for a child — `createComponentStub`
|
|
1181
1211
|
|
|
1182
1212
|
Do not hand-write `class MockChartComponent` with a copied selector: nothing checks the copy, so a
|
package/agent-docs/checklist.md
CHANGED
|
@@ -48,7 +48,9 @@ a unit-test target, Analog below 2.7.5, `vite` below 6.4, or Node below 22.12 in
|
|
|
48
48
|
`.node-version`, CI or a private package's `engines`. `fs-module-cache-not-persisted` warns when
|
|
49
49
|
`fsModuleCache` is on and no CI config caches its directory. Renamed config keys Vitest 5 still
|
|
50
50
|
honours (`experimental.fsModuleCache`, `browser.isolate`, `cache.dir`, …) are left to Vitest's own
|
|
51
|
-
deprecation line.
|
|
51
|
+
deprecation line. `mock-reset-config-unread` notes a `no-redundant-mock-reset` whose `configFile` names
|
|
52
|
+
a config built by a factory or `mergeConfig`, with no flag beside it: the rule cannot see the flags
|
|
53
|
+
that call sets.
|
|
52
54
|
It is worth one run after any large edit to a test suite — especially after a codemod, which is where
|
|
53
55
|
the eaten glob below came from.
|
|
54
56
|
|
package/agent-docs/errors.md
CHANGED
|
@@ -47,9 +47,9 @@ Part of the agent reference [`AGENTS.md`](../AGENTS.md), which maps every sectio
|
|
|
47
47
|
| `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: … })` |
|
|
48
48
|
| `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 |
|
|
49
49
|
| `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) |
|
|
50
|
-
| `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) |
|
|
50
|
+
| `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, happy-dom's `MediaQueryList` included (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) |
|
|
51
51
|
| `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()` |
|
|
52
|
-
| `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` |
|
|
52
|
+
| `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`; members the same call replaced before `X` stay spied until `restoreSpiedInstance(instance)` or the `setupAutoSpy()` sweep |
|
|
53
53
|
| `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 |
|
|
54
54
|
| `.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) |
|
|
55
55
|
| `@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) |
|
|
@@ -126,7 +126,7 @@ Part of the agent reference [`AGENTS.md`](../AGENTS.md), which maps every sectio
|
|
|
126
126
|
| `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 |
|
|
127
127
|
| `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) |
|
|
128
128
|
| `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) |
|
|
129
|
-
| `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) |
|
|
129
|
+
| `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] })`; on Angular ≥ 22.2, for a directive with no static host attribute, `TemplateRef` or sibling markup, `TestBed.createDirective(Dir, { tagName, bindings })` (§13) |
|
|
130
130
|
| `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) |
|
|
131
131
|
| `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) |
|
|
132
132
|
| `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 |
|
package/agent-docs/eslint.md
CHANGED
|
@@ -75,7 +75,7 @@ blanket downgrade so those keep their severity; do not copy the two names into a
|
|
|
75
75
|
| `prefer-settle-dynamic-import` | `error` | suggest | `await import('./thing')` and `import('./thing').then(…)` inside an `it` / `test` body or a `beforeEach` / `beforeAll` / `afterEach` / `afterAll` hook (the `.only`, `.skip` and `.each` spellings included) → `await settleDynamicImport(() => import('./thing'))`, which is the same load plus `flushEventLoop(1)` and returns the namespace, so the destructured form keeps reading the same way. The bare `await` waits for the **module** and not for the continuation of the code that was loading it, so the assertion runs a turn early and the test is green only while that continuation is short. Syntax only. Silent wherever a function of its own sits between the runner's callback and the import — a `vi.mock` factory, a lazy route's `loadComponent` / `loadChildren`, a callback handed to production code, `settleDynamicImport`'s own `() => import(…)` — and, by the same reading, silent on a spec-local `const load = async () => { await import('…') }`, which is written identically whether the spec calls it or the code under test does |
|
|
76
76
|
| `prefer-create-mock` | `warn` | suggest | an object literal under `as SomeType` — `{ id: '1', isOffline: false } as Device`, `<Device>{ … }` too → `createMock<Device>({ … })`. A cast asks whether the two types overlap rather than whether the value is one of them, so it passes a key the type does not declare (the excess-property check is skipped) **and** a required field the fixture never sets; both type gates stay silent, and the same object is then spread into the expected payload of a call assertion. Where the literal already sits in a typed slot the first repair is to delete the cast. Silent on `as const`, `as unknown` / `as any` and the double cast built from them, on a cast of anything but a literal, and on a literal inside one of this library's own factories. `warn`, because accepting the suggestion makes a drifted fixture red on the next type-check — the finding, and a migration taken file by file |
|
|
77
77
|
| `no-mock-cast` | `error` | suggest | a cast to Vitest's `Mock` / `MockInstance` over a **member access** — `TestBed.inject(S).m as Mock` → `injectSpy(S).m`, which the suggestion writes whenever the token is in view (directly, or through a `const` the file settled with a `TestBed.inject`). `Mock` with no parameters is `Mock<any>`: `mockReturnValue` takes anything and `toHaveBeenCalledWith` stops comparing arguments. `(spy.m.mockReturnValue as Mock)(…)` gets its own message — the cast is on the member that installs the answer, so neither the value nor the method's return type is checked. The name must resolve to an import from `vitest` / `@rstest/core` / `bun:test` / `jest`, or to nothing at all, so a domain `Mock` is left alone |
|
|
78
|
-
| `no-redundant-mock-reset` | `error` | `--fix` / suggest | a mock reset the runner already performs between tests — `vi.clearAllMocks()` / `resetAllMocks()` / `restoreAllMocks()`, `x.mockClear()` / `mockReset()` / `mockRestore()` — standing where nothing the file wrote ran since the runner's own: the first statement of a `beforeEach` no other `beforeEach` precedes, or a clear as the last statement of an `afterEach` → delete it, and the hook with it where that is all it held. A restore or reset in `afterEach` / `afterAll` is never reported: after the last test it is what takes a spy off before the `afterAll` hooks. **Silent** until the flags are known: options `{ clearMocks, restoreMocks, mockReset }` (or `{ configFile }` naming the runner config) first, then a `vitest.config.*` / `vite.config.*` searched upwards from the file and read as text. Flag matches call, never family — `restoreMocks` walks only the spies `vi.spyOn` installed. `--fix` only in a file whose only before-hook it is; a suggestion otherwise; never inside a test body |
|
|
78
|
+
| `no-redundant-mock-reset` | `error` | `--fix` / suggest | a mock reset the runner already performs between tests — `vi.clearAllMocks()` / `resetAllMocks()` / `restoreAllMocks()`, `x.mockClear()` / `mockReset()` / `mockRestore()` — standing where nothing the file wrote ran since the runner's own: the first statement of a `beforeEach` no other `beforeEach` precedes, or a clear as the last statement of an `afterEach` → delete it, and the hook with it where that is all it held. A restore or reset in `afterEach` / `afterAll` is never reported: after the last test it is what takes a spy off before the `afterAll` hooks. **Silent** until the flags are known: options `{ clearMocks, restoreMocks, mockReset }` (or `{ configFile }` naming the runner config) first, then a `vitest.config.*` / `vite.config.*` searched upwards from the file and read as text; a config that leaves `clearMocks` out counts it on from Vitest 5 (its default). A config built by a factory or `mergeConfig` from another module is not read through — write its flags beside `configFile` (`doctor` notes the case as `mock-reset-config-unread`). `setupAutoSpy({ restoreMocks: true })` is not the runner's `restoreMocks` (it restores in an `afterEach`, after the test) — never pass the rule a flag only the setup file sets. Flag matches call, never family — `restoreMocks` walks only the spies `vi.spyOn` installed. `--fix` only in a file whose only before-hook it is; a suggestion otherwise; never inside a test body |
|
|
79
79
|
| `no-unasserted-argument` | `warn` | — | a bare `expect(spy).toHaveBeenCalled()` on evidence from the file: the same subject asserted with `toHaveBeenCalledWith(…)` in another test, or a title containing `with` over a body whose every assertion is a bare call → `toHaveBeenCalledWith(…)` / `mustBeCalledWith(…)`. `not.toHaveBeenCalled()` and the counting matchers are never reported |
|
|
80
80
|
| `no-compile-components` | `error` | suggest | `compileComponents()` under a builder that inlines `templateUrl` / `styleUrls` — a promise already settled → delete it, and the `async` of a hook that awaits nothing else. **Silent until** `['error', { builder: 'inline-resources' }]`: under a JIT setup that loads resources at run time the call is load-bearing. **Keep the call for a component whose template holds a `@defer` block** — that ships async class metadata, which `TestBed` resolves in this very call whatever the builder did, and dropping it fails the test with `has unresolved metadata`; the rule cannot see another file's template, so list those classes in `{ ignoreComponents: ['CardComponent'] }` (a spec naming one is left alone) or keep a `// eslint-disable-next-line vitest-auto-spy/no-compile-components -- @defer: async class metadata` |
|
|
81
81
|
| `no-sync-testbed-await` | `error` | suggest | `await` on a TestBed call that answers the TestBed or a fixture — `configureTestingModule`, `override*`, `resetTestingModule`, `createComponent`, `getLastFixture`, through `TestBed`, `getTestBed()`, a chain of those, or a name holding one → drop the `await`, and the `async` of a hook that then awaits nothing else; the suggestion does both. Reads **no types**, so it reports without `parserOptions.project`, where `@typescript-eslint/await-thenable` cannot. `inject` and `runInInjectionContext` are never reported: each answers whatever the token or the callback holds, which can be a promise |
|
package/agent-docs/setup.md
CHANGED
|
@@ -202,7 +202,9 @@ setupAutoSpy({ strayListeners: true }); // wrap addEventListener, sweep what the
|
|
|
202
202
|
|
|
203
203
|
The split is the one `pruneMockRegistry` uses: a `beforeAll` marks the listeners already on
|
|
204
204
|
`window`/`document` — registered while the module graph was evaluated, a framework's one-time
|
|
205
|
-
initialisation — and the `afterAll` takes off everything added since.
|
|
205
|
+
initialisation — and the `afterAll` takes off everything added since. A registration jsdom or
|
|
206
|
+
happy-dom makes itself (jsdom wires nine focus, keyboard and mouse listeners the first time a
|
|
207
|
+
document is queried) is the environment's: neither counted nor swept. The pieces are exported too:
|
|
206
208
|
`trackStrayListeners()` (idempotent, returns the undo), `baselineStrayListeners()`,
|
|
207
209
|
`removeStrayListeners()` (returns how many), `countStrayListeners()` (throws before
|
|
208
210
|
`trackStrayListeners()` has run, like the timer counter) and `describeStrayListeners()` — each
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { pendingRequestsReport, assertAngularInternals, instrumentTestBed, onTestingModuleConfigured, onComponentCreated, beforeTestBedReset, verifyOnTeardown } from './chunk-GKSVYPZQ.js';
|
|
2
2
|
export { disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, reportSpecTiming } from './chunk-GKSVYPZQ.js';
|
|
3
|
-
import { failOnUnspiedProvider } from './chunk-
|
|
3
|
+
import { failOnUnspiedProvider } from './chunk-2KBRDNIB.js';
|
|
4
4
|
import './chunk-GG7BQKEK.js';
|
|
5
5
|
import './chunk-FWXDSPZD.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-6KP5QMMV.js';
|
|
7
7
|
import './chunk-FOL5RH22.js';
|
|
8
8
|
import './chunk-PC3FAZT3.js';
|
|
9
|
-
import './chunk-
|
|
9
|
+
import './chunk-RYFF55PV.js';
|
|
10
10
|
import { isAutoSpyLike } from './chunk-Q7L4AWI7.js';
|
|
11
11
|
import { count, taskName } from './chunk-M3NTXLZG.js';
|
|
12
12
|
import { angularPendingRequests, angularShadowedProviders, angularDeadSchemas, angularNgModuleScopesAuto } from './chunk-5FQZGJLJ.js';
|
package/dist/angular-doubles.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describeInstance } from './chunk-BS432KB2.js';
|
|
2
|
-
import { useVitestAdapter } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
import { useVitestAdapter } from './chunk-YNXQ2WFH.js';
|
|
3
|
+
import './chunk-B6C3K27C.js';
|
|
4
4
|
import './chunk-YHDBRBGU.js';
|
|
5
5
|
import './chunk-TXDBDMIL.js';
|
|
6
6
|
import './chunk-FOL5RH22.js';
|
|
7
7
|
import './chunk-PC3FAZT3.js';
|
|
8
|
-
import { createFunctionSpy } from './chunk-
|
|
8
|
+
import { createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
9
9
|
import './chunk-Q7L4AWI7.js';
|
|
10
10
|
import './chunk-M3NTXLZG.js';
|
|
11
11
|
import { angularDialog } from './chunk-5FQZGJLJ.js';
|
package/dist/angular-matchers.js
CHANGED
|
@@ -17,11 +17,14 @@ function rootOf(received) {
|
|
|
17
17
|
candidate
|
|
18
18
|
) : void 0;
|
|
19
19
|
}
|
|
20
|
+
function matching(root, predicate) {
|
|
21
|
+
return predicate(root) ? [root, ...root.queryAll(predicate)] : root.queryAll(predicate);
|
|
22
|
+
}
|
|
20
23
|
function diagnose(directive, selector, root) {
|
|
21
|
-
const
|
|
24
|
+
const elements = selector === void 0 ? [] : matching(root, By.css(selector));
|
|
22
25
|
const where = selector === void 0 ? "" : ` on '${selector}'`;
|
|
23
26
|
const prefix = `[vitest-auto-spy] expected ${directive.name} to be applied${where}`;
|
|
24
|
-
if (selector !== void 0 &&
|
|
27
|
+
if (selector !== void 0 && elements.length === 0) {
|
|
25
28
|
return withDocs(
|
|
26
29
|
`${prefix}, but no element matches that selector.
|
|
27
30
|
Run fixture.detectChanges() before asserting, and check the selector against the template.`,
|
|
@@ -47,14 +50,14 @@ function directiveResult(received, directive, selector) {
|
|
|
47
50
|
if (!root) {
|
|
48
51
|
throw new Error(
|
|
49
52
|
withDocs(
|
|
50
|
-
`[vitest-auto-spy] toHaveDirectiveApplied: expected a ComponentFixture or a DebugElement, received ${describeReceived(received)}.
|
|
53
|
+
`[vitest-auto-spy] toHaveDirectiveApplied: expected a ComponentFixture, a DirectiveFixture or a DebugElement, received ${describeReceived(received)}.
|
|
51
54
|
Pass the fixture itself, or fixture.debugElement \u2014 not fixture.nativeElement.`,
|
|
52
55
|
angularDirectiveApplied
|
|
53
56
|
)
|
|
54
57
|
);
|
|
55
58
|
}
|
|
56
|
-
const withDirective = root
|
|
57
|
-
const applied = selector === void 0 ? withDirective.length > 0 : root
|
|
59
|
+
const withDirective = matching(root, By.directive(directive));
|
|
60
|
+
const applied = selector === void 0 ? withDirective.length > 0 : matching(root, By.css(selector)).some((element) => element.providerTokens.includes(directive));
|
|
58
61
|
return {
|
|
59
62
|
pass: applied,
|
|
60
63
|
message: () => applied ? `[vitest-auto-spy] expected ${directive.name} not to be applied, but it is on ${count(withDirective.length, "element")}.` : diagnose(directive, selector, root)
|
package/dist/angular-router.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describeInstance } from './chunk-BS432KB2.js';
|
|
2
2
|
import { angularInternalsError } from './chunk-GG7BQKEK.js';
|
|
3
|
-
import { createFunctionSpy } from './chunk-
|
|
3
|
+
import { createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
4
4
|
import './chunk-Q7L4AWI7.js';
|
|
5
5
|
import { count } from './chunk-M3NTXLZG.js';
|
|
6
6
|
import { angularRouteDouble, angularRouterInject, angularRouterEvents, angularLocationDouble, angularRouteWiring, angularRouterDouble } from './chunk-5FQZGJLJ.js';
|
package/dist/angular.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { u as AngularTokenProvider, A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, E as ElementConstructor, N as NativeElementHolder, R as RenderShallowOptions, c as ResourceStatusLike, d as RunCounter, S as SettleResourceOptions, e as ShallowRender, f as SpyRegistry, g as StableOptions, h as createWithAutoSpies, i as flushEffects, j as hostElement, k as injectSpy, p as provideAutoSpy, v as provideAutoSpyForToken, q as queryElement, r as renderShallow, l as runEffect, s as setInputs, m as settleResource, n as stable, t as trackEffectRuns, o as trackRecomputations } from './track-signal-runs-
|
|
1
|
+
export { u as AngularTokenProvider, A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, E as ElementConstructor, N as NativeElementHolder, R as RenderShallowOptions, c as ResourceStatusLike, d as RunCounter, S as SettleResourceOptions, e as ShallowRender, f as SpyRegistry, g as StableOptions, h as createWithAutoSpies, i as flushEffects, j as hostElement, k as injectSpy, p as provideAutoSpy, v as provideAutoSpyForToken, q as queryElement, r as renderShallow, l as runEffect, s as setInputs, m as settleResource, n as stable, t as trackEffectRuns, o as trackRecomputations } from './track-signal-runs-C7SrW3Ub.js';
|
|
2
2
|
import { o as DeepPartial, C as ClassType, m as ClassSpyConfiguration, S as Spy, s as OnlyMethodKeysOf, h as AddSpyMethodsByReturnTypes, r as NotAPublicKey } from './types-BVKEkhWj.js';
|
|
3
3
|
import { InjectionToken, Provider, Type, WritableSignal, Signal } from '@angular/core';
|
|
4
4
|
import { A as AutoMockConfiguration, D as DeepReadonly } from './expect-emission-wUaoy0NW.js';
|
package/dist/bun-angular.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { AdoptMockOptions, AdoptedMock, ArgCaptor, AsInstances, AssertMockedOpti
|
|
|
3
3
|
export { A as AutoMockConfiguration, a as AutoMocked, b as AutoSpyDefaultEntry, C as CallbackSubscribable, E as EmissionObserver, c as EmissionOptions, d as EmissionSource, S as SubscribableLike, e as autoMocked, f as clearAutoSpyDefaults, g as createAutoMock, h as expectAllEmissions, i as expectCompletion, j as expectEmission, k as expectEmissions, l as expectError, m as expectNoEmission, r as registerAutoSpyDefaults, s as setEmissionTimeout } from './expect-emission-wUaoy0NW.js';
|
|
4
4
|
export { c as createFunctionSpy, d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-5pFBRWW9.js';
|
|
5
5
|
export { A as AccessorImplementations, O as OutsideHookReaction, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as reportPropsOutsideHooks, e as restoreMockedProps } from './prop-mock-8Ps9usRa.js';
|
|
6
|
-
export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, E as ElementConstructor, N as NativeElementHolder, R as RenderShallowOptions, c as ResourceStatusLike, d as RunCounter, S as SettleResourceOptions, e as ShallowRender, f as SpyRegistry, g as StableOptions, h as createWithAutoSpies, i as flushEffects, j as hostElement, k as injectSpy, p as provideAutoSpy, q as queryElement, r as renderShallow, l as runEffect, s as setInputs, m as settleResource, n as stable, t as trackEffectRuns, o as trackRecomputations } from './track-signal-runs-
|
|
6
|
+
export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, E as ElementConstructor, N as NativeElementHolder, R as RenderShallowOptions, c as ResourceStatusLike, d as RunCounter, S as SettleResourceOptions, e as ShallowRender, f as SpyRegistry, g as StableOptions, h as createWithAutoSpies, i as flushEffects, j as hostElement, k as injectSpy, p as provideAutoSpy, q as queryElement, r as renderShallow, l as runEffect, s as setInputs, m as settleResource, n as stable, t as trackEffectRuns, o as trackRecomputations } from './track-signal-runs-C7SrW3Ub.js';
|
|
7
7
|
import 'vitest';
|
|
8
8
|
import '@angular/core';
|
|
9
9
|
import '@angular/core/testing';
|
package/dist/bun-angular.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { createSpyForToken } from './chunk-
|
|
2
|
-
export { injectSpy, provideAutoSpy } from './chunk-
|
|
1
|
+
import { createSpyForToken } from './chunk-2TZCJ3MM.js';
|
|
2
|
+
export { injectSpy, provideAutoSpy } from './chunk-2KBRDNIB.js';
|
|
3
3
|
import { stable, flushEffects } from './chunk-DBC6526L.js';
|
|
4
4
|
export { flushEffects, stable } from './chunk-DBC6526L.js';
|
|
5
5
|
import { angularInternalsError } from './chunk-GG7BQKEK.js';
|
|
6
6
|
import './chunk-QDBRZQJO.js';
|
|
7
|
-
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-
|
|
7
|
+
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-5TYNQH5Q.js';
|
|
8
8
|
import { mockValueProp } from './chunk-FWXDSPZD.js';
|
|
9
9
|
export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-FWXDSPZD.js';
|
|
10
|
-
import { closestName } from './chunk-
|
|
11
|
-
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-
|
|
10
|
+
import { closestName } from './chunk-6KP5QMMV.js';
|
|
11
|
+
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6KP5QMMV.js';
|
|
12
12
|
import { fakeClockBacklog } from './chunk-W5EXSI22.js';
|
|
13
13
|
import './chunk-TXDBDMIL.js';
|
|
14
14
|
import './chunk-FOL5RH22.js';
|
|
15
15
|
import './chunk-PC3FAZT3.js';
|
|
16
|
-
export { createFunctionSpy, errorHandler } from './chunk-
|
|
16
|
+
export { createFunctionSpy, errorHandler } from './chunk-RYFF55PV.js';
|
|
17
17
|
import { libraryWarn } from './chunk-Q7L4AWI7.js';
|
|
18
18
|
import { displayPath, count } from './chunk-M3NTXLZG.js';
|
|
19
19
|
import { angularEffects, angularTrackRuns, bunAngular, angularUnreadResource, angularCreateWithAutoSpies, angularResources, angularTypedElements, angularInputs, angularKeepTemplate } from './chunk-5FQZGJLJ.js';
|
package/dist/bun.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import './chunk-QDBRZQJO.js';
|
|
2
|
-
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-
|
|
2
|
+
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-5TYNQH5Q.js';
|
|
3
3
|
export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-FWXDSPZD.js';
|
|
4
|
-
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-
|
|
4
|
+
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6KP5QMMV.js';
|
|
5
5
|
import './chunk-W5EXSI22.js';
|
|
6
6
|
import './chunk-TXDBDMIL.js';
|
|
7
7
|
import './chunk-FOL5RH22.js';
|
|
8
8
|
import './chunk-PC3FAZT3.js';
|
|
9
|
-
export { createFunctionSpy, errorHandler } from './chunk-
|
|
9
|
+
export { createFunctionSpy, errorHandler } from './chunk-RYFF55PV.js';
|
|
10
10
|
import './chunk-Q7L4AWI7.js';
|
|
11
11
|
import './chunk-M3NTXLZG.js';
|
|
12
12
|
import './chunk-5FQZGJLJ.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { currentSpecFile } from './chunk-FWXDSPZD.js';
|
|
2
|
-
import { createSpyFromClass } from './chunk-
|
|
2
|
+
import { createSpyFromClass } from './chunk-6KP5QMMV.js';
|
|
3
3
|
import { isAutoSpyLike, misconfigurationThrows, reportMisconfiguration } from './chunk-Q7L4AWI7.js';
|
|
4
4
|
import { angularInjectSpyReal } from './chunk-5FQZGJLJ.js';
|
|
5
5
|
import { withDocs } from './chunk-ENCEEH23.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { mockValueProp, mockAccessorsProp } from './chunk-FWXDSPZD.js';
|
|
2
|
-
import { resolveConfiguration, mergeAutoSpyDefaults, resolveReadGuard, mergeMethodNames, getCallableMemberNames, createTrackedPropSpy, applyConfiguredReturns, createSpyFromClass, warnOnUnknownMethods, warnOnAccessorNamingAMethod, resolveAccessors, createAccessorsSpies, ownerOf, createProxyPropStore, storeWriteTraps, describeStoredProp, hasStoredProp, isProtocolKey, isDeletedProp, readStoredAccessor, NOT_STORED, disposeAutoSpy, writeStoredValue } from './chunk-
|
|
2
|
+
import { resolveConfiguration, mergeAutoSpyDefaults, resolveReadGuard, mergeMethodNames, getCallableMemberNames, createTrackedPropSpy, applyConfiguredReturns, createSpyFromClass, warnOnUnknownMethods, warnOnAccessorNamingAMethod, resolveAccessors, createAccessorsSpies, ownerOf, createProxyPropStore, storeWriteTraps, describeStoredProp, hasStoredProp, isProtocolKey, isDeletedProp, readStoredAccessor, NOT_STORED, disposeAutoSpy, writeStoredValue } from './chunk-6KP5QMMV.js';
|
|
3
3
|
import { unpatchedSetTimeout, unpatchedClearTimeout, fakeClockAdvice, fakeClockBacklog } from './chunk-W5EXSI22.js';
|
|
4
4
|
import { redefineFailure } from './chunk-FOL5RH22.js';
|
|
5
5
|
import { DISPOSE } from './chunk-PC3FAZT3.js';
|
|
6
|
-
import { defineHelper, adoptFunctionSpy, reinstallDispatch, serializeValue, resolveUnstubbedGuard, createFunctionSpy } from './chunk-
|
|
6
|
+
import { defineHelper, adoptFunctionSpy, reinstallDispatch, serializeValue, resolveUnstubbedGuard, createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
7
7
|
import { isMarkedMock, reportMisconfiguration, DEEP_CHILDREN } from './chunk-Q7L4AWI7.js';
|
|
8
8
|
import { count, displayPath } from './chunk-M3NTXLZG.js';
|
|
9
9
|
import { moduleMocksAssert, moduleMocksNoOp, narrow, adoptMock, observableFailures, strictModePassthrough, createSpyFromClassReturns, captureArg, eventLoopUntil, mockConstructor, createSpyFromClassLiveDomNode } from './chunk-5FQZGJLJ.js';
|
|
@@ -79,12 +79,15 @@ function looksLikeLiveHostObject(instance) {
|
|
|
79
79
|
continue;
|
|
80
80
|
}
|
|
81
81
|
if (constructor.name === "EventTarget") {
|
|
82
|
-
return engineLevel;
|
|
82
|
+
return engineLevel || isEnginePrivateEventTarget(constructor);
|
|
83
83
|
}
|
|
84
84
|
engineLevel ||= Reflect.get(globalThis, constructor.name) === constructor;
|
|
85
85
|
}
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
|
+
function isEnginePrivateEventTarget(constructor) {
|
|
89
|
+
return typeof Node !== "undefined" && constructor !== Reflect.get(globalThis, "EventTarget") && Reflect.getPrototypeOf(Node.prototype) === Reflect.get(constructor, "prototype");
|
|
90
|
+
}
|
|
88
91
|
function warnOnUndiscriminatedHostDiscovery(label, listedAdditions) {
|
|
89
92
|
const additions = listedAdditions ? "The methods listed (a bare array is methodsToSpyOn) are spied in addition to that discovery, not instead of it. " : "";
|
|
90
93
|
reportMisconfiguration(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DISPOSE } from './chunk-PC3FAZT3.js';
|
|
2
|
-
import { defaultStrict, resolveUnstubbedGuard, seedReturnValue, createFunctionSpy } from './chunk-
|
|
2
|
+
import { defaultStrict, resolveUnstubbedGuard, seedReturnValue, createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
3
3
|
import { runClearHook, runConfigReset, reportMisconfiguration, AUTO_SPY_MARK, markAsMock, isMarkedMock, readDeepChildren } from './chunk-Q7L4AWI7.js';
|
|
4
4
|
import { autoMockHeldBack, createSpyFromClassInstanceMethods, createSpyFromClassAccessors, createSpyFromClassReturns, createSpyFromClassLazySpies } from './chunk-5FQZGJLJ.js';
|
|
5
5
|
import { withDocs } from './chunk-ENCEEH23.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { guardAccessorSpies, spyOnAccessorByRedefine } from './chunk-TXDBDMIL.js';
|
|
2
2
|
import { DISPOSE } from './chunk-PC3FAZT3.js';
|
|
3
|
-
import { isFastSpy, FAST_SPY_BRAND, isThenable } from './chunk-
|
|
3
|
+
import { isFastSpy, FAST_SPY_BRAND, isThenable } from './chunk-RYFF55PV.js';
|
|
4
4
|
import { setSharedHelperSink, hooksOf } from './chunk-Q7L4AWI7.js';
|
|
5
5
|
import { mockConstructor } from './chunk-5FQZGJLJ.js';
|
|
6
6
|
import { withDocs } from './chunk-ENCEEH23.js';
|
|
@@ -768,11 +768,15 @@ function installSettledResultsPolyfill(mockFn) {
|
|
|
768
768
|
// src/lib/stack-frames.ts
|
|
769
769
|
var FOREIGN_FRAME = /node_modules|node:internal|\(node:/;
|
|
770
770
|
var LIBRARY_FRAME = /[/\\]vitest-auto-spy[/\\]dist[/\\]|[/\\]\.vite[/\\]deps[^/\\]*[/\\]vitest-auto-spy[^/\\]*\.js/;
|
|
771
|
+
var HELPER_FRAME = /\b__VITEST_HELPER__\b/;
|
|
772
|
+
function isLibraryFrame(frame) {
|
|
773
|
+
return LIBRARY_FRAME.test(frame) || HELPER_FRAME.test(frame);
|
|
774
|
+
}
|
|
771
775
|
function stackFrames(stack) {
|
|
772
776
|
return String(stack).split("\n").filter((line) => /^\s*at\s/.test(line)).map((line) => line.trim());
|
|
773
777
|
}
|
|
774
778
|
function ownFrames(frames, limit) {
|
|
775
|
-
const outside = frames.filter((frame) => !
|
|
779
|
+
const outside = frames.filter((frame) => !isLibraryFrame(frame));
|
|
776
780
|
const own = outside.filter((frame) => !FOREIGN_FRAME.test(frame));
|
|
777
781
|
const shown = [own, outside].find((candidates) => candidates.length > 0) ?? frames;
|
|
778
782
|
return shown.slice(0, limit);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createRunnerMockAdapter } from './chunk-
|
|
1
|
+
import { createRunnerMockAdapter } from './chunk-B6C3K27C.js';
|
|
2
2
|
import { SWEEP_SENTINEL } from './chunk-YHDBRBGU.js';
|
|
3
3
|
import { hasMockAdapter, registerMockAdapter } from './shared-state.js';
|
|
4
4
|
import { vi } from 'vitest';
|
package/dist/cli.js
CHANGED
|
@@ -536,6 +536,7 @@ var DOCTOR_CHECKS = [
|
|
|
536
536
|
"fs-module-cache-not-persisted",
|
|
537
537
|
"helper-from-wrong-entry",
|
|
538
538
|
"jasmine-era-project",
|
|
539
|
+
"mock-reset-config-unread",
|
|
539
540
|
"module-mock-leak",
|
|
540
541
|
"no-agent-instructions",
|
|
541
542
|
"no-unawaited-helper",
|
|
@@ -3421,7 +3422,7 @@ function checkForeignPragma(graph) {
|
|
|
3421
3422
|
}
|
|
3422
3423
|
|
|
3423
3424
|
// src/cli/checks/export-map.generated.ts
|
|
3424
|
-
var EXPORT_MAP_VERSION = "5.
|
|
3425
|
+
var EXPORT_MAP_VERSION = "5.37.0";
|
|
3425
3426
|
var ENTRY_SPECIFIERS = "vitest-auto-spy vitest-auto-spy/bun vitest-auto-spy/bun-angular vitest-auto-spy/node vitest-auto-spy/rstest vitest-auto-spy/rxjs vitest-auto-spy/console vitest-auto-spy/dom-stubs vitest-auto-spy/diagnostics vitest-auto-spy/jasmine vitest-auto-spy/jasmine-compat vitest-auto-spy/observer-spy vitest-auto-spy/angular vitest-auto-spy/angular/diagnostics vitest-auto-spy/angular/doubles vitest-auto-spy/angular/matchers vitest-auto-spy/angular-http vitest-auto-spy/angular-router vitest-auto-spy/signal-forms vitest-auto-spy/nestjs vitest-auto-spy/react vitest-auto-spy/vue vitest-auto-spy/svelte vitest-auto-spy/setup vitest-auto-spy/zone vitest-auto-spy/eslint-plugin vitest-auto-spy/perf-reporter";
|
|
3426
3427
|
var EXPORTED_BY = {
|
|
3427
3428
|
AccessorImplementations: "0 1 2 3 4 12 20 21 22",
|
|
@@ -3701,6 +3702,7 @@ var EXPORTED_BY = {
|
|
|
3701
3702
|
PendingRequestsOptions: "13",
|
|
3702
3703
|
PerTestHandle: "23",
|
|
3703
3704
|
PlatformOverrides: "14",
|
|
3705
|
+
PluginRule: "25",
|
|
3704
3706
|
PropStubValue: "0 1 2 3 4 20 21 22",
|
|
3705
3707
|
PrototypePollutionReaction: "23",
|
|
3706
3708
|
provideActivatedRoute: "17",
|
|
@@ -4058,6 +4060,73 @@ function checkJasmineEra(profile) {
|
|
|
4058
4060
|
}
|
|
4059
4061
|
];
|
|
4060
4062
|
}
|
|
4063
|
+
var RULE_KEY = /["'][\w/@-]*\/no-redundant-mock-reset["']\s*:\s*\[/g;
|
|
4064
|
+
var CONFIG_FILE = /\bconfigFile\s*:\s*(["'`])([^"'`]+)\1/g;
|
|
4065
|
+
var OPTION_FLAG = /\b(?:clearMocks|mockReset|restoreMocks)\s*:/g;
|
|
4066
|
+
var ANY_FLAG = /\b(?:clearMocks|mockReset|restoreMocks)\b/;
|
|
4067
|
+
var DEFAULT_CALL = /\b(?:export\s+default|module\.exports\s*=)\s*([$A-Z_a-z][\w$.]*)\s*(?:<[^>]*>)?\s*\(/;
|
|
4068
|
+
var READABLE = /* @__PURE__ */ new Set(["defineConfig", "defineProject"]);
|
|
4069
|
+
function closingBracket(text, spans, open) {
|
|
4070
|
+
let depth = 0;
|
|
4071
|
+
for (let index = open; index < text.length; index += 1) {
|
|
4072
|
+
const span = spans.find((candidate) => candidate.start === index);
|
|
4073
|
+
if (span !== void 0) {
|
|
4074
|
+
index = span.end - 1;
|
|
4075
|
+
continue;
|
|
4076
|
+
}
|
|
4077
|
+
const char = text.charAt(index);
|
|
4078
|
+
depth += char === "[" ? 1 : char === "]" ? -1 : 0;
|
|
4079
|
+
if (depth === 0) {
|
|
4080
|
+
return index + 1;
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return text.length;
|
|
4084
|
+
}
|
|
4085
|
+
function inCode(spans, match, base) {
|
|
4086
|
+
return !isInsideLiteral(spans, base + match.index);
|
|
4087
|
+
}
|
|
4088
|
+
function unflaggedConfigFiles(text) {
|
|
4089
|
+
const spans = literalSpans(text);
|
|
4090
|
+
const found = [];
|
|
4091
|
+
for (const match of text.matchAll(RULE_KEY)) {
|
|
4092
|
+
if (spans.find((span) => span.start <= match.index && match.index < span.end)?.start !== match.index) {
|
|
4093
|
+
continue;
|
|
4094
|
+
}
|
|
4095
|
+
const open = match.index + match[0].length - 1;
|
|
4096
|
+
const options = text.slice(open, closingBracket(text, spans, open));
|
|
4097
|
+
const configFile = [...options.matchAll(CONFIG_FILE)].find((entry) => inCode(spans, entry, open))?.[2];
|
|
4098
|
+
const flagged = [...options.matchAll(OPTION_FLAG)].some((entry) => inCode(spans, entry, open));
|
|
4099
|
+
if (configFile !== void 0 && !flagged) {
|
|
4100
|
+
found.push(configFile);
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
return found;
|
|
4104
|
+
}
|
|
4105
|
+
function unreadableCallee(configText) {
|
|
4106
|
+
if (ANY_FLAG.test(configText)) {
|
|
4107
|
+
return void 0;
|
|
4108
|
+
}
|
|
4109
|
+
const callee = DEFAULT_CALL.exec(configText)?.[1];
|
|
4110
|
+
return callee === void 0 || READABLE.has(callee) ? void 0 : callee;
|
|
4111
|
+
}
|
|
4112
|
+
function checkMockResetConfig(profile, graph) {
|
|
4113
|
+
const findings = [];
|
|
4114
|
+
for (const [file, text] of graph.texts) {
|
|
4115
|
+
for (const configFile of unflaggedConfigFiles(text)) {
|
|
4116
|
+
const callee = unreadableCallee(readTextFile(resolve(profile.cwd, configFile)) ?? "");
|
|
4117
|
+
if (callee !== void 0) {
|
|
4118
|
+
findings.push({
|
|
4119
|
+
check: "mock-reset-config-unread",
|
|
4120
|
+
severity: "info",
|
|
4121
|
+
file,
|
|
4122
|
+
message: `\`no-redundant-mock-reset\` reads \`${configFile}\`, whose default export is a \`${callee}(\u2026)\` call: the rule reads the file as text, finds no \`clearMocks\` / \`mockReset\` / \`restoreMocks\`, and decides on the runner's defaults instead of what \`${callee}\` sets.`,
|
|
4123
|
+
fix: "Write the flags that config ends up with beside `configFile` in the rule options, e.g. `{ configFile, clearMocks: true }`; a flag written there wins over the file."
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
return findings;
|
|
4129
|
+
}
|
|
4061
4130
|
var BASE_CONFIGS2 = ["ts", "mts", "cts", "js", "mjs", "cjs"].map((extension) => `vitest-base.config.${extension}`);
|
|
4062
4131
|
var SHARED_BY_DEFAULT_FROM = [21];
|
|
4063
4132
|
var OPTION_WINS_FROM = [22, 1];
|
|
@@ -4760,6 +4829,7 @@ function runDoctor(profile) {
|
|
|
4760
4829
|
...checkHelperEntry(profile, graph),
|
|
4761
4830
|
...checkUnawaitedHelper(profile, graph),
|
|
4762
4831
|
...checkModuleMockLeak(profile, graph),
|
|
4832
|
+
...checkMockResetConfig(profile, graph),
|
|
4763
4833
|
...checkVitest5Removed(profile, graph),
|
|
4764
4834
|
...checkVitest5ClearMocks(profile, graph),
|
|
4765
4835
|
...checkVitest5Available(profile),
|
|
@@ -4978,23 +5048,24 @@ function rxjsBullet(profile, facts) {
|
|
|
4978
5048
|
}
|
|
4979
5049
|
const target = facts.setupFile ?? profile.setupFiles[0] ?? "the test setup file";
|
|
4980
5050
|
return `- Observable spies (\`nextWith\`, \`observablePropsToSpyOn\`) need \`import 'vitest-auto-spy/rxjs'\` once, in
|
|
4981
|
-
\`${target}\`. Without it they throw "Observable spies require rxjs".`;
|
|
5051
|
+
\`${target}\` or a module / \`.d.ts\` it loads. Without it they throw "Observable spies require rxjs".`;
|
|
4982
5052
|
}
|
|
4983
5053
|
function companionsBullet(facts) {
|
|
4984
5054
|
if (facts.companions.length === 0) {
|
|
4985
5055
|
return void 0;
|
|
4986
5056
|
}
|
|
4987
5057
|
const list = facts.companions.map((entry) => `\`${entry}\``).join(", ");
|
|
4988
|
-
return `- Setup helpers also come from ${list},
|
|
4989
|
-
|
|
5058
|
+
return `- Setup helpers also come from ${list}, separate entries since
|
|
5059
|
+
5.21.0 that do not re-export the core.`;
|
|
4990
5060
|
}
|
|
4991
5061
|
function renderBody(profile, facts = NO_FACTS) {
|
|
4992
5062
|
const lines = [
|
|
4993
5063
|
"## Tests that use `vitest-auto-spy`",
|
|
4994
5064
|
"",
|
|
4995
|
-
"
|
|
4996
|
-
"`vitest-auto-spy`
|
|
4997
|
-
"
|
|
5065
|
+
"For a spec that uses `vitest-auto-spy`, read the short map",
|
|
5066
|
+
"`node_modules/vitest-auto-spy/AGENTS.md` whole, then only the `agent-docs/*.md` files it names.",
|
|
5067
|
+
"On a failure: `grep -n -F '<error text>' node_modules/vitest-auto-spy/agent-docs/errors.md`.",
|
|
5068
|
+
"Where docs and code disagree, `dist/*.d.ts` wins.",
|
|
4998
5069
|
"",
|
|
4999
5070
|
`- This repository imports from \`${profile.entry}\`. Each entry registers its mock adapter on`,
|
|
5000
5071
|
" import, so the wrong one leaves the wrong adapter installed and the spies fail at runtime.",
|
|
@@ -5002,8 +5073,7 @@ function renderBody(profile, facts = NO_FACTS) {
|
|
|
5002
5073
|
companionsBullet(facts),
|
|
5003
5074
|
rxjsBullet(profile, facts),
|
|
5004
5075
|
"- `methodsToSpyOn` **adds** to the auto-discovered prototype methods; the exhaustive whitelist is",
|
|
5005
|
-
" `onlyMethodsToSpyOn`. For methods
|
|
5006
|
-
" `createAutoMock<T>()`.",
|
|
5076
|
+
" `onlyMethodsToSpyOn`. For methods on the instance, not the prototype, use `createAutoMock<T>()`.",
|
|
5007
5077
|
"- `Spy<T>` is a mapped type and drops `#private` members, so it is not assignable to `T`. Declare",
|
|
5008
5078
|
" the variable as `Spy<T>`, or pass `asInstance(spy)` where the real type is required.",
|
|
5009
5079
|
"- `npx vitest-auto-spy doctor` reports suite-level defects that never fail a run."
|
|
@@ -6211,7 +6281,7 @@ function nothingOverBudgetNote(gate = GATE_DEFAULTS, runFailed = false) {
|
|
|
6211
6281
|
return `Nothing over budget: no file over its budget and no test body over ${formatMs(gate.maxTestMs)}. ${verdict}`;
|
|
6212
6282
|
}
|
|
6213
6283
|
var DOMINATES = 0.3;
|
|
6214
|
-
var
|
|
6284
|
+
var CONFIG_FILE2 = /(?:^|\/)vite(?:st)?[\w.-]*\.config\.[cm]?[jt]s$/;
|
|
6215
6285
|
var NO_ISOLATION = /\bisolate\s*:\s*false/;
|
|
6216
6286
|
var JSDOM = /\benvironment\s*:\s*["'`]jsdom["'`]/;
|
|
6217
6287
|
var HAPPY_DOM = /happy-dom/;
|
|
@@ -6223,7 +6293,7 @@ var LARGE_RUN_MS = 6e4;
|
|
|
6223
6293
|
function configCode(graph) {
|
|
6224
6294
|
const configs = [];
|
|
6225
6295
|
for (const [file, text] of graph.texts) {
|
|
6226
|
-
if (!
|
|
6296
|
+
if (!CONFIG_FILE2.test(file)) {
|
|
6227
6297
|
continue;
|
|
6228
6298
|
}
|
|
6229
6299
|
configs.push([
|
package/dist/console.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useVitestAdapter } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { useVitestAdapter } from './chunk-YNXQ2WFH.js';
|
|
2
|
+
import './chunk-B6C3K27C.js';
|
|
3
3
|
import './chunk-YHDBRBGU.js';
|
|
4
4
|
import './chunk-TXDBDMIL.js';
|
|
5
5
|
import './chunk-FOL5RH22.js';
|
|
6
6
|
import './chunk-PC3FAZT3.js';
|
|
7
|
-
import { createFunctionSpy } from './chunk-
|
|
7
|
+
import { createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
8
8
|
import './chunk-Q7L4AWI7.js';
|
|
9
9
|
import './chunk-M3NTXLZG.js';
|
|
10
10
|
import './chunk-5FQZGJLJ.js';
|
package/dist/eslint-plugin.d.cts
CHANGED
|
@@ -11,6 +11,7 @@ declare const plugin: Plugin.AutoSpyEslintPlugin;
|
|
|
11
11
|
declare namespace plugin {
|
|
12
12
|
export type AutoSpyEslintPlugin = Plugin.AutoSpyEslintPlugin;
|
|
13
13
|
export type FlatConfig = Plugin.FlatConfig;
|
|
14
|
+
export type PluginRule = Plugin.PluginRule;
|
|
14
15
|
export type RuleSeverity = Plugin.RuleSeverity;
|
|
15
16
|
}
|
|
16
17
|
|
package/dist/eslint-plugin.d.ts
CHANGED
|
@@ -248,12 +248,24 @@ interface RuleModule {
|
|
|
248
248
|
type RuleSeverity = 'error' | 'off' | 'warn';
|
|
249
249
|
/** A flat-config object: the plugin under its name, plus the rules it turns on. */
|
|
250
250
|
interface FlatConfig {
|
|
251
|
-
plugins: Record<string,
|
|
251
|
+
plugins: Record<string, AutoSpyEslintPlugin>;
|
|
252
252
|
rules: Record<string, RuleSeverity>;
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* One visitor of a published rule. A method signature is bivariant in its parameter, which lets a
|
|
256
|
+
* visitor typed on its selector's node fit ESLint's `(...args: any[]) => void`.
|
|
257
|
+
*/
|
|
258
|
+
type PluginRuleVisitor = {
|
|
259
|
+
visit(node: unknown): void;
|
|
260
|
+
}['visit'];
|
|
261
|
+
/** A rule as the plugin publishes it: ESLint calls `create`, so no caller needs its context type. */
|
|
262
|
+
interface PluginRule {
|
|
263
|
+
meta: RuleModule['meta'];
|
|
264
|
+
create(context: never): Record<string, PluginRuleVisitor>;
|
|
265
|
+
}
|
|
254
266
|
/** The plugin object, as ESLint consumes it. */
|
|
255
267
|
interface AutoSpyEslintPlugin {
|
|
256
|
-
rules: Record<string,
|
|
268
|
+
rules: Record<string, PluginRule>;
|
|
257
269
|
configs: {
|
|
258
270
|
recommended: FlatConfig;
|
|
259
271
|
strict: FlatConfig;
|
|
@@ -262,4 +274,4 @@ interface AutoSpyEslintPlugin {
|
|
|
262
274
|
}
|
|
263
275
|
declare const plugin: AutoSpyEslintPlugin;
|
|
264
276
|
|
|
265
|
-
export { type AutoSpyEslintPlugin, type FlatConfig, type RuleSeverity, plugin as default };
|
|
277
|
+
export { type AutoSpyEslintPlugin, type FlatConfig, type PluginRule, type RuleSeverity, plugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1609,11 +1609,15 @@ function installSettledResultsPolyfill(mockFn) {
|
|
|
1609
1609
|
// src/lib/stack-frames.ts
|
|
1610
1610
|
var FOREIGN_FRAME = /node_modules|node:internal|\(node:/;
|
|
1611
1611
|
var LIBRARY_FRAME = /[/\\]vitest-auto-spy[/\\]dist[/\\]|[/\\]\.vite[/\\]deps[^/\\]*[/\\]vitest-auto-spy[^/\\]*\.js/;
|
|
1612
|
+
var HELPER_FRAME = /\b__VITEST_HELPER__\b/;
|
|
1613
|
+
function isLibraryFrame(frame) {
|
|
1614
|
+
return LIBRARY_FRAME.test(frame) || HELPER_FRAME.test(frame);
|
|
1615
|
+
}
|
|
1612
1616
|
function stackFrames(stack) {
|
|
1613
1617
|
return String(stack).split("\n").filter((line) => /^\s*at\s/.test(line)).map((line) => line.trim());
|
|
1614
1618
|
}
|
|
1615
1619
|
function ownFrames(frames, limit) {
|
|
1616
|
-
const outside = frames.filter((frame) => !
|
|
1620
|
+
const outside = frames.filter((frame) => !isLibraryFrame(frame));
|
|
1617
1621
|
const own = outside.filter((frame) => !FOREIGN_FRAME.test(frame));
|
|
1618
1622
|
const shown = [own, outside].find((candidates) => candidates.length > 0) ?? frames;
|
|
1619
1623
|
return shown.slice(0, limit);
|
|
@@ -3243,12 +3247,15 @@ function looksLikeLiveHostObject(instance) {
|
|
|
3243
3247
|
continue;
|
|
3244
3248
|
}
|
|
3245
3249
|
if (constructor.name === "EventTarget") {
|
|
3246
|
-
return engineLevel;
|
|
3250
|
+
return engineLevel || isEnginePrivateEventTarget(constructor);
|
|
3247
3251
|
}
|
|
3248
3252
|
engineLevel ||= Reflect.get(globalThis, constructor.name) === constructor;
|
|
3249
3253
|
}
|
|
3250
3254
|
return false;
|
|
3251
3255
|
}
|
|
3256
|
+
function isEnginePrivateEventTarget(constructor) {
|
|
3257
|
+
return typeof Node !== "undefined" && constructor !== Reflect.get(globalThis, "EventTarget") && Reflect.getPrototypeOf(Node.prototype) === Reflect.get(constructor, "prototype");
|
|
3258
|
+
}
|
|
3252
3259
|
function warnOnUndiscriminatedHostDiscovery(label, listedAdditions) {
|
|
3253
3260
|
const additions = listedAdditions ? "The methods listed (a bare array is methodsToSpyOn) are spied in addition to that discovery, not instead of it. " : "";
|
|
3254
3261
|
reportMisconfiguration(
|
package/dist/jasmine.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { enableJasmineCompat } from './chunk-3ZBRBPOL.js';
|
|
2
2
|
export { enableJasmineCompat } from './chunk-3ZBRBPOL.js';
|
|
3
|
-
import { createSpyFromClass } from './chunk-
|
|
4
|
-
import { useVitestAdapter } from './chunk-
|
|
5
|
-
import './chunk-
|
|
3
|
+
import { createSpyFromClass } from './chunk-6KP5QMMV.js';
|
|
4
|
+
import { useVitestAdapter } from './chunk-YNXQ2WFH.js';
|
|
5
|
+
import './chunk-B6C3K27C.js';
|
|
6
6
|
import './chunk-YHDBRBGU.js';
|
|
7
7
|
import './chunk-TXDBDMIL.js';
|
|
8
8
|
import './chunk-FOL5RH22.js';
|
|
9
9
|
import './chunk-PC3FAZT3.js';
|
|
10
|
-
import { createFunctionSpy } from './chunk-
|
|
10
|
+
import { createFunctionSpy } from './chunk-RYFF55PV.js';
|
|
11
11
|
import { reportMisconfiguration, misconfigurationThrows } from './chunk-Q7L4AWI7.js';
|
|
12
12
|
import './chunk-M3NTXLZG.js';
|
|
13
13
|
import { jasmineGlobals, jasmineClock, jasmineAutoSpies, jasmineTimeout } from './chunk-5FQZGJLJ.js';
|
package/dist/nestjs.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { createSpyForToken } from './chunk-
|
|
2
|
-
export { trackInjections } from './chunk-
|
|
3
|
-
import { createSpyFromClass } from './chunk-
|
|
4
|
-
import { useVitestAdapter } from './chunk-
|
|
5
|
-
import './chunk-
|
|
1
|
+
import { createSpyForToken } from './chunk-2TZCJ3MM.js';
|
|
2
|
+
export { trackInjections } from './chunk-2TZCJ3MM.js';
|
|
3
|
+
import { createSpyFromClass } from './chunk-6KP5QMMV.js';
|
|
4
|
+
import { useVitestAdapter } from './chunk-YNXQ2WFH.js';
|
|
5
|
+
import './chunk-B6C3K27C.js';
|
|
6
6
|
import './chunk-YHDBRBGU.js';
|
|
7
7
|
import './chunk-TXDBDMIL.js';
|
|
8
8
|
import './chunk-FOL5RH22.js';
|
|
9
9
|
import './chunk-PC3FAZT3.js';
|
|
10
|
-
import './chunk-
|
|
10
|
+
import './chunk-RYFF55PV.js';
|
|
11
11
|
import './chunk-Q7L4AWI7.js';
|
|
12
12
|
import './chunk-M3NTXLZG.js';
|
|
13
13
|
import { nestUnitRefusals } from './chunk-5FQZGJLJ.js';
|
package/dist/node.cjs
CHANGED
|
@@ -1240,11 +1240,15 @@ function installSettledResultsPolyfill(mockFn) {
|
|
|
1240
1240
|
// src/lib/stack-frames.ts
|
|
1241
1241
|
var FOREIGN_FRAME = /node_modules|node:internal|\(node:/;
|
|
1242
1242
|
var LIBRARY_FRAME = /[/\\]vitest-auto-spy[/\\]dist[/\\]|[/\\]\.vite[/\\]deps[^/\\]*[/\\]vitest-auto-spy[^/\\]*\.js/;
|
|
1243
|
+
var HELPER_FRAME = /\b__VITEST_HELPER__\b/;
|
|
1244
|
+
function isLibraryFrame(frame) {
|
|
1245
|
+
return LIBRARY_FRAME.test(frame) || HELPER_FRAME.test(frame);
|
|
1246
|
+
}
|
|
1243
1247
|
function stackFrames(stack) {
|
|
1244
1248
|
return String(stack).split("\n").filter((line) => /^\s*at\s/.test(line)).map((line) => line.trim());
|
|
1245
1249
|
}
|
|
1246
1250
|
function ownFrames(frames, limit) {
|
|
1247
|
-
const outside = frames.filter((frame) => !
|
|
1251
|
+
const outside = frames.filter((frame) => !isLibraryFrame(frame));
|
|
1248
1252
|
const own = outside.filter((frame) => !FOREIGN_FRAME.test(frame));
|
|
1249
1253
|
const shown = [own, outside].find((candidates) => candidates.length > 0) ?? frames;
|
|
1250
1254
|
return shown.slice(0, limit);
|
|
@@ -2863,12 +2867,15 @@ function looksLikeLiveHostObject(instance) {
|
|
|
2863
2867
|
continue;
|
|
2864
2868
|
}
|
|
2865
2869
|
if (constructor.name === "EventTarget") {
|
|
2866
|
-
return engineLevel;
|
|
2870
|
+
return engineLevel || isEnginePrivateEventTarget(constructor);
|
|
2867
2871
|
}
|
|
2868
2872
|
engineLevel ||= Reflect.get(globalThis, constructor.name) === constructor;
|
|
2869
2873
|
}
|
|
2870
2874
|
return false;
|
|
2871
2875
|
}
|
|
2876
|
+
function isEnginePrivateEventTarget(constructor) {
|
|
2877
|
+
return typeof Node !== "undefined" && constructor !== Reflect.get(globalThis, "EventTarget") && Reflect.getPrototypeOf(Node.prototype) === Reflect.get(constructor, "prototype");
|
|
2878
|
+
}
|
|
2872
2879
|
function warnOnUndiscriminatedHostDiscovery(label, listedAdditions) {
|
|
2873
2880
|
const additions = listedAdditions ? "The methods listed (a bare array is methodsToSpyOn) are spied in addition to that discovery, not instead of it. " : "";
|
|
2874
2881
|
reportMisconfiguration(
|
package/dist/node.js
CHANGED
|
@@ -1129,11 +1129,15 @@ function installSettledResultsPolyfill(mockFn) {
|
|
|
1129
1129
|
// src/lib/stack-frames.ts
|
|
1130
1130
|
var FOREIGN_FRAME = /node_modules|node:internal|\(node:/;
|
|
1131
1131
|
var LIBRARY_FRAME = /[/\\]vitest-auto-spy[/\\]dist[/\\]|[/\\]\.vite[/\\]deps[^/\\]*[/\\]vitest-auto-spy[^/\\]*\.js/;
|
|
1132
|
+
var HELPER_FRAME = /\b__VITEST_HELPER__\b/;
|
|
1133
|
+
function isLibraryFrame(frame) {
|
|
1134
|
+
return LIBRARY_FRAME.test(frame) || HELPER_FRAME.test(frame);
|
|
1135
|
+
}
|
|
1132
1136
|
function stackFrames(stack) {
|
|
1133
1137
|
return String(stack).split("\n").filter((line) => /^\s*at\s/.test(line)).map((line) => line.trim());
|
|
1134
1138
|
}
|
|
1135
1139
|
function ownFrames(frames, limit) {
|
|
1136
|
-
const outside = frames.filter((frame) => !
|
|
1140
|
+
const outside = frames.filter((frame) => !isLibraryFrame(frame));
|
|
1137
1141
|
const own = outside.filter((frame) => !FOREIGN_FRAME.test(frame));
|
|
1138
1142
|
const shown = [own, outside].find((candidates) => candidates.length > 0) ?? frames;
|
|
1139
1143
|
return shown.slice(0, limit);
|
|
@@ -2757,12 +2761,15 @@ function looksLikeLiveHostObject(instance) {
|
|
|
2757
2761
|
continue;
|
|
2758
2762
|
}
|
|
2759
2763
|
if (constructor.name === "EventTarget") {
|
|
2760
|
-
return engineLevel;
|
|
2764
|
+
return engineLevel || isEnginePrivateEventTarget(constructor);
|
|
2761
2765
|
}
|
|
2762
2766
|
engineLevel ||= Reflect.get(globalThis, constructor.name) === constructor;
|
|
2763
2767
|
}
|
|
2764
2768
|
return false;
|
|
2765
2769
|
}
|
|
2770
|
+
function isEnginePrivateEventTarget(constructor) {
|
|
2771
|
+
return typeof Node !== "undefined" && constructor !== Reflect.get(globalThis, "EventTarget") && Reflect.getPrototypeOf(Node.prototype) === Reflect.get(constructor, "prototype");
|
|
2772
|
+
}
|
|
2766
2773
|
function warnOnUndiscriminatedHostDiscovery(label, listedAdditions) {
|
|
2767
2774
|
const additions = listedAdditions ? "The methods listed (a bare array is methodsToSpyOn) are spied in addition to that discovery, not instead of it. " : "";
|
|
2768
2775
|
reportMisconfiguration(
|
package/dist/rstest.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-
|
|
1
|
+
export { adoptMock, asInstance, asInstances, asSpy, assertMocked, captureArg, createFixture, createFixtureFactory, createLog, createMock, createSpyClass, createSpyFromInstance, describeDuplicateCopies, expectAllEmissions, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, getPackageCopies, mockConstructor, mockDeep, moduleNamespace, narrow, outOfType, restoreSpiedInstance, setEmissionTimeout, settleDynamicImport, spyOnOwnMethod, spyOnVoidMethod, stubConstructor, withOverrides } from './chunk-5TYNQH5Q.js';
|
|
2
2
|
export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, reportPropsOutsideHooks, restoreMockedProps } from './chunk-FWXDSPZD.js';
|
|
3
|
-
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-
|
|
3
|
+
export { autoMocked, clearAutoSpy, clearAutoSpyDefaults, createAutoMock, createSpyFromClass, registerAutoSpyDefaults, resetAutoSpy } from './chunk-6KP5QMMV.js';
|
|
4
4
|
import './chunk-W5EXSI22.js';
|
|
5
|
-
import { createRunnerMockAdapter } from './chunk-
|
|
5
|
+
import { createRunnerMockAdapter } from './chunk-B6C3K27C.js';
|
|
6
6
|
import './chunk-TXDBDMIL.js';
|
|
7
7
|
import './chunk-FOL5RH22.js';
|
|
8
8
|
import './chunk-PC3FAZT3.js';
|
|
9
|
-
export { createFunctionSpy, errorHandler } from './chunk-
|
|
9
|
+
export { createFunctionSpy, errorHandler } from './chunk-RYFF55PV.js';
|
|
10
10
|
import './chunk-Q7L4AWI7.js';
|
|
11
11
|
import './chunk-M3NTXLZG.js';
|
|
12
12
|
import './chunk-5FQZGJLJ.js';
|
package/dist/setup.js
CHANGED
|
@@ -1245,11 +1245,15 @@ function storagePrototype() {
|
|
|
1245
1245
|
// src/lib/stack-frames.ts
|
|
1246
1246
|
var FOREIGN_FRAME = /node_modules|node:internal|\(node:/;
|
|
1247
1247
|
var LIBRARY_FRAME = /[/\\]vitest-auto-spy[/\\]dist[/\\]|[/\\]\.vite[/\\]deps[^/\\]*[/\\]vitest-auto-spy[^/\\]*\.js/;
|
|
1248
|
+
var HELPER_FRAME = /\b__VITEST_HELPER__\b/;
|
|
1249
|
+
function isLibraryFrame(frame) {
|
|
1250
|
+
return LIBRARY_FRAME.test(frame) || HELPER_FRAME.test(frame);
|
|
1251
|
+
}
|
|
1248
1252
|
function stackFrames(stack) {
|
|
1249
1253
|
return String(stack).split("\n").filter((line) => /^\s*at\s/.test(line)).map((line) => line.trim());
|
|
1250
1254
|
}
|
|
1251
1255
|
function ownFrames(frames, limit) {
|
|
1252
|
-
const outside = frames.filter((frame) => !
|
|
1256
|
+
const outside = frames.filter((frame) => !isLibraryFrame(frame));
|
|
1253
1257
|
const own = outside.filter((frame) => !FOREIGN_FRAME.test(frame));
|
|
1254
1258
|
const shown = [own, outside].find((candidates) => candidates.length > 0) ?? frames;
|
|
1255
1259
|
return shown.slice(0, limit);
|
|
@@ -1442,12 +1446,24 @@ function recordEntry(tracking, type, listener, options) {
|
|
|
1442
1446
|
function forgetEntries(tracking, type, listener, capture) {
|
|
1443
1447
|
tracking.entries = tracking.entries.filter((entry) => entry.type !== type || entry.listener !== listener || entry.capture !== capture);
|
|
1444
1448
|
}
|
|
1449
|
+
var OWN_MODULE_FRAME = /stray-listeners\.[jt]s/;
|
|
1450
|
+
var ENVIRONMENT_FRAME = /[/\\]node_modules[/\\](?:jsdom|happy-dom|@asamuzakjp[/\\][^/\\]+)[/\\]/;
|
|
1451
|
+
var environmentVerdicts = /* @__PURE__ */ new WeakMap();
|
|
1452
|
+
function isEnvironmentEntry(entry) {
|
|
1453
|
+
let verdict = environmentVerdicts.get(entry);
|
|
1454
|
+
if (verdict === void 0) {
|
|
1455
|
+
const caller = stackFrames(entry.trace.stack).find((frame) => !OWN_MODULE_FRAME.test(frame) && !isLibraryFrame(frame));
|
|
1456
|
+
verdict = caller !== void 0 && ENVIRONMENT_FRAME.test(caller);
|
|
1457
|
+
environmentVerdicts.set(entry, verdict);
|
|
1458
|
+
}
|
|
1459
|
+
return verdict;
|
|
1460
|
+
}
|
|
1445
1461
|
function strayEntries(tracking) {
|
|
1446
1462
|
const { baseline } = tracking;
|
|
1447
1463
|
if (!baseline) {
|
|
1448
1464
|
return [];
|
|
1449
1465
|
}
|
|
1450
|
-
return tracking.entries.filter((entry) => !baseline.has(entry));
|
|
1466
|
+
return tracking.entries.filter((entry) => !baseline.has(entry) && !isEnvironmentEntry(entry));
|
|
1451
1467
|
}
|
|
1452
1468
|
function installTracking({ name, target }) {
|
|
1453
1469
|
const host = target;
|
|
@@ -1549,7 +1565,6 @@ function countStrayListeners(targets) {
|
|
|
1549
1565
|
}
|
|
1550
1566
|
return total;
|
|
1551
1567
|
}
|
|
1552
|
-
var OWN_MODULE_FRAME = /stray-listeners\.[jt]s/;
|
|
1553
1568
|
function describeEntry(name, entry) {
|
|
1554
1569
|
return { target: name, type: entry.type, ...describeOriginOf(entry, OWN_MODULE_FRAME) };
|
|
1555
1570
|
}
|
|
@@ -456,8 +456,10 @@ interface StableOptions {
|
|
|
456
456
|
* one component. On expiry this throws the cause instead, and names the two things that produce it.
|
|
457
457
|
*
|
|
458
458
|
* Pass `{ label }` when a spec awaits more than one fixture, so the failure says which.
|
|
459
|
+
*
|
|
460
|
+
* Any fixture with `whenStable()` is taken — Angular 22.2's `TestBed.createDirective` fixture too.
|
|
459
461
|
*/
|
|
460
|
-
declare function stable(fixture: ComponentFixture<unknown>, options?: StableOptions): Promise<void>;
|
|
462
|
+
declare function stable(fixture: Pick<ComponentFixture<unknown>, 'whenStable'>, options?: StableOptions): Promise<void>;
|
|
461
463
|
|
|
462
464
|
/**
|
|
463
465
|
* `setInputs` — change a component's inputs after it is rendered, and let Angular catch up.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitest-auto-spy",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.38.0",
|
|
4
4
|
"description": "Auto-generate fully-typed test spies from a class — across Vitest, Bun, node:test and Rstest, with Angular/NestJS/React/Vue/Svelte recipes. Drop-in replacement for jest-auto-spies and jasmine-auto-spies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auto-mock",
|
|
@@ -110,6 +110,12 @@ describe('TaskService', () => {
|
|
|
110
110
|
});
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
`type Spy`, `provideAutoSpy` and `injectSpy` come from `vitest-auto-spy/angular`. Of the core it
|
|
114
|
+
re-exports only the `Spy<T>` type, the `mock*Prop` helpers and the `expectEmission` family;
|
|
115
|
+
`createSpyFromClass`, `createMock`, `createAutoMock`, `spyOnVoidMethod`, `spyOnOwnMethod`,
|
|
116
|
+
`stubConstructor` and `asInstance` stay on `vitest-auto-spy` — keep that second import line instead
|
|
117
|
+
of folding the names into the `/angular` one.
|
|
118
|
+
|
|
113
119
|
One `configureTestingModule` per `describe` — reconfiguring per `it()` recompiles the module every
|
|
114
120
|
test. Use `mockSignalProp(service, 'count', 0)` for a signal on a collaborator — a member that already is
|
|
115
121
|
a `signal()`, `model()`, `linkedSignal()` **or a `signal().asReadonly()` view** is written through rather
|
|
@@ -281,7 +287,7 @@ it('loads', async () => {
|
|
|
281
287
|
| the same 100-line model literal copied into eight specs (`TS1117`) | one `createFixtureFactory<T>(defaults)`; specs call it with what they change |
|
|
282
288
|
| `'params' in link` ladders, or a cast, to pick a union branch | `narrow.byKey(link, 'params')` / `narrow.observable(x)` |
|
|
283
289
|
| `{ ...modelInstance, flag: true }` losing every getter | `withOverrides(modelInstance, { flag: true })` |
|
|
284
|
-
| `NG0303` / `NG0304` / silence from a directive spec | `createDirectiveHost({ template, scope: [Module] })`
|
|
290
|
+
| `NG0303` / `NG0304` / silence from a directive spec | `createDirectiveHost({ template, scope: [Module] })`; Angular ≥ 22.2, no host markup needed: `TestBed.createDirective(Dir, { tagName, bindings })`, which `stable` takes |
|
|
285
291
|
| a hand-written `class MockChartComponent` restating a child's selector | `createComponentStub(ChartComponent)` (`/angular`) — selector, inputs, outputs read from `ɵcmp` |
|
|
286
292
|
| a `TestingStorage` class for `localStorage` / `sessionStorage` | `stubWebStorage('localStorage', { items })` from `/dom-stubs` — `snapshot()` to assert |
|
|
287
293
|
| a hand-written `MockWorker` whose `addEventListener` sets `onmessage` | `stubWorker({ respond })` from `/dom-stubs` — `last.emit(data)`, `last.messages` |
|
|
@@ -544,7 +550,7 @@ from `vitest-auto-spy/angular-router` rather than at `provideAutoSpy`.
|
|
|
544
550
|
|
|
545
551
|
**`no-self-called-spy` reports a test that calls the spied method itself and then asserts that it was called** — `vi.spyOn(obj, 'm')`, then `obj.m(…)` written by the test body after it, then a positive `toHaveBeenCalled*`. Such a test proves that `emit` calls `emit`: delete the template binding or subscription its title names and it stays green. Drive the real trigger instead and keep the assertion. Order decides it, so a call written **before** the spy is arrangement and is never reported; neither is a negated matcher or `toHaveBeenCalledTimes(0)`, a call whose record a `mockClear` / `vi.clearAllMocks()` drops before the assertion reads it, an assertion whose arguments the call did not pass, a spy installed in a hook, or a call made from inside a callback.
|
|
546
552
|
|
|
547
|
-
**`no-redundant-mock-reset` reports a mock reset in a hook that the runner already performs** — `vi.clearAllMocks()` / `vi.resetAllMocks()` / `vi.restoreAllMocks()` and the per-mock `mockClear()` / `mockReset()` / `mockRestore()` — as the first statement of a `beforeEach` that no other `beforeEach` precedes, or a clear as the last statement of an `afterEach`. Vitest resets in `onBeforeTryTask`, ahead of every `beforeEach` chain and never after a test, so a reset that anything ran before, or a restore in `afterEach` / `afterAll` (the only thing that takes the last test's spies off before the `afterAll` hooks), is left alone. **It is silent until it knows the configuration**: options first — `['error', { clearMocks: true, restoreMocks: true }]`, or `{ configFile: 'path/to/runner.config.ts' }` for a runner config the search cannot find — then a `vitest.config.*` / `vite.config.*` searched upwards from the file and read as text; with neither, it reports nothing. The flag has to match the call, not the family: `restoreMocks` walks only the spies `vi.spyOn` installed, so it makes a `vi.clearAllMocks()` dead only where the receiver is such a spy. `--fix` deletes the line only in a file whose only before-hook it is, and offers a suggestion everywhere else; a reset in the middle of a test body is never reported, because there it separates two arrangements inside one test.
|
|
553
|
+
**`no-redundant-mock-reset` reports a mock reset in a hook that the runner already performs** — `vi.clearAllMocks()` / `vi.resetAllMocks()` / `vi.restoreAllMocks()` and the per-mock `mockClear()` / `mockReset()` / `mockRestore()` — as the first statement of a `beforeEach` that no other `beforeEach` precedes, or a clear as the last statement of an `afterEach`. Vitest resets in `onBeforeTryTask`, ahead of every `beforeEach` chain and never after a test, so a reset that anything ran before, or a restore in `afterEach` / `afterAll` (the only thing that takes the last test's spies off before the `afterAll` hooks), is left alone. **It is silent until it knows the configuration**: options first — `['error', { clearMocks: true, restoreMocks: true }]`, or `{ configFile: 'path/to/runner.config.ts' }` for a runner config the search cannot find — then a `vitest.config.*` / `vite.config.*` searched upwards from the file and read as text; with neither, it reports nothing. A config that leaves `clearMocks` out counts it on from Vitest 5, whose default it is; a config a factory or `mergeConfig` assembles in another module is not read through, so write its flags beside it — `{ configFile: 'vitest.config.ts', clearMocks: true }`. Pass only what the runner config sets: `setupAutoSpy({ restoreMocks: true })` restores in an `afterEach`, after the test, which is not the runner's `restoreMocks`. The flag has to match the call, not the family: `restoreMocks` walks only the spies `vi.spyOn` installed, so it makes a `vi.clearAllMocks()` dead only where the receiver is such a spy. `--fix` deletes the line only in a file whose only before-hook it is, and offers a suggestion everywhere else; a reset in the middle of a test body is never reported, because there it separates two arrangements inside one test.
|
|
548
554
|
|
|
549
555
|
**`no-unasserted-argument` reports a bare `expect(spy).toHaveBeenCalled()` where the file itself says the arguments are the point** — either the same subject is pinned with `toHaveBeenCalledWith(…)` in another test of the file, or the test's title says `with` and its body asserts nothing but bare calls. Narrower than `vitest/prefer-called-with` on purpose: on one 2032-file suite that reports 1941 times in 360 files and this one 175 in 90. `not.toHaveBeenCalled()` and the counting matchers are never reported. `warn` rather than `error`, because the repair is the argument list the test should have named — `toHaveBeenCalledWith(…)`, `toHaveBeenCalledExactlyOnceWith(…)`, or `mustBeCalledWith(…)` where the double is configured — and that is the one thing the rule cannot write.
|
|
550
556
|
|