vitest-auto-spy 5.41.0 → 5.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +104 -1
  2. package/README.md +66 -39
  3. package/agent-docs/angular.md +3 -3
  4. package/agent-docs/checklist.md +18 -4
  5. package/agent-docs/configuration.md +5 -2
  6. package/agent-docs/errors.md +1 -0
  7. package/agent-docs/factories.md +7 -6
  8. package/dist/angular-diagnostics.js +3 -3
  9. package/dist/angular-doubles.d.ts +1 -1
  10. package/dist/angular-doubles.js +3 -3
  11. package/dist/angular-router.d.ts +11 -1
  12. package/dist/angular-router.js +12 -3
  13. package/dist/angular.d.ts +7 -7
  14. package/dist/bun-angular.d.ts +5 -5
  15. package/dist/bun-angular.js +6 -6
  16. package/dist/bun.d.ts +5 -5
  17. package/dist/bun.js +3 -3
  18. package/dist/{chunk-O55MVK7N.js → chunk-25QOHNGU.js} +1 -1
  19. package/dist/{chunk-HUS2MHK5.js → chunk-CENALW7R.js} +24 -21
  20. package/dist/{chunk-T7EGA4G4.js → chunk-EYXARTWD.js} +152 -98
  21. package/dist/{chunk-IE4NI2OQ.js → chunk-J2C3KRTC.js} +39 -17
  22. package/dist/{chunk-6ZGH56G4.js → chunk-J4IJCTHT.js} +1 -1
  23. package/dist/{chunk-OWDUWUAO.js → chunk-MHN6GMXP.js} +1 -1
  24. package/dist/{chunk-DG5EP3PO.js → chunk-RYEBG2KB.js} +2 -2
  25. package/dist/cli.js +1309 -472
  26. package/dist/console.d.ts +1 -1
  27. package/dist/console.js +3 -3
  28. package/dist/dom-stubs.d.ts +2 -2
  29. package/dist/dom-stubs.js +38 -16
  30. package/dist/{expect-emission-CwosjG6t.d.ts → expect-emission-D273986K.d.ts} +1 -1
  31. package/dist/index.d.ts +4 -4
  32. package/dist/index.js +214 -135
  33. package/dist/jasmine-compat.d.ts +1 -1
  34. package/dist/jasmine.d.ts +2 -2
  35. package/dist/jasmine.js +4 -4
  36. package/dist/nestjs.d.ts +2 -2
  37. package/dist/nestjs.js +6 -6
  38. package/dist/node.cjs +174 -117
  39. package/dist/node.d.ts +4 -4
  40. package/dist/node.js +175 -118
  41. package/dist/{package-identity-CBgwC1T6.d.ts → package-identity-BnqwTQIn.d.ts} +1 -1
  42. package/dist/{prop-mock-C8PJ-Vo8.d.ts → prop-mock-Cz0yKWEP.d.ts} +1 -1
  43. package/dist/react.d.ts +4 -4
  44. package/dist/rstest.d.ts +4 -4
  45. package/dist/rstest.js +4 -4
  46. package/dist/rxjs.d.ts +2 -2
  47. package/dist/setup.d.ts +3 -3
  48. package/dist/setup.js +38 -16
  49. package/dist/svelte.d.ts +4 -4
  50. package/dist/{track-injections-Bp8TgLjG.d.ts → track-injections-BTJKOqWz.d.ts} +1 -1
  51. package/dist/{track-signal-runs-DUZUFWf-.d.ts → track-signal-runs-bs2umXNE.d.ts} +3 -3
  52. package/dist/{types-DJ0OGc3C.d.ts → types-CyRUgJVd.d.ts} +17 -15
  53. package/dist/vue.d.ts +5 -5
  54. package/package.json +1 -1
  55. package/skills/vitest-auto-spy/SKILL.md +2 -1
package/CHANGELOG.md CHANGED
@@ -10,6 +10,108 @@ The latest released version here must always match the one published on
10
10
 
11
11
  ## [Unreleased]
12
12
 
13
+ ## [5.42.0] - 2026-09-27
14
+
15
+ ### Added
16
+
17
+ - **`npx vitest-auto-spy ng-test` — sharding and changed-only runs under the Angular unit-test
18
+ builder.** `ng test` has no pass-through for Vitest's flags: `startVitest()` receives an object the
19
+ builder built, and Vitest's own `--changed` / `--related` find nothing there because its module graph
20
+ holds the builder's bundles, not your sources. `ng-test --shard 2/4` lists the target's specs with
21
+ `ng test --list-tests` (`@angular/build` 21+), splits them the way Vitest does and hands the shard to
22
+ the builder as `--include` paths, so it compiles only that shard; `ng-test --changed [ref]` and
23
+ `--related <files>` run the specs whose imports reach a changed file (relative imports,
24
+ `compilerOptions.paths` aliases, a template or stylesheet through the component naming it; a config,
25
+ a lockfile or a change the setup files reach runs everything). Everything after `--` goes to
26
+ `ng run <project>:<target>`. On a 700-spec workspace with coverage and the builder cache off, as in
27
+ CI, the slower of two `ng-test` shards took 7.58 s against 11.21 s for the whole run, and 9.38 s for
28
+ a `test.shard` set in the runner config, which still compiles every spec.
29
+ - **`provideActivatedRoute({ resources })` / `createActivatedRoute({ resources })`.** Angular 22.2
30
+ gave a route a `resources` record (developer preview), and a component reading
31
+ `route.resources['user']` got `undefined` from the double. The record now lands on
32
+ `route.resources` and on every snapshot's `resources` — the same object, carried into each new
33
+ snapshot as a navigation that keeps the route does. Arrange a value with
34
+ `mockResourceProp(resources, 'user', undefined)` on that record. On Angular 20 and 21 the key
35
+ exists in the type as `never`, so nothing can be passed where the router has no such field.
36
+ - **`doctor` points at the module cache where the unit-test builder runs istanbul.**
37
+ `angular-build-istanbul-module-cache` (info) fires for an `@angular/build:unit-test` target on 21+
38
+ and Vitest 5 whose coverage provider resolves to istanbul and whose runner config lacks
39
+ `fsModuleCache`; on a 700-file Angular 22.2 suite the cache took the run from
40
+ 24.55 s to 13.20 s (−46 %), −41 % with the builder cache off as on CI. The fix names the runner
41
+ config, or asks for `"runnerConfig"` on the target, and adds the CI cache step when no CI config
42
+ keeps `node_modules/.vitest-cache`. Quiet with v8, where the cache gained nothing, and for a
43
+ `browsers` target unless its runner config names istanbul itself: browser mode was not measured.
44
+ - **`doctor` warns before `fsModuleCache` breaks an Analog suite.** `analog-module-cache-inline-styles`
45
+ (warning): with the Analog plugin in JIT mode and a component with inline `styles`, the warm run
46
+ fails with `Cannot find module '/@id/__x00__virtual:angular:jit:style:inline;<hash>'` (verified on
47
+ Analog 2.7.5, Angular 22.2, Vitest 5.0.0).
48
+ - **`doctor` warns when Analog `fastCompile` drops constructor types.**
49
+ `analog-fast-compile-ctor-injection` (warning): with `fastCompile` in JIT mode, an `@Injectable`
50
+ class that takes a constructor parameter known only by its type gets no `ctorParameters`, so it
51
+ throws NG0202 in `TestBed.inject` and `createWithAutoSpies` alike. The finding lists each class and
52
+ the fixes: `inject()`, `@Inject(X)`, or `fastCompile` off.
53
+ - **`doctor` notes happy-dom for builder users.** `angular-build-happy-dom` (info): on
54
+ `@angular/build` 21+ the builder picks happy-dom itself once installed; −4.6 % wall and −6 % RSS on
55
+ the 700-file suite.
56
+
57
+ ### Changed
58
+
59
+ - **`createSpyFromClass` builds a double of a class with 8 or more methods as a `Proxy`.** When
60
+ `lazySpies` is not set, a class of 8+ methods gets `lazySpies: 'proxy'`; a narrower one keeps the
61
+ accessor placeholders it had. Why upgrade: a wide double a test touches holds 21–68 % less and is
62
+ built 2–6× faster — measured per double with one and two methods called: 2 110 → 1 417 B and
63
+ 3 269 → 2 573 B at 8–16 methods, 4 412 → 1 417 B and 5 570 → 2 577 B at 45; create and call 2.2 →
64
+ 1.1 µs at 8 methods, 6.5 → 1.0 µs at 45. The accessor placeholders put a touched double into a
65
+ property dictionary as wide as the class; the proxy defines nothing until a method is read. What a
66
+ wide class's double now does differently: every read of a member costs ~20 ns more;
67
+ `util.types.isProxy(double)` is `true`; `console.log` shows only the methods already read;
68
+ `vi.spyOn` on a method nobody has read returns the double's own spy, so `mockRestore()` resets it;
69
+ `Object.create(double).method` builds the spy on the double; an untouched double is ~100 B heavier.
70
+ Snapshots, `toEqual`, `Object.keys` and spread are unchanged. `lazySpies: true` brings the
71
+ placeholders back for one class, `registerAutoSpyDefaults(Class, { lazySpies: true })` for all its
72
+ doubles. `provideAutoSpy` and `injectSpy` follow the same rule.
73
+ - **`lazySpies: 'proxy'` holds ~0.26 kB per untouched double at any width**, down from 1 860 B at 10
74
+ methods and 4 097 B at 100 (`bench:memory`, 258 and 259 B): one trap handler per double and one
75
+ method-name set per class.
76
+ - **`createSpyFromClass` without `returns`, `selfReturning` or `overrides` no longer builds its message
77
+ label** — eight regex replacements per call, −0.2 µs per double in every mode.
78
+ - **A double retains less.** A materialised method spy no longer allocates an empty `Once` queue, a
79
+ closure context for its callable, a separate state object, or a six-slot context for its dispatch
80
+ (−128 B per method); the empty `accessorSpies` bag of a class without spied accessors is built from
81
+ objects sized to hold nothing (−64 B per double, identical to `{}` to every reader); and
82
+ `createAutoMock` / `mockDeep` nodes create their accessor and tombstone collections on first write
83
+ (−336 B each). `bench:memory` on the `lazySpies: true` arm (the default before this release):
84
+ untouched 243 → 178 B at 100 methods, all called 128 956 → 116 082 B (−10 %); `createAutoMock`
85
+ untouched 705 → 369 B (−48 %). Construction and call timings are unchanged within noise.
86
+
87
+ ### Fixed
88
+
89
+ - **`vi.when` on a method spy no longer reports the `calledWith()` as deciding nothing.** Vitest 5's
90
+ `vi.when(spy)` reads the spy's implementation and installs a wrapper that answers its own rows and
91
+ passes every other call through to it — to the library's dispatch, so the `calledWith` chain keeps
92
+ deciding. Both orders printed the "replaced the dispatch" warning, and under
93
+ `setupAutoSpy({ preset: 'strict' })` it threw. An implementation installed right after
94
+ `getMockImplementation()` handed out the current one is now treated as a wrapper; a `vi.when` over
95
+ a `mockReturnValue` is still reported.
96
+ - **A `calledWith` after a `mockReturnValue` that was the spy's first touch since `vi.resetAllMocks()`
97
+ is reported again.** The pending reset was applied after the replacement was recorded and erased it.
98
+ - **`perf` stops giving advice that fails under `@angular/build:unit-test` and Analog.** Under the
99
+ builder the settings findings (`perf-transform`, `perf-workers`, `perf-isolation`,
100
+ `perf-environment-engine`) name the runner config the run reads — `--runner-config` in `--command`,
101
+ then the target's `runnerConfig` — instead of the first `vite(st).config.*` in the tree, say to add
102
+ `"runnerConfig": "vitest-base.config.mts"` to the target when it names none, and say the setting is
103
+ not available on `@angular/build` 20.x, which reads no runner config. `perf-vitest-doctor` no longer
104
+ sends a builder workspace to `npx vitest doctor`, which fails there on every file with
105
+ `describe is not defined`; it gives an A/B recipe through
106
+ `ng run <project>:<target> --runner-config=<variant>` instead. `isolate` and `environment` the
107
+ builder passes to Vitest itself no longer count as the user's choice, and the DOM-engine advice
108
+ there becomes "install `happy-dom`": from 21 the builder picks it by itself. The barrel advice is
109
+ off under the builder, and the confirmed-finding card names a spec's `spec-*.js` bundle after the
110
+ spec and drops `chunk-*.js`, neither of which exists on disk. Under `@analogjs/vite-plugin-angular`
111
+ 2.7.5 and older with an inline-styled component, `perf-transform` is a warning not to turn
112
+ `fsModuleCache` on: the warm run fails with
113
+ `Cannot find module '/@id/__x00__virtual:angular:jit:style:inline;<hash>'`.
114
+
13
115
  ## [5.41.0] - 2026-09-27
14
116
 
15
117
  ### Changed
@@ -5590,7 +5692,8 @@ moved under 1 %: `/angular` +192 B (+1.0 %) for the override queue and the HTTP
5590
5692
  This copy ships with the package and carries 5.x only. Releases before 5.0.0 are in the
5591
5693
  [full changelog](https://github.com/ASDAlexey/vitest-auto-spy/blob/master/CHANGELOG.md).
5592
5694
 
5593
- [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.41.0...HEAD
5695
+ [Unreleased]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.42.0...HEAD
5696
+ [5.42.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.41.0...v5.42.0
5594
5697
  [5.41.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.40.1...v5.41.0
5595
5698
  [5.40.1]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.40.0...v5.40.1
5596
5699
  [5.40.0]: https://github.com/ASDAlexey/vitest-auto-spy/compare/v5.39.0...v5.40.0
package/README.md CHANGED
@@ -23,7 +23,7 @@ faster at suite scale ([benchmarks](#benchmarks)) — and for
23
23
  [![downloads per month](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.npmjs.org%2Fdownloads%2Fpoint%2Flast-month%2Fvitest-auto-spy&query=%24.downloads&color=brightgreen&logo=npm&label=downloads%2Fmonth)](https://www.npmjs.com/package/vitest-auto-spy)
24
24
  [![downloads over 18 months](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.npmjs.org%2Fdownloads%2Fpoint%2F2026-06-21%3A2030-01-01%2Fvitest-auto-spy&query=%24.downloads&color=brightgreen&logo=npm&label=downloads%2F18mo)](https://www.npmjs.com/package/vitest-auto-spy)
25
25
  [![CI](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml/badge.svg)](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
26
- [![minzipped size](https://img.shields.io/badge/minzip-27.3%20kB-brightgreen)](#install)
26
+ [![minzipped size](https://img.shields.io/badge/minzip-27.6%20kB-brightgreen)](#install)
27
27
  [![types](https://img.shields.io/npm/types/vitest-auto-spy?logo=typescript&logoColor=white)](https://www.npmjs.com/package/vitest-auto-spy)
28
28
  [![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
29
29
  [![license](https://img.shields.io/npm/l/vitest-auto-spy?color=blue)](./LICENSE)
@@ -998,8 +998,14 @@ npx vitest-auto-spy doctor # read-only. Exits 1 when it finds something
998
998
  npx vitest-auto-spy perf # where the suite's CPU time goes. --gate fails a budget and says why
999
999
  npx vitest-auto-spy codemod # prints the migration diff. Writes nothing without --write
1000
1000
  npx vitest-auto-spy init # writes the agent instructions pointer
1001
+ npx vitest-auto-spy ng-test # ng test with --shard / --changed the Angular builder does not pass through
1001
1002
  ```
1002
1003
 
1004
+ [`ng-test`](https://asdalexey.github.io/vitest-auto-spy/utilities/cli#ng-test-—-sharding-and-changed-only-runs-under-the-angular-builder)
1005
+ shards a suite under `@angular/build:unit-test`, or runs only the specs a change reaches: `ng test`
1006
+ passes neither Vitest's `--shard` nor its `--changed` through, so it picks the specs itself and hands
1007
+ them to the builder as `--include` paths.
1008
+
1003
1009
  **Exit `0` means "ran, nothing to report"; `1` means "ran, and here is the finding"; `2` means
1004
1010
  "there was nothing to judge".** The third one is the reason to read this line: an unknown flag for a
1005
1011
  known command is an error and **nothing runs** — `init --dryrun` used to write the files and
@@ -1035,31 +1041,35 @@ error tsconfig-glob-matches-nothing libs/users/tsconfig.spec.json
1035
1041
  3 errors, 4 warnings, 1 note
1036
1042
  ```
1037
1043
 
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
- | `angular-build-splitting-deprecated` | `"splitting"` on a unit-test target under `@angular/build` 22.2+, which deprecates it — `true` is a no-op, `false` still costs the memory |
1049
- | `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 |
1050
- | `coverage-all-removed` | `coverage.all` in a config, on a Vitest that stopped reading the key |
1051
- | `coverage-include-misses-bundle` | A `coverage.include` of sources only, in a runner config over a bundle |
1052
- | `coverage-include-recompiles-globs` | A coverage scope large enough that `picomatch` recompiling it per file costs more than the coverage. Info |
1053
- | `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) |
1054
- | `vitest-5-deprecated` | `experimental_clearCache` / `experimental_parseSpecifications` on Vitest 5, which nothing warns about at run time. Info |
1055
- | `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 |
1056
- | `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 |
1057
- | `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 |
1058
- | `fs-module-cache-not-persisted` | `fsModuleCache` on, and no CI config caches its directory — every CI run starts cold |
1059
- | `jasmine-era-project` | `jasmine-core`, `@types/jasmine`, `karma.conf.*` or `@hirez_io/observer-spy` still installed. Info, not an error |
1060
- | `no-agent-instructions` | No instruction file names the package. A note, not an error |
1061
- | `helper-from-wrong-entry` | A named import taken from an entry that does not export it — `provideAutoSpy` from the root |
1062
- | `no-unawaited-helper` | An `expectEmission` / `stable` / `flushEventLoop` call dropped as a bare statement, so nothing awaits it |
1044
+ | Check | What it finds |
1045
+ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1046
+ | `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 |
1047
+ | `tsconfig-file-missing` | A `files` entry naming a file that is gone |
1048
+ | `spec-imported-by-non-spec` | A production module importing a `*.spec.ts` |
1049
+ | `spec-exports-fixture` | A spec importing another spec, whose hooks then run in a foreign file |
1050
+ | `foreign-runner-pragma` | `@jest-environment` left in a spec, which Vitest never reads |
1051
+ | `dead-runner-config` | `jest.config.*` / `karma.conf.*` for a runner that is not installed |
1052
+ | `orphan-runner-file` | A setup file only that dead config referenced |
1053
+ | `angular-build-splitting-off` | `@angular/build` in `[22.1.5, 22.1.7)` — the OOM under `--coverage` |
1054
+ | `angular-build-splitting-deprecated` | `"splitting"` on a unit-test target under `@angular/build` 22.2+, which deprecates it — `true` is a no-op, `false` still costs the memory |
1055
+ | `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 |
1056
+ | `analog-fast-compile-ctor-injection` | Analog `fastCompile` in JIT mode with an `@Injectable` whose constructor parameter is known only by its type — NG0202 at injection |
1057
+ | `analog-module-cache-inline-styles` | `fsModuleCache` on under the Analog plugin with a component that has inline `styles` — the warm run fails on `virtual:angular:jit:style:inline` |
1058
+ | `angular-build-istanbul-module-cache` | istanbul coverage under the unit-test builder (not in `browsers`) without `fsModuleCache` — −46 % on a 700-file Angular 22.2 suite. Info |
1059
+ | `angular-build-happy-dom` | jsdom only because `happy-dom` is not installed; the builder picks it by itself from 21 — −4.6 % wall, −6 % RSS. Info |
1060
+ | `coverage-all-removed` | `coverage.all` in a config, on a Vitest that stopped reading the key |
1061
+ | `coverage-include-misses-bundle` | A `coverage.include` of sources only, in a runner config over a bundle |
1062
+ | `coverage-include-recompiles-globs` | A coverage scope large enough that `picomatch` recompiling it per file costs more than the coverage. Info |
1063
+ | `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) |
1064
+ | `vitest-5-deprecated` | `experimental_clearCache` / `experimental_parseSpecifications` on Vitest 5, which nothing warns about at run time. Info |
1065
+ | `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 |
1066
+ | `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 |
1067
+ | `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 |
1068
+ | `fs-module-cache-not-persisted` | `fsModuleCache` on, and no CI config caches its directory — every CI run starts cold |
1069
+ | `jasmine-era-project` | `jasmine-core`, `@types/jasmine`, `karma.conf.*` or `@hirez_io/observer-spy` still installed. Info, not an error |
1070
+ | `no-agent-instructions` | No instruction file names the package. A note, not an error |
1071
+ | `helper-from-wrong-entry` | A named import taken from an entry that does not export it — `provideAutoSpy` from the root |
1072
+ | `no-unawaited-helper` | An `expectEmission` / `stable` / `flushEventLoop` call dropped as a bare statement, so nothing awaits it |
1063
1073
 
1064
1074
  The check that motivated the tool: a spec showing `Cannot find name 'vi'` in the editor while
1065
1075
  `tsc --noEmit` reported zero errors. A migration codemod editing `include` had eaten a `/**`,
@@ -1879,7 +1889,8 @@ multipliers do not transfer to suite scale: building a double is on the order of
1879
1889
  so a 10× win on the double shows up as a few per cent on the run, and nearly everything else in a
1880
1890
  suite swamps it.
1881
1891
 
1882
- **Memory, `isolate: false`, 100-method class, 10 000 tests, peak RSS:**
1892
+ **Memory, `isolate: false`, 100-method class, 10 000 tests, peak RSS** — measured before 2026-09-27,
1893
+ on the accessor-placeholder default and the proxy mode of that time:
1883
1894
 
1884
1895
  | Arm | Peak RSS |
1885
1896
  | ------------------------------------- | -------: |
@@ -1891,19 +1902,35 @@ Hand-written doubles use 3.0x the default's peak RSS here — the difference bet
1891
1902
  OOM'd worker on a large suite.
1892
1903
 
1893
1904
  That gap traces down to a single double: on the same 100-method class, untouched, a hand-written
1894
- double retains **414 462 B**. The two arms above are what the library retained against it when they
1895
- were captured; the per-double figure has since moved a long way, and in the direction that makes the
1896
- table's third row unnecessary. Re-measured 2026-09-17 on Node 24, the **default** retains **215 B**
1897
- per untouched 100-method double — the lazy placeholder's accessor pair is now shared by method name
1898
- rather than minted per double — and `lazySpies: 'proxy'` retains **4 090 B**, nineteen times more.
1899
- Full retained-memory tables:
1905
+ double retains **414 462 B**. Re-measured 2026-09-27 (`npm run bench:memory`, Node 24, Vitest 5), the
1906
+ default on that class retains **259 B** per untouched double and `lazySpies: true` **178 B** — the lazy
1907
+ placeholder's accessor pair is shared by method name rather than minted per double. Full
1908
+ retained-memory tables:
1900
1909
  [Performance](https://asdalexey.github.io/vitest-auto-spy/core/performance#retained-memory-per-double).
1901
1910
 
1911
+ The first read is where the accessor placeholders pay: it drops the double into a property
1912
+ dictionary as wide as the class. That dictionary is why a class of 8 methods or more gets `'proxy'`
1913
+ when `lazySpies` is not set. The proxy answers every method from one trap handler and one name set
1914
+ per class and defines nothing, so there is no shared map to leave and no dictionary to grow. Bytes
1915
+ per double with one and two methods called (1 000 doubles held at once, 2026-09-27):
1916
+
1917
+ | Methods in the class | `true`, 1 / 2 touched | `'proxy'`, 1 / 2 touched | Saving |
1918
+ | -------------------: | --------------------: | -----------------------: | ------------: |
1919
+ | 4–6 | 1 743 / 2 887 B | 1 415 / 2 573 B | −19 % / −11 % |
1920
+ | 8–16 | 2 110 / 3 269 B | 1 417 / 2 573 B | −33 % / −21 % |
1921
+ | 20–30 | 2 877 / 4 036 B | 1 416 / 2 573 B | −51 % / −36 % |
1922
+ | 45 | 4 412 / 5 570 B | 1 417 / 2 577 B | −68 % / −54 % |
1923
+
1924
+ The steps are V8's: the dictionary holds `pow2ceil(1.5·(width + 3))` slots. Building and touching the
1925
+ double is cheaper too — 2.2 → 1.1 µs at 8 methods, 6.5 → 1.0 µs at 45. The price is a trap on every
1926
+ read of a member for the life of the double, about 25 ns against 5 ns for a plain property, ~100 B more
1927
+ on a double nobody touches, and a double a spec can see is a `Proxy`. Eight methods is the smallest
1928
+ width where the proxy saves at least 15 % on both profiles; below it the default stays a plain object.
1929
+ `lazySpies: true` opts a wide class out.
1930
+
1902
1931
  **Guidance keyed to suite size:** `isolate: false` is worth about 4x on its own — more than any
1903
- library choice measured here — and it makes memory, not wall-clock, the binding constraint. The
1904
- default is the memory answer at every width now; `lazySpies: 'proxy'` is left for the one thing it
1905
- is still faster at, building a double of a very wide class, and it taxes every read for the life of
1906
- that double (53 ns against 7 ns).
1932
+ library choice measured here — and it makes memory, not wall-clock, the binding constraint. Leave
1933
+ `lazySpies` alone: the width picks the lighter double.
1907
1934
 
1908
1935
  Full write-up, methodology and the complete suite-scale tables:
1909
1936
  [Performance](https://asdalexey.github.io/vitest-auto-spy/core/performance).
@@ -2630,7 +2657,7 @@ beforeEach(() => {
2630
2657
  > startup with `TypeError: cache.has is not a function`.
2631
2658
 
2632
2659
  > **Lazy by default, everywhere.** Every factory builds each method spy on first access
2633
- > (`lazySpies: true`), since Angular tests typically spy a wide service but call
2660
+ > (accessor placeholders below 8 methods, a `Proxy` from 8), since Angular tests typically spy a wide service but call
2634
2661
  > only a few of its methods — and the margin widens as the class does: **1.4×** on a ten-method
2635
2662
  > class a test calls twice, **1.9×** on a forty-method one it calls three times. Behaviour is
2636
2663
  > unchanged; pass `{ lazySpies: false }` to build every spy eagerly.
@@ -4336,7 +4363,7 @@ as `methodsToSpyOn`, named for callables that live on the instance — `signal()
4336
4363
  `gettersToSpyOn`, `settersToSpyOn`, `autoSpyAccessors` (discover every getter/setter),
4337
4364
  `fillMissing` (answer a name the prototype never carried with a spy — for a **partially** abstract
4338
4365
  class, where `abstract` members are erased and the empty-prototype fallback no longer fires),
4339
- `lazySpies` (materialize method spies on first access — the `provideAutoSpy` default on Angular; the placeholder's accessor pair is shared by method name, so an untouched 100-method double retains 215 B. `'proxy'` answers every method from one trap object instead: it retains 4 090 B on the same class and pays a trap on every read (53 ns against 7 ns), so what is left of it is build time on a very wide class — see [Performance](https://asdalexey.github.io/vitest-auto-spy/core/performance#retained-memory-per-double))
4366
+ `lazySpies` (build each method spy on first read. Unset: accessor placeholders below 8 methods, `'proxy'` from 8 — a `Proxy` that defines nothing per method, 1.4 kB against 2.1 kB for a 8–16-method double with one method called and 1.4 against 4.4 kB at 45, at ~20 ns per read. `true` keeps a plain object at any width, `false` builds every spy up front — see [Performance](https://asdalexey.github.io/vitest-auto-spy/core/performance#retained-memory-per-double))
4340
4367
 
4341
4368
  `ValueConfig` (for `nextWithValues`): `{ value, delay? }` | `{ errorValue, delay? }` | `{ complete?, delay? }`.
4342
4369
 
@@ -14,8 +14,8 @@ TestBed.configureTestingModule({
14
14
  const myService = injectSpy(MyService); // Spy<MyService>
15
15
  ```
16
16
 
17
- `provideAutoSpy` defaults to `lazySpies: true` (the plain `createSpyFromClass` does not). Pass
18
- `{ lazySpies: false }` to opt out. The spies never touch `NgZone`, so they work zoneless and with
17
+ `provideAutoSpy` is lazy by default, as `createSpyFromClass` is: an unset `lazySpies` is `true` below 8
18
+ methods and `'proxy'` from 8. Pass `{ lazySpies: false }` to opt out. The spies never touch `NgZone`, so they work zoneless and with
19
19
  zone.js alike. The entry needs **Angular >= 20** (§1); on 16 or 17 it does not link at all, because
20
20
  `ɵSIGNAL` is not there to import.
21
21
 
@@ -524,7 +524,7 @@ built over one record, so every stream, both `ParamMap`s and `snapshot` read the
524
524
 
525
525
  | Call | Does |
526
526
  | --- | --- |
527
- | `provideActivatedRoute(init?)` | a `FactoryProvider` — a fresh route per injector; `init`: `params`, `queryParams`, `data`, `title`, `fragment`, `url`, `outlet`, `component`, `routeConfig`, `resolve` |
527
+ | `provideActivatedRoute(init?)` | a `FactoryProvider` — a fresh route per injector; `init`: `params`, `queryParams`, `data`, `title`, `fragment`, `url`, `outlet`, `component`, `routeConfig`, `resolve`, `children`, `resources` (22.2+: one record on the route and every snapshot — fill it with `mockResourceProp(resources, 'user', …)`) |
528
528
  | `injectActivatedRoute(injector?)` | the handle: `.route`, `setParams`, `setQueryParams`, `setData`, `setFragment`, `setUrl`, `set({ … })` |
529
529
  | `createActivatedRoute(init?)` | the same handle without a `TestBed` — for `new Page(route)`, or a guard given `route.snapshot` |
530
530
 
@@ -50,9 +50,16 @@ a unit-test target, Analog below 2.7.5, `vite` below 6.4, or Node below 22.12 in
50
50
  `.node-version`, CI or a private package's `engines`. `fs-module-cache-not-persisted` warns when
51
51
  `fsModuleCache` is on and no CI config caches its directory. Renamed config keys Vitest 5 still
52
52
  honours (`experimental.fsModuleCache`, `browser.isolate`, `cache.dir`, …) are left to Vitest's own
53
- deprecation line. `mock-reset-config-unread` notes a `no-redundant-mock-reset` whose `configFile` names
54
- a config built by a factory or `mergeConfig`, with no flag beside it: the rule cannot see the flags
55
- that call sets.
53
+ deprecation line. Four more cover the Angular unit-test builder and Analog:
54
+ `angular-build-istanbul-module-cache` notes an istanbul run under `@angular/build:unit-test` 21+ on
55
+ Vitest 5 without `fsModuleCache` in the target's runner config (−46 % measured), and
56
+ `analog-module-cache-inline-styles` warns that `fsModuleCache` under the Analog plugin breaks the
57
+ warm run of any spec reaching a component with inline `styles`. `angular-build-happy-dom` notes a
58
+ builder target on jsdom only because `happy-dom` is not installed.
59
+ `analog-fast-compile-ctor-injection` warns that Analog `fastCompile` in JIT mode leaves
60
+ `@Injectable` constructor parameters without a token (NG0202). `mock-reset-config-unread` notes a
61
+ `no-redundant-mock-reset` whose `configFile` names a config built by a factory or `mergeConfig`,
62
+ with no flag beside it: the rule cannot see the flags that call sets.
56
63
  It is worth one run after any large edit to a test suite — especially after a codemod, which is where
57
64
  the eaten glob below came from.
58
65
 
@@ -133,6 +140,11 @@ per file on 5, where it is the wait for Vite's transforms and `import`/`setup` a
133
140
  totals are CPU time summed across every worker, not wall clock** — a report showing `20.29s of CPU
134
141
  time` under `986ms wall clock` is not a bug, it is the work spread over workers.
135
142
 
143
+ Under `@angular/build:unit-test`, `ng test` takes no Vitest flag. Shard or run only what a change
144
+ reaches with `npx vitest-auto-spy ng-test --shard 1/4` / `--changed [ref]` / `--related <files>`
145
+ (`@angular/build` 21+; everything after `--` goes to `ng`); `test.repeats` in the runner config
146
+ reaches Vitest as it is. `vitest doctor` does not work there — use `perf --command`.
147
+
136
148
  When `environment` dominates, the `perf-environment` finding names spec files that could run under
137
149
  the `node` environment instead — but only the ones it could _prove_ reach no DOM: the spec, its
138
150
  configured setup files, and every repository module any of them imports were all read, none
@@ -173,7 +185,9 @@ used rather than the machine's cores; under `isolate: false`, `perf-heap` lists
173
185
  to its lane's heap. Environment time is counted once per lane (`concurrencyId`) and value — not per
174
186
  `workerId`, which Vitest 5 renews for every file even in a reused worker. A finding about a switch
175
187
  also prints `perf-vitest-doctor`: confirm it with `npx vitest doctor`, Vitest's own A/B runner, not
176
- this package's `doctor`. A bare run on Vitest 5 passes `--experimental.diagnostics=false` so Vitest's
188
+ this package's `doctor`. Under `@angular/build:unit-test` it gives an A/B through `ng run <project>:<target> --runner-config=<variant>`
189
+ instead, because `npx vitest doctor` cannot build that suite; every settings finding there names the runner config
190
+ the target reads. A bare run on Vitest 5 passes `--experimental.diagnostics=false` so Vitest's
177
191
  own hints do not repeat these. The reporter rewrites a `partial: true` report every ~2 s while the run
178
192
  goes, so a killed or timed-out run still leaves one: `perf` prints it under a warning and the gate
179
193
  refuses it like a red run.
@@ -15,7 +15,7 @@ createSpyFromClass(MyService, {
15
15
  gettersToSpyOn: ['userName'],
16
16
  settersToSpyOn: ['userName'],
17
17
  autoSpyAccessors: true, // discover every accessor on the prototype chain
18
- lazySpies: true, // build each method spy on first access ('proxy' for very wide classes)
18
+ lazySpies: true, // unset: true below 8 methods, 'proxy' from 8; false = eager
19
19
  returns: { getProducts: of([]) }, // what a spied METHOD answers
20
20
  selfReturning: ['where'], // a method that answers the double itself, for a chained call
21
21
  overrides: { products$: subject }, // a member that is not a method result
@@ -28,7 +28,7 @@ createSpyFromClass(MyService, {
28
28
  | `onlyMethodsToSpyOn` | **Exhaustive whitelist.** Skips discovery; anything not listed is absent. |
29
29
  | `instanceMethodsToSpyOn` | **Additive.** The name to prefer in new code (see below). |
30
30
  | `autoSpyAccessors` | Merged with the explicit getter/setter lists. |
31
- | `lazySpies` | Behaviour-identical; only changes _when_ each spy is built. `'proxy'` also changes _what holds the name_. |
31
+ | `lazySpies` | Unset: `true` (accessor placeholders) below 8 methods, `'proxy'` (a `Proxy`, lighter once touched) from 8. Explicit `true` / `false` / `'proxy'` apply at any width. Calls, `Object.keys`, spread and snapshots behave the same in every mode. |
32
32
  | `strict` | Throw on a method nobody configured, instead of answering `undefined` (below). |
33
33
  | `onUnstubbedCall` | The general form of `strict`; its return value becomes the call's return value. |
34
34
  | `selfReturning` | The named methods answer the double itself — a default like `returns`; a name in both answers `returns`. |
@@ -251,6 +251,9 @@ Precedence, first one set wins: the double's `onUnstubbedCall` → the double's
251
251
  double is built, or `resolveWith` / `nextWith` / `failWith` — which a `calledWith` still wins over.
252
252
  The report is this library's own spy engine's, so Vitest and Rstest have it; Bun, `node:test` and
253
253
  `setSpyEngine('runner')` do not. The `Once` family is never reported.
254
+ `vi.when(spy)` (Vitest 5) is not reported either: it wraps the dispatch rather than replacing it,
255
+ so a `calledWith` on the same method still answers every call `vi.when` has no row for. A
256
+ `vi.when` over a `mockReturnValue` still is.
254
257
  - **A throw something swallowed still fails the test.** Under `setupAutoSpy({ strict: true })` every
255
258
  strict throw is recorded, and one that a `try`/`catch` in the code under test or an RxJS error with
256
259
  no handler (its rethrow waits on a fake clock) kept from the test fails it after the test
@@ -126,6 +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
+ | `NG0202 … dependency at index N of the parameter list is invalid` from `createWithAutoSpies` or plain `TestBed.inject`, under Analog `fastCompile: true` | the plugin drops the constructor types of `@Injectable` classes in JIT mode — not a library bug (`doctor` reports `analog-fast-compile-ctor-injection` and lists the classes) | an `inject()` field, or `@Inject(X)` on the parameter; or turn `fastCompile` off (§13) |
129
130
  | `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
131
  | `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
132
  | `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) |
@@ -349,12 +349,13 @@ retains: an untouched 100-method double holds **215 B** where it held 25 593, an
349
349
  construction on very wide classes — building a 300-method double costs about 28 % more — and
350
350
  materialising every method of one is about 26 % cheaper in exchange.
351
351
 
352
- That inverts the case for `lazySpies: 'proxy'`, which answers every method from a single trap
353
- object: it now retains **4 090 B** against the default's 215 B at 100 methods — 19× more — and still
354
- pays a trap on every read (53 ns against 7 ns) for the life of the double, because a `Proxy` cannot
355
- remove itself while the default leaves a plain data property behind once a method materialises. What
356
- is left of its advantage is build time on a wide class. The option is unchanged and still supported;
357
- there is no longer a memory reason to reach for it.
352
+ The first materialisation is where the accessor path pays: it drops the double into a property
353
+ dictionary as wide as the class. So since 2026-09-27 an unset `lazySpies` depends on width: a class of
354
+ 8 methods or more gets `'proxy'`, which defines nothing per method and never enters dictionary mode —
355
+ 21–68 % lighter once touched, 2–6× faster to build — for ~20 ns on every read and ~100 B more on an
356
+ untouched double. A narrower class keeps the accessor placeholders. A spec on a wide class that needs a
357
+ plain object (`util.types.isProxy`, `console.log` of an unread double, `vi.spyOn` wrapping an unread
358
+ method) passes `lazySpies: true`.
358
359
 
359
360
  A frozen or sealed double is fine now. `Object.freeze(spy)` — a deep-freeze fixture helper, a
360
361
  dev-mode state guard — used to make the first read of any method throw `Cannot redefine property`
@@ -1,12 +1,12 @@
1
1
  import { pendingRequestsReport, assertAngularInternals, instrumentTestBed, onTestingModuleConfigured, onComponentCreated, beforeTestBedReset, verifyOnTeardown } from './chunk-JFOJFCVQ.js';
2
2
  export { disableTestBedDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, reportSpecTiming } from './chunk-JFOJFCVQ.js';
3
- import { failOnUnspiedProvider } from './chunk-OWDUWUAO.js';
3
+ import { failOnUnspiedProvider } from './chunk-MHN6GMXP.js';
4
4
  import './chunk-GG7BQKEK.js';
5
5
  import './chunk-MNY4ZHEQ.js';
6
- import './chunk-T7EGA4G4.js';
6
+ import './chunk-EYXARTWD.js';
7
7
  import './chunk-FOL5RH22.js';
8
8
  import './chunk-PC3FAZT3.js';
9
- import './chunk-HUS2MHK5.js';
9
+ import './chunk-CENALW7R.js';
10
10
  import { isAutoSpyLike } from './chunk-Q7L4AWI7.js';
11
11
  import { count, sourceClassName, taskName } from './chunk-DYAS4OK4.js';
12
12
  import { angularPendingRequests, angularShadowedProviders, angularDeadSchemas, angularNgModuleScopesAuto } from './chunk-5FQZGJLJ.js';
@@ -1,5 +1,5 @@
1
1
  import { InjectionToken, AbstractType, Injector, ValueProvider, FactoryProvider, ProviderToken } from '@angular/core';
2
- import { h as AddSpyMethodsByReturnTypes } from './types-DJ0OGc3C.js';
2
+ import { h as AddSpyMethodsByReturnTypes } from './types-CyRUgJVd.js';
3
3
  import 'vitest';
4
4
 
5
5
  /**
@@ -1,11 +1,11 @@
1
1
  import { describeInstance } from './chunk-XEIOGUGP.js';
2
- import { useVitestAdapter } from './chunk-6ZGH56G4.js';
3
- import './chunk-IE4NI2OQ.js';
2
+ import { useVitestAdapter } from './chunk-J4IJCTHT.js';
3
+ import './chunk-J2C3KRTC.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-HUS2MHK5.js';
8
+ import { createFunctionSpy } from './chunk-CENALW7R.js';
9
9
  import './chunk-Q7L4AWI7.js';
10
10
  import { sourceClassName } from './chunk-DYAS4OK4.js';
11
11
  import { angularDialog } from './chunk-5FQZGJLJ.js';
@@ -1,6 +1,6 @@
1
1
  import { Type, Injector, FactoryProvider, Provider } from '@angular/core';
2
2
  import { Params, Data, UrlSegment, ActivatedRoute, Route, ResolveData, Navigation, Router, Event } from '@angular/router';
3
- import { h as AddSpyMethodsByReturnTypes } from './types-DJ0OGc3C.js';
3
+ import { h as AddSpyMethodsByReturnTypes } from './types-CyRUgJVd.js';
4
4
  import { SpyLocation } from '@angular/common/testing';
5
5
  import 'vitest';
6
6
 
@@ -38,6 +38,11 @@ interface ActivatedRouteChange {
38
38
  /** The matched URL segments. A string is split on `/`; pass `UrlSegment`s for matrix parameters. */
39
39
  url?: UrlSegment[] | string;
40
40
  }
41
+ /**
42
+ * `ActivatedRoute.resources` where the installed `@angular/router` has it (22.2 on), `never` before —
43
+ * so the init key stays harmless on 20 and 21.
44
+ */
45
+ type RouteResources = NonNullable<ActivatedRoute[Extract<'resources', keyof ActivatedRoute>]>;
41
46
  /** The route a spec starts from: what a navigation moves, plus what stays fixed for the route's life. */
42
47
  interface ActivatedRouteInit extends ActivatedRouteChange {
43
48
  /** The outlet the route is rendered into. Default `'primary'`. */
@@ -48,6 +53,11 @@ interface ActivatedRouteInit extends ActivatedRouteChange {
48
53
  routeConfig?: Route | null;
49
54
  /** The resolve record — the snapshot's own `_resolve`, kept apart from `data` as Angular keeps it. */
50
55
  resolve?: ResolveData;
56
+ /**
57
+ * The record a route's `resources` function returned — `route.resources` and `snapshot.resources`,
58
+ * the same object on every snapshot, as a navigation that keeps the route carries it over.
59
+ */
60
+ resources?: RouteResources;
51
61
  /** Child routes, each a double of its own: `route.children`, `firstChild` and a child's `parent` answer them. */
52
62
  children?: readonly ActivatedRouteInit[];
53
63
  }
@@ -1,6 +1,6 @@
1
1
  import { describeInstance } from './chunk-XEIOGUGP.js';
2
2
  import { angularInternalsError } from './chunk-GG7BQKEK.js';
3
- import { createFunctionSpy } from './chunk-HUS2MHK5.js';
3
+ import { createFunctionSpy } from './chunk-CENALW7R.js';
4
4
  import './chunk-Q7L4AWI7.js';
5
5
  import { count } from './chunk-DYAS4OK4.js';
6
6
  import { angularRouteDouble, angularRouterInject, angularRouterEvents, angularLocationDouble, angularRouteWiring, angularRouterDouble } from './chunk-5FQZGJLJ.js';
@@ -110,7 +110,14 @@ function buildSnapshot(state, fixed) {
110
110
  fixed.routeConfig,
111
111
  state.resolve
112
112
  ];
113
- return Reflect.construct(ActivatedRouteSnapshot, args);
113
+ const snapshot = Reflect.construct(ActivatedRouteSnapshot, args);
114
+ withResources(snapshot, fixed);
115
+ return snapshot;
116
+ }
117
+ function withResources(target, fixed) {
118
+ if (fixed.resources !== void 0) {
119
+ Reflect.set(target, "resources", fixed.resources);
120
+ }
114
121
  }
115
122
  function routeWiringError(member) {
116
123
  return new Error(
@@ -187,13 +194,15 @@ function constructRoute(streams, fixed, snapshot) {
187
194
  snapshot
188
195
  ]);
189
196
  route.snapshot = snapshot;
197
+ withResources(route, fixed);
190
198
  return route;
191
199
  }
192
200
  function buildActivatedRoute(init) {
193
201
  const fixed = {
194
202
  outlet: init.outlet ?? PRIMARY_OUTLET,
195
203
  component: init.component ?? null,
196
- routeConfig: init.routeConfig ?? null
204
+ routeConfig: init.routeConfig ?? null,
205
+ resources: init.resources
197
206
  };
198
207
  let state = initialState(init);
199
208
  const streams = streamsOf(state);
package/dist/angular.d.ts CHANGED
@@ -1,12 +1,12 @@
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-DUZUFWf-.js';
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-DJ0OGc3C.js';
3
- export { H as SubjectOf } from './types-DJ0OGc3C.js';
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-bs2umXNE.js';
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-CyRUgJVd.js';
3
+ export { H as SubjectOf } from './types-CyRUgJVd.js';
4
4
  import { InjectionToken, Provider, Type, WritableSignal, Signal } from '@angular/core';
5
- import { A as AutoMockConfiguration, D as DeepReadonly } from './expect-emission-CwosjG6t.js';
6
- export { C as CallbackSubscribable, E as EmissionObserver, c as EmissionOptions, d as EmissionSource, S as SubscribableLike, h as expectAllEmissions, i as expectCompletion, j as expectEmission, k as expectEmissions, l as expectError, m as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CwosjG6t.js';
5
+ import { A as AutoMockConfiguration, D as DeepReadonly } from './expect-emission-D273986K.js';
6
+ export { C as CallbackSubscribable, E as EmissionObserver, c as EmissionOptions, d as EmissionSource, S as SubscribableLike, h as expectAllEmissions, i as expectCompletion, j as expectEmission, k as expectEmissions, l as expectError, m as expectNoEmission, s as setEmissionTimeout } from './expect-emission-D273986K.js';
7
7
  import { TestAPI } from 'vitest';
8
- export { I as InjectionLog, T as TrackInjectionsOptions, a as TrackedProvider, t as trackInjections } from './track-injections-Bp8TgLjG.js';
9
- export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, e as restoreMockedProps } from './prop-mock-C8PJ-Vo8.js';
8
+ export { I as InjectionLog, T as TrackInjectionsOptions, a as TrackedProvider, t as trackInjections } from './track-injections-BTJKOqWz.js';
9
+ export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, e as restoreMockedProps } from './prop-mock-Cz0yKWEP.js';
10
10
  import '@angular/core/testing';
11
11
 
12
12
  /**