vitest-auto-spy 3.11.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -77,7 +77,8 @@ Do you have a real class at runtime?
77
77
  ├── yes, and reads chain (a.b.c()) → mockDeep<T>(overrides?) → DeepMockProxy<T>
78
78
  ├── yes, and CALLS chain (a.b().c()) → mockDeep<T>({}, { selfReturning: true })
79
79
  └── no, it is only READ (DTO, config, route snapshot)
80
- → createMock<T>(partial?) → T (no spies)
80
+ ├── one spec, a couple of fields → createMock<T>(partial?) → T (no spies)
81
+ └── many specs, one shared model → createFixtureFactory<T>(defaults) → (overrides?) => T
81
82
 
82
83
  One standalone function? → createFunctionSpy<Fn>('name')
83
84
  Code under test does `new Foo()`? → a real class? createSpyClass(Foo)
@@ -97,6 +98,16 @@ noise scales with the number of them.
97
98
  `createMock<T>()` is the one to reach for on data shapes — it returns a plain `T`, so it satisfies a
98
99
  `no-type-assertion` lint rule without an `eslint-disable` on every fixture.
99
100
 
101
+ **`createFixture<T>(defaults, overrides?)` / `createFixtureFactory<T>(defaults)` are for the model
102
+ that more than one spec builds.** The difference from `createMock` is the `defaults` argument: it is
103
+ a **complete** `T`, checked in full, in one place — so a field the model dropped fails there instead
104
+ of in eight copies of a hundred-line literal. Overrides are deep-partial-checked and merge leaf by
105
+ leaf; an overridden array replaces the default one. Every call hands back a fresh object and the
106
+ defaults are copied at build time, which is what keeps one test's mutation out of the next test —
107
+ across files, under `isolate: false`. The copy is deep through plain objects and arrays only: a
108
+ `Date`, a `Map` or a class instance travels by reference, because rebuilding it would strip its
109
+ prototype. Defaults that are a class instance with getters go through `withOverrides()` first.
110
+
100
111
  **`mockDeep` builds depth on property access, not on calls** — the distinction the tree now spells
101
112
  out, and the one that costs an afternoon otherwise. `mock.repo.user.find()` chains because every hop
102
113
  but the last is a _read_. A node that is **called** returns what it was configured to return, and by
@@ -1539,6 +1550,37 @@ assertNgModuleScopes(DirectivesModule, PipesModule); // throws, naming the modul
1539
1550
  Then declare what the spec needs in the TestBed module directly. Pass only modules you expect to
1540
1551
  bring declarations — a providers-only module is legitimately empty.
1541
1552
 
1553
+ ### A component whose own definition has a hole in it
1554
+
1555
+ The same bundle, one level down. A component's `providers`, `viewProviders` and compiled scope are
1556
+ **baked into `ɵcmp` when its module executes**, not read at `createComponent` time — so a barrel
1557
+ split into a chunk that has not run yet produces a definition with `undefined` in those lists.
1558
+ Angular finds out much later, from inside itself, with a stack that names neither the barrel nor the
1559
+ component:
1560
+
1561
+ ```
1562
+ TypeError: Cannot read properties of undefined (reading 'provide')
1563
+ ❯ resolveProvider render3/di_setup.ts:95
1564
+ ```
1565
+
1566
+ Both obvious cures fail: `await import('@scope/lib')` at the top of `beforeEach` is already too late,
1567
+ and a static import at the top of the spec does not fix the order this bundler emits. Worse, the spec
1568
+ that breaks is one nobody touched — chunk boundaries move with file *contents*, so editing a type
1569
+ next door is enough.
1570
+
1571
+ ```ts
1572
+ import { assertComponentDefIntact } from 'vitest-auto-spy/angular';
1573
+
1574
+ assertComponentDefIntact(HoverMenuComponent); // HoverMenuComponent.ɵcmp.providers[0] is undefined
1575
+ const fixture = TestBed.createComponent(HoverMenuComponent);
1576
+ ```
1577
+
1578
+ It walks the three lists, nested arrays and forward-reference thunks included, and answers the
1579
+ related `Cannot read properties of undefined (reading 'ɵcmp')` from `imports: [Cmp]` as well — there
1580
+ the class reference itself never arrived, and the message names the argument position. Directives
1581
+ (`ɵdir`) are checked the same way. Neither this nor `assertNgModuleScopes` fixes the build; both
1582
+ replace a stack inside `@angular/core` with a line naming what is missing.
1583
+
1542
1584
  ### Four silent failures, as one setup line
1543
1585
 
1544
1586
  ```ts
@@ -2015,6 +2057,9 @@ packages, which a subpath export can never be.
2015
2057
  | `overrideComponentProvider(…): the override did not apply` | the component injects a different token, or a later `overrideProvider` won | pass the token the component actually injects (a base class, an `InjectionToken`), and override after nothing else re-configures |
2016
2058
  | `the test ended with N unflushed HttpTestingController request(s)` | `enableAngularDiagnostics({ pendingRequests })` — nothing answered them | flush each (`controller.expectOne(url).flush(body)`), or `controller.verify()` where absence is the assertion (§13) |
2017
2059
  | `NgModule(s) with an empty runtime scope: …` | `ngModuleScopes` (or `assertNgModuleScopes`) — an AOT test bundle stripped `ɵɵsetNgModuleScope`, so the import contributes nothing | declare what the spec needs in the TestBed module directly; pass only modules expected to bring declarations (§13) |
2060
+ | `Cannot read properties of undefined (reading 'provide')`, stack inside `render3/di_setup` | a barrel chunk had not run when the component's definition was built, so a provider slot is `undefined` | `assertComponentDefIntact(Cmp)` before `createComponent` — it names the list and the index (§13) |
2061
+ | `assertComponentDefIntact(): argument N is undefined, which carries no ɵcmp or ɵdir` | the class reference itself never arrived — the `Cannot read properties of undefined (reading 'ɵcmp')` case | the same split barrel; import the component from its own module, not the barrel (§13) |
2062
+ | `TS1117: An object literal cannot have multiple properties with the same name`, in a fixture | a hundred-line model literal copied into eight specs and edited independently | one `createFixtureFactory<T>(defaults)`; note the runtime keeps the **second** key, so do not auto-fix by dropping one (§12) |
2018
2063
  | `configureTestingModule was given N schema(s) that can never apply` | `enableAngularDiagnostics({ deadSchemas })` — `schemas` next to a standalone component, with `declarations` empty | drop the `schemas` entry and put the missing directive/pipe in the component's own `imports`, or use `createDirectiveHost` (§13) |
2019
2064
  | `injectSpy(X): the injector returned a plain instance, not an auto-spy` | the token is provided for real; a `console.warn` on its own, a **throw** under `enableAngularDiagnostics({ unspiedProviders })` | `provideAutoSpy(X)` / `provideAutoSpyForToken(TOKEN)`, or `TestBed.inject(X)` if the real thing is what the spec wants |
2020
2065
  | `trackInjections(...).get(X): that token is not tracked by this log` | `get` only answers for tokens whose providers the log created | add the token to the `trackInjections([...])` list, or read it from the injector directly (§13) |
package/README.md CHANGED
@@ -16,7 +16,7 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
16
16
  [![npm version](https://img.shields.io/npm/v/vitest-auto-spy?color=brightgreen&logo=npm)](https://www.npmjs.com/package/vitest-auto-spy)
17
17
  [![npm downloads](https://img.shields.io/npm/dm/vitest-auto-spy?color=brightgreen&logo=npm)](https://www.npmjs.com/package/vitest-auto-spy)
18
18
  [![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)
19
- [![minzipped size](https://img.shields.io/badge/minzip-14.3%20kB-brightgreen)](#install)
19
+ [![minzipped size](https://img.shields.io/badge/minzip-14.5%20kB-brightgreen)](#install)
20
20
  [![types](https://img.shields.io/npm/types/vitest-auto-spy?logo=typescript&logoColor=white)](https://www.npmjs.com/package/vitest-auto-spy)
21
21
  [![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/ASDAlexey/vitest-auto-spy/actions/workflows/ci.yml)
22
22
  [![license](https://img.shields.io/npm/l/vitest-auto-spy?color=blue)](./LICENSE)
@@ -49,7 +49,7 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
49
49
  - ⚙️ Getter / setter spies via `accessorSpies`
50
50
  - 🧰 DI & mocking utilities — `provideAutoSpy` / `injectSpy` (Angular, NestJS, Vue), `createFunctionSpy`, `mockReadonlyProp` for signals
51
51
  - ⚡ Angular speed & zoneless helpers — `renderShallow` (**1.7×** on real component specs), `createWithAutoSpies`, `stable` / `flushEffects`, `settleResource` for `httpResource()`, `toHaveSignalValue`, per-file `TestBed` timings
52
- - 🧱 The providers a testing module cannot reach — `overrideComponentProvider` (which verifies the override actually applied), `provideAutoSpyForToken`, `assertNgModuleScopes`, `createDirectiveHost`
52
+ - 🧱 The providers a testing module cannot reach — `overrideComponentProvider` (which verifies the override actually applied), `provideAutoSpyForToken`, `assertNgModuleScopes`, `assertComponentDefIntact`, `createDirectiveHost`
53
53
  - 🚨 Failures that used to be silence — `enableAngularDiagnostics()` for dead NgModule imports, dead `schemas`, an unspied provider and unflushed HTTP requests; `trackInjections` for which collaborators the code actually asked for
54
54
  - 🔒 [Strict doubles](#strict-doubles--fail-on-a-method-nobody-configured) — `strict: true` / `onUnstubbedCall` fail on a method nobody configured, naming the class, the method and the arguments instead of answering `undefined`
55
55
  - ♻️ `using spy = createSpyFromClass(X)` — every double carries `[Symbol.dispose]`, so the `afterEach` that only reset one spy can go
@@ -58,7 +58,7 @@ identical API, with **RxJS** spies and **Angular / NestJS / React / Vue·Pinia /
58
58
  - ⏳ Waiting that is not a guess — `flushEventLoop`, `settleDynamicImport`, `flushEventLoopUntil`, and a clock that survives fake timers (`mockSystemTime`, `useCountingClock`)
59
59
  - 🌀 `fakeAsync` / `waitForAsync` on Vitest — one import of `vitest-auto-spy/zone`; zone.js stays out of every other entry
60
60
  - 🧩 Module mocks that prove they applied — `assertMocked`, `moduleNamespace`, for a `vi.mock()` a bundler quietly ignored
61
- - 🧾 Fixtures without casts — deep-partial `createMock`, `narrow()`, `withOverrides()`, `asInstances()`, `captureArg()`
61
+ - 🧾 Fixtures without casts — deep-partial `createMock`, `createFixture` / `createFixtureFactory`, `narrow()`, `withOverrides()`, `asInstances()`, `captureArg()`
62
62
  - 🚚 A migration you can verify — `compareTestRuns` on the two JSON reports, `diffByField` for the assertion the reporter collapses
63
63
  - 📏 Lint rules and one-line test-run hygiene — fourteen rules in `vitest-auto-spy/eslint-plugin` (two `--fix`, six suggestions), `setupAutoSpy()`
64
64
  - 🩺 [Editor diagnostics](#editor-diagnostics--webstorm--vs-code) — the same anti-patterns underlined while you type: native ESLint inspections in **WebStorm** and the other JetBrains IDEs, the ESLint extension in **VS Code**, no extra plugin either way
@@ -1171,6 +1171,40 @@ Rule of thumb: `createAutoMock` for a collaborator you **call** and assert on, `
1171
1171
  data shape you **read**. `createMock` is also the one place the `as` lives, so a suite under a
1172
1172
  `no-type-assertion` lint rule stops sprinkling `eslint-disable` over its fixtures.
1173
1173
 
1174
+ ### A model many specs build — `createFixture` / `createFixtureFactory`
1175
+
1176
+ `createMock` answers "this spec reads two fields of a big shape". The other habit is more expensive:
1177
+ a model with seventeen required fields, each with its own nested interface, copied into every spec
1178
+ that needs one. Measured on one migration shard, those copies alone produced **28 `TS1117`**
1179
+ diagnostics — a duplicate key in a literal, where the runtime keeps the *second* one.
1180
+
1181
+ ```ts
1182
+ import { createFixtureFactory } from 'vitest-auto-spy';
1183
+
1184
+ // article.fixture.ts — the model, written out once and checked in full
1185
+ export const anArticle = createFixtureFactory<Article>({
1186
+ id: '1',
1187
+ header: { title: '', subtitle: 'none' },
1188
+ tags: [],
1189
+ publishedAt: new Date(0),
1190
+ });
1191
+
1192
+ // in a spec — name only what this test is about
1193
+ const draft = anArticle({ header: { title: 'Draft' } }); // header.subtitle survives
1194
+ ```
1195
+
1196
+ `defaults` is a **complete** `T`, and that is the point rather than a chore: a field the model
1197
+ dropped six months ago fails in one place instead of in eight copies nobody re-checks. `Partial<T>`
1198
+ and `as T` both delete that diagnostic. Overrides are deep-partial-checked and merge leaf by leaf; an
1199
+ overridden array replaces the default one outright.
1200
+
1201
+ Every call returns a **new object**, and the defaults are copied when the factory is built — a
1202
+ fixture shared by reference is the most common way one test's mutation decides another's outcome, and
1203
+ under `isolate: false` that reaches across files. The copy is deep through plain objects and arrays
1204
+ and stops there: a `Date`, a `Map` or a class instance is carried across by reference rather than
1205
+ rebuilt without its prototype. For defaults that *are* a class instance with getters, snapshot them
1206
+ with `withOverrides()` first.
1207
+
1174
1208
  ## Synchronous methods
1175
1209
 
1176
1210
  ```ts
@@ -1813,6 +1847,8 @@ single-purpose utility you can pick up independently — they all ride on the sa
1813
1847
  | `createFunctionSpy(name)` | core | A single standalone function spy with the full helper set (`calledWith`, `resolveWith`, `nextWith`, …) — no class needed |
1814
1848
  | `createAutoMock<T>(overrides?)` | core | Proxy-based spy from a **type/interface** alone ([details](#auto-mock-by-type-no-class-needed)) |
1815
1849
  | `createMock<T>(partial?)` | core | A plain, spy-free `T` built from the fields a test seeds — for data shapes, not collaborators |
1850
+ | `createFixture<T>(defaults, overrides?)` | core | One `T` from a complete, checked default plus what this test changes — a fresh copy every call |
1851
+ | `createFixtureFactory<T>(defaults)` | core | Somewhere to put that default: returns `(overrides?) => T`, with the defaults pinned at build time |
1816
1852
  | `createObservableWithValues(configs, opts?)` | `/rxjs` | Build a fake `Observable` emitting a precise sequence of values / errors / completion |
1817
1853
  | `consoleInfoSpy` / `consoleWarnSpy` / … | `/console` | Silent typed spies over the global `console`, installed on import ([details](#console-spies--vitest-auto-spyconsole)) |
1818
1854
  | `mockReadonlyProp(obj, prop, value)` | `/angular` | Overwrite a `readonly` property (incl. Angular signals) with a static value |
@@ -1850,6 +1886,7 @@ single-purpose utility you can pick up independently — they all ride on the sa
1850
1886
  | `registerFocusMatchers()` | `/setup` | Adds `expect(el).toHaveFocus()`, which names _why_ focus is elsewhere |
1851
1887
  | `overrideAutoSpy(Token, config?)` / `overrideComponentProvider(Cmp, Token, config?)` | `/angular` | Replace a dependency a component declares in its own `providers` |
1852
1888
  | `assertNgModuleScopes(...modules)` | `/angular` | Fail early when an AOT test bundle left an NgModule with no runtime declarations |
1889
+ | `assertComponentDefIntact(...components)` | `/angular` | Fail before rendering when a half-loaded barrel chunk left a hole in a component's own `providers` or scope |
1853
1890
  | `enableAngularDiagnostics(opts?)` / `assertNoPendingRequests()` | `/angular` | Dead NgModule imports, dead `schemas`, an unspied provider and unflushed HTTP requests, as failures ([details](#diagnostics--four-silent-failures-made-loud)) |
1854
1891
  | `trackInjections(tokens, opts?)` | `/angular`, `/nestjs` | Which collaborators DI actually constructed, recorded through provider factories — with the doubles attached |
1855
1892
  | `mockSignalProp(obj, prop, initial)` | `/angular` | Replace a signal-valued property with a real `WritableSignal`, and hand the writable handle back |
@@ -2342,6 +2379,31 @@ asSpy(TestBed.inject(CartService)); // CartService → Spy<CartService>, for the
2342
2379
 
2343
2380
  Both are the same object at runtime; only the view changes.
2344
2381
 
2382
+ ### Error → cure
2383
+
2384
+ Keyed by what the compiler prints, because that is what you have when you get there. The helper
2385
+ names are unfindable from these messages otherwise — no `TS2739` text contains the word `asInstance`.
2386
+
2387
+ | Message | What actually happened | Cure |
2388
+ | ------------------------------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------- |
2389
+ | `TS2352 … 'Spy<X>' … Property 'accessorSpies' is missing in type 'X'` | `x as Spy<X>`, written by hand | `asSpy(x)` — never a double assertion |
2390
+ | `TS2739` / `TS2740`: `'Spy<X>' is missing … ` + a list of **private** fields | a spy handed to an API typed against `X` | `asInstance(spy)` |
2391
+ | `TS2345: Argument of type 'Spy<X>' is not assignable to parameter of type 'X'` | the same, in an argument | `asInstance(spy)`, or `asInstances(a, b, c)` |
2392
+ | `TS2322: Type 'Spy<X>' is not assignable to type 'Mocked<X>' …` | the variable was declared `Mocked<T>` | declare it `Spy<T>` |
2393
+ | `'AddPromiseSpyMethods<unknown>' is missing … from type 'WithMockReturnValue<…>'` | a generic class inferred as `Service<any>` | `asSpy<Service>(…)` / `injectSpy<Service>(…)` |
2394
+ | `TS2739 … 'Spy<X>' is missing …` **on a line with `injectSpy`** | the provider handed back the real object | `provideAutoSpy(X)`, or an honest `TestBed.inject` |
2395
+
2396
+ Two notes that cost real time when they are missing.
2397
+
2398
+ **The last row is word for word the second one**, and that is a property of the language rather than
2399
+ a flaw in the table: one message serves two different mistakes. The tell is the line it lands on.
2400
+
2401
+ **The error count does not go down monotonically.** TypeScript stops checking a call at the first bad
2402
+ argument, so "one error left" means "as many as there are unfixed arguments" — one file counted
2403
+ 40 → 1 → 1 → 1 → 0. Excess-property checking stops at the first unknown key of a literal for the same
2404
+ reason. The useful heuristic: if a file already contains one `asInstance`, it almost certainly needs
2405
+ another, and the next one is in that same file.
2406
+
2345
2407
  ## API reference
2346
2408
 
2347
2409
  | Export | Description |
@@ -2349,6 +2411,7 @@ Both are the same object at runtime; only the view changes.
2349
2411
  | `createSpyFromClass(Class, methodsOrConfig?)` | Build a fully-typed `Spy<T>` from a class |
2350
2412
  | `createAutoMock<T>(overrides?, config?)` | Build a `Spy<T>` from a **type/interface** alone (Proxy, no class); `{ returns, observablePropsToSpyOn }` configure it |
2351
2413
  | `createMock<T>(partial?)` | Build a plain, spy-free `T` from the fields a test seeds — for data shapes the code under test reads |
2414
+ | `createFixture<T>(defaults, overrides?)` / `createFixtureFactory<T>(defaults)` | A model written out and checked once, stamped into a fresh copy per test — for the fixture eight specs would otherwise each keep a copy of |
2352
2415
  | `mockDeep<T>(overrides?, options?)` | Build a **recursive** auto-mock — `mock.repo.user.find()` chains without seeding; `{ selfReturning: true }` chains through calls too |
2353
2416
  | `resetAutoSpy(spy)` / `clearAutoSpy(spy)` | Reset every spy in an auto-spy at once — `reset` also reverts return-value config (`calledWith` **and** a bare `mockReturnValue`); `clear` keeps it |
2354
2417
  | `spy[Symbol.dispose]()` | What `using spy = createSpyFromClass(X)` runs at the end of the block — `resetAutoSpy(this)`, on every double including each `mockDeep` node |
@@ -2371,7 +2434,7 @@ Both are the same object at runtime; only the view changes.
2371
2434
  | `autoMocked<T>(overrides?)` | `createAutoMock` typed as `T & Spy<T>` |
2372
2435
  | `mockSystemTime` / `withSystemTime` / `mockNow` / `useCountingClock` _(`/setup`)_ | Clock control that survives fake timers being re-installed per test |
2373
2436
  | `registerFocusMatchers()` _(`/setup`)_ | Adds `expect(el).toHaveFocus()` |
2374
- | `overrideAutoSpy` / `overrideComponentProvider` / `assertNgModuleScopes` _(Angular)_ | Override a component-level provider — and verify on the next fixture that the override applied; diagnose an NgModule with an empty runtime scope |
2437
+ | `overrideAutoSpy` / `overrideComponentProvider` / `assertNgModuleScopes` / `assertComponentDefIntact` _(Angular)_ | Override a component-level provider — and verify on the next fixture that the override applied; diagnose an NgModule with an empty runtime scope |
2375
2438
  | `enableAngularDiagnostics(opts?)` / `disableAngularDiagnostics()` / `assertNoPendingRequests()` _(Angular)_ | Dead NgModule imports, dead `schemas`, an unspied provider and unflushed HTTP requests, as failures |
2376
2439
  | `trackInjections(tokens, opts?)` _(Angular, NestJS)_ | Providers that record which collaborators DI constructed, with an auto-spy behind each token |
2377
2440
  | `setupAutoSpy(opts?)` _(`/setup`)_ | Property restore + duplicate-copy detection + mock-registry hygiene, in one call |
package/dist/angular.d.ts CHANGED
@@ -35,6 +35,12 @@ import 'vitest';
35
35
  * landed. So {@link overrideComponentProvider} also checks, on the next `TestBed.createComponent`,
36
36
  * that the component's own injector really answers with the spy — see {@link verifyOnNextCreate}
37
37
  * for why that check is always on rather than an opt-in diagnostic.
38
+ *
39
+ * The same AOT bundle is behind the two assertions at the end of the file.
40
+ * {@link assertNgModuleScopes} covers the module whose scope the bundler stripped;
41
+ * {@link assertComponentDefIntact} covers the component whose own definition was built while the
42
+ * chunk holding one of its providers had not run yet. Neither fixes a build — both replace a stack
43
+ * inside `@angular/core` with a line naming the thing that is missing.
38
44
  */
39
45
 
40
46
  /** The `{ useValue }` shape `TestBed.overrideProvider` expects, carrying an auto-spy. */
@@ -75,6 +81,39 @@ declare function overrideAutoSpy<T>(ObjectClass: ClassType<T>, methodsToSpyOnOrC
75
81
  * runtime scope the bundler has stripped — leaving the component with none of them.
76
82
  */
77
83
  declare function overrideComponentProvider<T>(component: Type<unknown>, ObjectClass: ClassType<T>, methodsToSpyOnOrConfig?: ClassSpyConfiguration<T> | OnlyMethodKeysOf<T>[]): Spy<T>;
84
+ /**
85
+ * Fail before rendering when a component's own definition has holes in it.
86
+ *
87
+ * Providers are **baked into `ɵcmp` when the component's module executes**, not read at
88
+ * `createComponent` time. So when a bundler splits a barrel into a chunk that has not run yet, the
89
+ * definition is built with `undefined` where a provider or a scope dependency should be, and Angular
90
+ * discovers it much later, from inside itself:
91
+ *
92
+ * ```
93
+ * TypeError: Cannot read properties of undefined (reading 'provide')
94
+ * ❯ resolveProvider render3/di_setup.ts:95
95
+ * ```
96
+ *
97
+ * The stack names neither the barrel, nor the symbol, nor the component — and the spec it breaks is
98
+ * usually one nobody touched, because chunk boundaries move with file *contents*: editing a type in
99
+ * a neighbouring file is enough. Both documented cures fail, too, and for the same reason: an
100
+ * `await import()` in `beforeEach` is already too late, and a static import at the top of the spec
101
+ * does not fix the order this bundler emits.
102
+ *
103
+ * ```ts
104
+ * assertComponentDefIntact(HoverMenuComponent);
105
+ * const fixture = TestBed.createComponent(HoverMenuComponent);
106
+ * ```
107
+ *
108
+ * The same call answers the related `Cannot read properties of undefined (reading 'ɵcmp')` from
109
+ * `imports: [Cmp]`, where the class reference itself is the thing that never arrived.
110
+ *
111
+ * This does not fix the build — that is a bundler configuration question — but it turns a
112
+ * half-hour investigation into one line, and points it away from the spec.
113
+ *
114
+ * @param components The component (or directive) classes a spec is about to render or import.
115
+ */
116
+ declare function assertComponentDefIntact(...components: unknown[]): void;
78
117
  /**
79
118
  * Fail early when an NgModule imported into the TestBed contributes nothing at runtime.
80
119
  *
@@ -576,4 +615,4 @@ declare function reportSpecTiming(timing: SpecTiming): void;
576
615
  */
577
616
  declare function enableTestBedDiagnostics(options?: TestBedDiagnosticsOptions): void;
578
617
 
579
- export { type AngularDiagnosticsOptions, type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyOverride, type DirectiveHostOptions, type MockedResource, type ResourceDouble, type ResourceDoubleStatus, type ResourceLike, type SignalLike, type SpecTiming, type TestBedDiagnosticsOptions, assertNgModuleScopes, assertNoPendingRequests, createDirectiveHost, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockResourceProp, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
618
+ export { type AngularDiagnosticsOptions, type AngularTestEnvMode, type AngularTestEnvOptions, type AutoSpyOverride, type DirectiveHostOptions, type MockedResource, type ResourceDouble, type ResourceDoubleStatus, type ResourceLike, type SignalLike, type SpecTiming, type TestBedDiagnosticsOptions, assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, createDirectiveHost, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, formatSpecTiming, getTestBedTiming, instrumentTestBed, mockResourceProp, mockSignalProp, overrideAutoSpy, overrideComponentProvider, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, reportSpecTiming, setupAngularTestEnv };
package/dist/angular.js CHANGED
@@ -1402,6 +1402,66 @@ function moduleName(module) {
1402
1402
  const name = readProperty(module, "name");
1403
1403
  return typeof name === "string" ? name : String(module);
1404
1404
  }
1405
+ var DEFINITION_LISTS = ["providers", "viewProviders", "dependencies"];
1406
+ function resolveList(list) {
1407
+ if (typeof list !== "function") {
1408
+ return list;
1409
+ }
1410
+ try {
1411
+ const produced = Reflect.apply(list, void 0, []);
1412
+ return produced;
1413
+ } catch {
1414
+ return void 0;
1415
+ }
1416
+ }
1417
+ function collectHoles(list, path, holes) {
1418
+ const resolved = resolveList(list);
1419
+ if (!Array.isArray(resolved)) {
1420
+ return;
1421
+ }
1422
+ resolved.forEach((entry, index) => {
1423
+ const at = `${path}[${index}]`;
1424
+ if (entry === void 0 || entry === null) {
1425
+ holes.push(at);
1426
+ } else if (Array.isArray(entry)) {
1427
+ collectHoles(entry, at, holes);
1428
+ }
1429
+ });
1430
+ }
1431
+ function definitionOf(type) {
1432
+ const component = readProperty(type, "\u0275cmp");
1433
+ if (component !== void 0) {
1434
+ return { definition: component, key: "\u0275cmp" };
1435
+ }
1436
+ const directive = readProperty(type, "\u0275dir");
1437
+ return directive === void 0 ? void 0 : { definition: directive, key: "\u0275dir" };
1438
+ }
1439
+ function assertComponentDefIntact(...components) {
1440
+ components.forEach((component, position) => {
1441
+ const named = moduleName(component);
1442
+ const found = definitionOf(component);
1443
+ if (!found) {
1444
+ throw new Error(
1445
+ withDocs(
1446
+ `[vitest-auto-spy] assertComponentDefIntact(): argument ${position} is ${named}, which carries no \u0275cmp or \u0275dir.
1447
+ Either it is not a component or directive, or the chunk that defines it has not executed yet \u2014 the import resolved to nothing. A barrel split across chunks is the usual cause.`,
1448
+ DOCS_LINKS.angularOverrides
1449
+ )
1450
+ );
1451
+ }
1452
+ const holes = [];
1453
+ DEFINITION_LISTS.forEach((list) => collectHoles(readProperty(found.definition, list), `${named}.${found.key}.${list}`, holes));
1454
+ if (holes.length > 0) {
1455
+ throw new Error(
1456
+ withDocs(
1457
+ `[vitest-auto-spy] ${holes.join(", ")} ${holes.length === 1 ? "is" : "are"} undefined.
1458
+ A component bakes its providers and its scope into the definition when its module executes, so a hole there means the chunk holding that symbol had not run at that moment \u2014 an uninitialised barrel chunk. Angular reports this much later as "Cannot read properties of undefined (reading 'provide')", from inside its own provider resolution.`,
1459
+ DOCS_LINKS.angularOverrides
1460
+ )
1461
+ );
1462
+ }
1463
+ });
1464
+ }
1405
1465
  function assertNgModuleScopes(...modules) {
1406
1466
  const empty = modules.filter(hasEmptyRuntimeScope).map(moduleName);
1407
1467
  if (empty.length === 0) {
@@ -2009,4 +2069,4 @@ function registerSignalMatchers() {
2009
2069
  }
2010
2070
  useVitestAdapter();
2011
2071
 
2012
- export { assertNgModuleScopes, assertNoPendingRequests, countMockedProps, createDirectiveHost, createWithAutoSpies, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, flushEffects, formatSpecTiming, getTestBedTiming, injectSpy, instrumentTestBed, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockResourceProp, mockSignalProp, mockValueProp, overrideAutoSpy, overrideComponentProvider, provideAutoSpy, provideAutoSpyForToken, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, renderShallow, reportSpecTiming, restoreMockedProps, runEffect, settleResource, setupAngularTestEnv, stable, trackInjections };
2072
+ export { assertComponentDefIntact, assertNgModuleScopes, assertNoPendingRequests, countMockedProps, createDirectiveHost, createWithAutoSpies, disableAngularDiagnostics, disableTestBedDiagnostics, enableAngularDiagnostics, enableTestBedDiagnostics, flushEffects, formatSpecTiming, getTestBedTiming, injectSpy, instrumentTestBed, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockResourceProp, mockSignalProp, mockValueProp, overrideAutoSpy, overrideComponentProvider, provideAutoSpy, provideAutoSpyForToken, registerDirectiveMatchers, registerResourceMatchers, registerSignalMatchers, renderShallow, reportSpecTiming, restoreMockedProps, runEffect, settleResource, setupAngularTestEnv, stable, trackInjections };
@@ -1,5 +1,5 @@
1
1
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, S as Spy, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
3
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
4
4
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
@@ -1,7 +1,7 @@
1
1
  import './chunk-Y4YG7UOK.js';
2
2
  import { createSpyForToken } from './chunk-LVLSMH6T.js';
3
3
  import './chunk-NQXXUJPS.js';
4
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
4
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
5
5
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
6
6
  import { createSpyFromClass } from './chunk-B7PDIHEG.js';
7
7
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
package/dist/bun.d.ts CHANGED
@@ -76,6 +76,88 @@ declare function createSpyFromClass<T, Options extends SpyOptions = SpyOptions>(
76
76
  */
77
77
  declare function createMock<T>(partial?: DeepPartial<T>): T;
78
78
 
79
+ /**
80
+ * `createFixture` / `createFixtureFactory` — one checked copy of a data model, handed out fresh.
81
+ *
82
+ * Specs do not only spy; they *build data*, and that is where a suite meets the type checker for
83
+ * the first time. A content model with seventeen required fields, each with its own nested
84
+ * interface, gets copied into every spec that needs it: eight files, a hundred-line literal apiece.
85
+ * The copies then rot independently. Measured on one migration shard, that single habit produced
86
+ * **28 `TS1117`** diagnostics (a duplicate key in a literal — the runtime keeps the *second*, so an
87
+ * automated "drop one" fix silently changes values) and half of the shard's `TS2741`.
88
+ *
89
+ * The two obvious escapes are worse than the problem:
90
+ *
91
+ * - `as T` and `Partial<T>` both delete the diagnostic that made the migration worth doing —
92
+ * `TS2353`, "this fixture still sets a field the model dropped six months ago". A fixture that
93
+ * cannot be wrong about the model is a fixture that never reports the model changed.
94
+ * - {@link createAutoMock} builds an object from a type, but only its **methods**. A data model has
95
+ * none, so the machine walks straight past the place the errors actually are.
96
+ *
97
+ * So the answer is not another way to skip the fields. It is somewhere to *put* them once:
98
+ * {@link createFixtureFactory} takes a complete, fully checked `T` — every required field, every
99
+ * removed field rejected, one place for the compiler to point at — and returns a function that
100
+ * stamps out copies with per-test changes applied. The check happens once; the fifty call sites
101
+ * that follow name only what they care about.
102
+ *
103
+ * **Each call returns a new object.** That is not a performance footnote — a fixture shared by
104
+ * reference across a file is the most common way one test's mutation decides another test's
105
+ * outcome, and under `isolate: false` the sharing reaches across files. The copy is deep through
106
+ * plain objects and arrays and stops there: a `Date`, a `Map`, a DOM node or a class instance is
107
+ * carried across by reference, because rebuilding one would strip its prototype — accessors
108
+ * included — and hand back something that is no longer the model it claims to be. When the defaults
109
+ * *are* a class instance with getters, snapshot it with {@link withOverrides} first and hand the
110
+ * result here.
111
+ *
112
+ * | | `createMock<T>()` | `createFixture<T>()` |
113
+ * | --- | --- | --- |
114
+ * | Input | the fields this test reads | a complete `T`, plus what this test changes |
115
+ * | Unnamed fields | `undefined` at runtime | the default's value |
116
+ * | Use it for | a shape read shallowly, once | a model many specs build, read deeply, and mutate |
117
+ */
118
+
119
+ /** Stamps out one fixture per call. What {@link createFixtureFactory} returns. */
120
+ type FixtureFactory<T> = (overrides?: DeepPartial<T>) => T;
121
+ /**
122
+ * Build one `T` from a complete default and the fields this test changes.
123
+ *
124
+ * ```ts
125
+ * const article = createFixture<Article>(ARTICLE_DEFAULTS, { header: { title: 'Draft' } });
126
+ * ```
127
+ *
128
+ * `defaults` is a whole `T`, so a field the model removed is a compile error here rather than a
129
+ * value nothing reads; `overrides` is checked at every depth against the same type. Sibling fields
130
+ * of an overridden leaf are kept — `header.subtitle` above survives — while an overridden array
131
+ * replaces the default one entirely.
132
+ *
133
+ * Reach for {@link createFixtureFactory} as soon as a second spec needs the same defaults; reach
134
+ * for {@link createMock} when there are no meaningful defaults to begin with and the test reads two
135
+ * fields of a large shape.
136
+ *
137
+ * @param defaults A complete `T`. Checked in full: missing and removed fields both fail here.
138
+ * @param overrides The fields this fixture changes, checked against `T` at every depth.
139
+ */
140
+ declare function createFixture<T>(defaults: T, overrides?: DeepPartial<T>): T;
141
+ /**
142
+ * Somewhere to put a fixture, so that the model is written out and checked exactly once.
143
+ *
144
+ * ```ts
145
+ * // article.fixture.ts — one file, one checked literal
146
+ * export const anArticle = createFixtureFactory<Article>({ id: '1', header: { title: '', subtitle: '' }, tags: [], … });
147
+ *
148
+ * // in a spec
149
+ * const draft = anArticle({ header: { title: 'Draft' } });
150
+ * const tagged = anArticle({ tags: ['news'] });
151
+ * ```
152
+ *
153
+ * The defaults are copied when the factory is built, so a later edit to the object that was passed
154
+ * in cannot reach a fixture already handed out — and every call returns a fresh copy, so one test
155
+ * mutating what it was given cannot decide what the next one sees.
156
+ *
157
+ * @param defaults A complete `T`, checked once, here.
158
+ */
159
+ declare function createFixtureFactory<T>(defaults: T): FixtureFactory<T>;
160
+
79
161
  /**
80
162
  * Behaviour switches for {@link mockDeep}.
81
163
  *
@@ -1105,4 +1187,4 @@ interface ResizeEntryRect {
1105
1187
  */
1106
1188
  declare function resizeEntry(target: Element, rect?: ResizeEntryRect): ResizeObserverEntry;
1107
1189
 
1108
- export { AddSpyMethodsByReturnTypes, type ArgCaptor, type AsInstances, type AssertMockedOptions, ClassSpyConfiguration, ClassType, type ConstructorMock, type ConstructorSpy, DeepMockProxy, DeepPartial, type FlushUntilOptions, Func, type IntersectionObserverStubOptions, type MediaElementState, type MediaElementStub, type MediaElementStubOptions, type MockDeepOptions, type ModuleNamespace, type ModuleNamespaceOptions, type MutationRecordInit, type ObserverGlobal, type ObserverInstance, type ObserverStub, type ObserverStubOptions, OnlyMethodKeysOf, type ResizeEntryRect, Spy, SpyOptions, type TestRunComparison, type TestRunReport, type TestRunSummary, UnstubbedCallHandler, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
1190
+ export { AddSpyMethodsByReturnTypes, type ArgCaptor, type AsInstances, type AssertMockedOptions, ClassSpyConfiguration, ClassType, type ConstructorMock, type ConstructorSpy, DeepMockProxy, DeepPartial, type FixtureFactory, type FlushUntilOptions, Func, type IntersectionObserverStubOptions, type MediaElementState, type MediaElementStub, type MediaElementStubOptions, type MockDeepOptions, type ModuleNamespace, type ModuleNamespaceOptions, type MutationRecordInit, type ObserverGlobal, type ObserverInstance, type ObserverStub, type ObserverStubOptions, OnlyMethodKeysOf, type ResizeEntryRect, Spy, SpyOptions, type TestRunComparison, type TestRunReport, type TestRunSummary, UnstubbedCallHandler, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
package/dist/bun.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import './chunk-Y4YG7UOK.js';
2
2
  import './chunk-NQXXUJPS.js';
3
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
3
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
4
4
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
5
5
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
6
6
  export { createFunctionSpy, errorHandler } from './chunk-3AWKPZCE.js';
@@ -9,6 +9,54 @@ function createMock(partial) {
9
9
  return partial ?? {};
10
10
  }
11
11
 
12
+ // src/lib/fixture.ts
13
+ var FORBIDDEN_KEY = "__proto__";
14
+ function isPlainRecord(value) {
15
+ if (typeof value !== "object" || value === null) {
16
+ return false;
17
+ }
18
+ const prototype = Object.getPrototypeOf(value);
19
+ return prototype === Object.prototype || prototype === null;
20
+ }
21
+ function copyValue(value) {
22
+ if (Array.isArray(value)) {
23
+ return value.map(copyValue);
24
+ }
25
+ return isPlainRecord(value) ? copyRecord(value) : value;
26
+ }
27
+ function copyRecord(record) {
28
+ const copy = {};
29
+ Object.keys(record).forEach((key) => {
30
+ if (key !== FORBIDDEN_KEY) {
31
+ copy[key] = copyValue(record[key]);
32
+ }
33
+ });
34
+ return copy;
35
+ }
36
+ function mergeValue(base, override) {
37
+ if (isPlainRecord(base) && isPlainRecord(override)) {
38
+ return mergeRecord(base, override);
39
+ }
40
+ return copyValue(override);
41
+ }
42
+ function mergeRecord(base, override) {
43
+ const merged = copyRecord(base);
44
+ Object.keys(override).forEach((key) => {
45
+ if (key !== FORBIDDEN_KEY) {
46
+ merged[key] = key in base ? mergeValue(base[key], override[key]) : copyValue(override[key]);
47
+ }
48
+ });
49
+ return merged;
50
+ }
51
+ function createFixture(defaults, overrides) {
52
+ const copy = copyValue(defaults);
53
+ return overrides === void 0 ? copy : mergeValue(copy, overrides);
54
+ }
55
+ function createFixtureFactory(defaults) {
56
+ const pinned = copyValue(defaults);
57
+ return (overrides) => createFixture(pinned, overrides);
58
+ }
59
+
12
60
  // src/lib/mock-deep.ts
13
61
  function collectKeys(value) {
14
62
  const keys = /* @__PURE__ */ new Set();
@@ -753,4 +801,4 @@ function resizeEntry(target, rect = {}) {
753
801
  return entry;
754
802
  }
755
803
 
756
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, diffByField, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
804
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, diffByField, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
@@ -307,6 +307,86 @@ function isFloatingChain(call) {
307
307
  return current.parent.type === "ExpressionStatement";
308
308
  }
309
309
 
310
+ // src/lib/eslint/hand-rolled-doubles.ts
311
+ function looksLikeHandRolledMock(object) {
312
+ return buildsRunnerFnAtModuleScope(object);
313
+ }
314
+ function providedDouble(context, value) {
315
+ if (isObjectExpression(value)) {
316
+ return value;
317
+ }
318
+ if (!isIdentifier(value)) {
319
+ return void 0;
320
+ }
321
+ const initializer = initializerOf(context.sourceCode.getScope(value), value);
322
+ return initializer && isObjectExpression(initializer) ? initializer : void 0;
323
+ }
324
+ function countRunnerFns(object) {
325
+ return object.properties.filter((property) => propertyName(property) !== void 0 && isRunnerFnCall(propertyValue(property))).length;
326
+ }
327
+ var TOKEN_NAME = /^[\dA-Z_]+$/;
328
+ function buildsInjectionToken(node) {
329
+ return node !== void 0 && isNewExpression(node) && isIdentifier(node.callee) && node.callee.name === "InjectionToken";
330
+ }
331
+ function providesToken(context, provide) {
332
+ if (!isIdentifier(provide)) {
333
+ return false;
334
+ }
335
+ return buildsInjectionToken(initializerOf(context.sourceCode.getScope(provide), provide)) || TOKEN_NAME.test(provide.name);
336
+ }
337
+ function handRolledProvider(context, useValue, useFactory) {
338
+ if (useValue) {
339
+ const double = providedDouble(context, useValue.value);
340
+ return double && looksLikeHandRolledMock(double) ? useValue : void 0;
341
+ }
342
+ return useFactory && buildsRunnerFn(factoryBody(context, useFactory.value), true) ? useFactory : void 0;
343
+ }
344
+ function factoryBody(context, value) {
345
+ if (!isIdentifier(value)) {
346
+ return value;
347
+ }
348
+ return initializerOf(context.sourceCode.getScope(value), value) ?? value;
349
+ }
350
+ var SPY_FACTORIES = /* @__PURE__ */ new Set([
351
+ "autoMocked",
352
+ "createAutoMock",
353
+ "createMock",
354
+ "createSpyClass",
355
+ "createSpyFromClass",
356
+ "mockConstructor",
357
+ "mockDeep",
358
+ "provideAutoSpy",
359
+ "provideAutoSpyForToken"
360
+ ]);
361
+ function isFactoryCall(node) {
362
+ return isCallExpression(node) && isIdentifier(node.callee) && SPY_FACTORIES.has(node.callee.name);
363
+ }
364
+ function insideFactorySeed(node) {
365
+ let current = node;
366
+ while (current.type !== "Program") {
367
+ if (isFactoryCall(current)) {
368
+ return true;
369
+ }
370
+ current = current.parent;
371
+ }
372
+ return false;
373
+ }
374
+ var MODULE_MOCKS = /* @__PURE__ */ new Set(["doMock", "mock"]);
375
+ function minRunnerFns(context) {
376
+ const configured = Reflect.get(Object(context.options[0]), "minRunnerFns");
377
+ return typeof configured === "number" ? configured : 2;
378
+ }
379
+ function insideModuleMock(node) {
380
+ let current = node;
381
+ while (current.type !== "Program") {
382
+ if (isRunnerCall(current, MODULE_MOCKS)) {
383
+ return true;
384
+ }
385
+ current = current.parent;
386
+ }
387
+ return false;
388
+ }
389
+
310
390
  // src/lib/eslint/import-time-spread.ts
311
391
  var IMPORT_DEFINITION2 = "ImportBinding";
312
392
  function spreadOfImport(context, node) {
@@ -798,45 +878,6 @@ function defineRule(options) {
798
878
  create: options.create
799
879
  };
800
880
  }
801
- function looksLikeHandRolledMock(object) {
802
- return buildsRunnerFnAtModuleScope(object);
803
- }
804
- function providedDouble(context, value) {
805
- if (isObjectExpression(value)) {
806
- return value;
807
- }
808
- if (!isIdentifier(value)) {
809
- return void 0;
810
- }
811
- const initializer = initializerOf(context.sourceCode.getScope(value), value);
812
- return initializer && isObjectExpression(initializer) ? initializer : void 0;
813
- }
814
- function countRunnerFns(object) {
815
- return object.properties.filter((property) => propertyName(property) !== void 0 && isRunnerFnCall(propertyValue(property))).length;
816
- }
817
- var TOKEN_NAME = /^[\dA-Z_]+$/;
818
- function buildsInjectionToken(node) {
819
- return node !== void 0 && isNewExpression(node) && isIdentifier(node.callee) && node.callee.name === "InjectionToken";
820
- }
821
- function providesToken(context, provide) {
822
- if (!isIdentifier(provide)) {
823
- return false;
824
- }
825
- return buildsInjectionToken(initializerOf(context.sourceCode.getScope(provide), provide)) || TOKEN_NAME.test(provide.name);
826
- }
827
- function handRolledProvider(context, useValue, useFactory) {
828
- if (useValue) {
829
- const double = providedDouble(context, useValue.value);
830
- return double && looksLikeHandRolledMock(double) ? useValue : void 0;
831
- }
832
- return useFactory && buildsRunnerFn(factoryBody(context, useFactory.value), true) ? useFactory : void 0;
833
- }
834
- function factoryBody(context, value) {
835
- if (!isIdentifier(value)) {
836
- return value;
837
- }
838
- return initializerOf(context.sourceCode.getScope(value), value) ?? value;
839
- }
840
881
  var preferProvideAutoSpy = defineRule({
841
882
  anchor: "-a-service-behind-angular-di",
842
883
  description: "Provide a spied service with provideAutoSpy() instead of a hand-rolled useValue object",
@@ -858,45 +899,6 @@ var preferProvideAutoSpy = defineRule({
858
899
  }
859
900
  })
860
901
  });
861
- var SPY_FACTORIES = /* @__PURE__ */ new Set([
862
- "autoMocked",
863
- "createAutoMock",
864
- "createMock",
865
- "createSpyClass",
866
- "createSpyFromClass",
867
- "mockConstructor",
868
- "mockDeep",
869
- "provideAutoSpy",
870
- "provideAutoSpyForToken"
871
- ]);
872
- function isFactoryCall(node) {
873
- return isCallExpression(node) && isIdentifier(node.callee) && SPY_FACTORIES.has(node.callee.name);
874
- }
875
- function insideFactorySeed(node) {
876
- let current = node;
877
- while (current.type !== "Program") {
878
- if (isFactoryCall(current)) {
879
- return true;
880
- }
881
- current = current.parent;
882
- }
883
- return false;
884
- }
885
- var MODULE_MOCKS = /* @__PURE__ */ new Set(["doMock", "mock"]);
886
- function minRunnerFns(context) {
887
- const configured = Reflect.get(Object(context.options[0]), "minRunnerFns");
888
- return typeof configured === "number" ? configured : 2;
889
- }
890
- function insideModuleMock(node) {
891
- let current = node;
892
- while (current.type !== "Program") {
893
- if (isRunnerCall(current, MODULE_MOCKS)) {
894
- return true;
895
- }
896
- current = current.parent;
897
- }
898
- return false;
899
- }
900
902
  var preferCreateSpyFromClass = defineRule({
901
903
  anchor: "-a-service-without-di",
902
904
  description: "Build a spy from the class (createSpyFromClass / createAutoMock) instead of an object of vi.fn()s",
@@ -305,6 +305,86 @@ function isFloatingChain(call) {
305
305
  return current.parent.type === "ExpressionStatement";
306
306
  }
307
307
 
308
+ // src/lib/eslint/hand-rolled-doubles.ts
309
+ function looksLikeHandRolledMock(object) {
310
+ return buildsRunnerFnAtModuleScope(object);
311
+ }
312
+ function providedDouble(context, value) {
313
+ if (isObjectExpression(value)) {
314
+ return value;
315
+ }
316
+ if (!isIdentifier(value)) {
317
+ return void 0;
318
+ }
319
+ const initializer = initializerOf(context.sourceCode.getScope(value), value);
320
+ return initializer && isObjectExpression(initializer) ? initializer : void 0;
321
+ }
322
+ function countRunnerFns(object) {
323
+ return object.properties.filter((property) => propertyName(property) !== void 0 && isRunnerFnCall(propertyValue(property))).length;
324
+ }
325
+ var TOKEN_NAME = /^[\dA-Z_]+$/;
326
+ function buildsInjectionToken(node) {
327
+ return node !== void 0 && isNewExpression(node) && isIdentifier(node.callee) && node.callee.name === "InjectionToken";
328
+ }
329
+ function providesToken(context, provide) {
330
+ if (!isIdentifier(provide)) {
331
+ return false;
332
+ }
333
+ return buildsInjectionToken(initializerOf(context.sourceCode.getScope(provide), provide)) || TOKEN_NAME.test(provide.name);
334
+ }
335
+ function handRolledProvider(context, useValue, useFactory) {
336
+ if (useValue) {
337
+ const double = providedDouble(context, useValue.value);
338
+ return double && looksLikeHandRolledMock(double) ? useValue : void 0;
339
+ }
340
+ return useFactory && buildsRunnerFn(factoryBody(context, useFactory.value), true) ? useFactory : void 0;
341
+ }
342
+ function factoryBody(context, value) {
343
+ if (!isIdentifier(value)) {
344
+ return value;
345
+ }
346
+ return initializerOf(context.sourceCode.getScope(value), value) ?? value;
347
+ }
348
+ var SPY_FACTORIES = /* @__PURE__ */ new Set([
349
+ "autoMocked",
350
+ "createAutoMock",
351
+ "createMock",
352
+ "createSpyClass",
353
+ "createSpyFromClass",
354
+ "mockConstructor",
355
+ "mockDeep",
356
+ "provideAutoSpy",
357
+ "provideAutoSpyForToken"
358
+ ]);
359
+ function isFactoryCall(node) {
360
+ return isCallExpression(node) && isIdentifier(node.callee) && SPY_FACTORIES.has(node.callee.name);
361
+ }
362
+ function insideFactorySeed(node) {
363
+ let current = node;
364
+ while (current.type !== "Program") {
365
+ if (isFactoryCall(current)) {
366
+ return true;
367
+ }
368
+ current = current.parent;
369
+ }
370
+ return false;
371
+ }
372
+ var MODULE_MOCKS = /* @__PURE__ */ new Set(["doMock", "mock"]);
373
+ function minRunnerFns(context) {
374
+ const configured = Reflect.get(Object(context.options[0]), "minRunnerFns");
375
+ return typeof configured === "number" ? configured : 2;
376
+ }
377
+ function insideModuleMock(node) {
378
+ let current = node;
379
+ while (current.type !== "Program") {
380
+ if (isRunnerCall(current, MODULE_MOCKS)) {
381
+ return true;
382
+ }
383
+ current = current.parent;
384
+ }
385
+ return false;
386
+ }
387
+
308
388
  // src/lib/eslint/import-time-spread.ts
309
389
  var IMPORT_DEFINITION2 = "ImportBinding";
310
390
  function spreadOfImport(context, node) {
@@ -796,45 +876,6 @@ function defineRule(options) {
796
876
  create: options.create
797
877
  };
798
878
  }
799
- function looksLikeHandRolledMock(object) {
800
- return buildsRunnerFnAtModuleScope(object);
801
- }
802
- function providedDouble(context, value) {
803
- if (isObjectExpression(value)) {
804
- return value;
805
- }
806
- if (!isIdentifier(value)) {
807
- return void 0;
808
- }
809
- const initializer = initializerOf(context.sourceCode.getScope(value), value);
810
- return initializer && isObjectExpression(initializer) ? initializer : void 0;
811
- }
812
- function countRunnerFns(object) {
813
- return object.properties.filter((property) => propertyName(property) !== void 0 && isRunnerFnCall(propertyValue(property))).length;
814
- }
815
- var TOKEN_NAME = /^[\dA-Z_]+$/;
816
- function buildsInjectionToken(node) {
817
- return node !== void 0 && isNewExpression(node) && isIdentifier(node.callee) && node.callee.name === "InjectionToken";
818
- }
819
- function providesToken(context, provide) {
820
- if (!isIdentifier(provide)) {
821
- return false;
822
- }
823
- return buildsInjectionToken(initializerOf(context.sourceCode.getScope(provide), provide)) || TOKEN_NAME.test(provide.name);
824
- }
825
- function handRolledProvider(context, useValue, useFactory) {
826
- if (useValue) {
827
- const double = providedDouble(context, useValue.value);
828
- return double && looksLikeHandRolledMock(double) ? useValue : void 0;
829
- }
830
- return useFactory && buildsRunnerFn(factoryBody(context, useFactory.value), true) ? useFactory : void 0;
831
- }
832
- function factoryBody(context, value) {
833
- if (!isIdentifier(value)) {
834
- return value;
835
- }
836
- return initializerOf(context.sourceCode.getScope(value), value) ?? value;
837
- }
838
879
  var preferProvideAutoSpy = defineRule({
839
880
  anchor: "-a-service-behind-angular-di",
840
881
  description: "Provide a spied service with provideAutoSpy() instead of a hand-rolled useValue object",
@@ -856,45 +897,6 @@ var preferProvideAutoSpy = defineRule({
856
897
  }
857
898
  })
858
899
  });
859
- var SPY_FACTORIES = /* @__PURE__ */ new Set([
860
- "autoMocked",
861
- "createAutoMock",
862
- "createMock",
863
- "createSpyClass",
864
- "createSpyFromClass",
865
- "mockConstructor",
866
- "mockDeep",
867
- "provideAutoSpy",
868
- "provideAutoSpyForToken"
869
- ]);
870
- function isFactoryCall(node) {
871
- return isCallExpression(node) && isIdentifier(node.callee) && SPY_FACTORIES.has(node.callee.name);
872
- }
873
- function insideFactorySeed(node) {
874
- let current = node;
875
- while (current.type !== "Program") {
876
- if (isFactoryCall(current)) {
877
- return true;
878
- }
879
- current = current.parent;
880
- }
881
- return false;
882
- }
883
- var MODULE_MOCKS = /* @__PURE__ */ new Set(["doMock", "mock"]);
884
- function minRunnerFns(context) {
885
- const configured = Reflect.get(Object(context.options[0]), "minRunnerFns");
886
- return typeof configured === "number" ? configured : 2;
887
- }
888
- function insideModuleMock(node) {
889
- let current = node;
890
- while (current.type !== "Program") {
891
- if (isRunnerCall(current, MODULE_MOCKS)) {
892
- return true;
893
- }
894
- current = current.parent;
895
- }
896
- return false;
897
- }
898
900
  var preferCreateSpyFromClass = defineRule({
899
901
  anchor: "-a-service-without-di",
900
902
  description: "Build a spy from the class (createSpyFromClass / createAutoMock) instead of an object of vi.fn()s",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, S as Spy, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
3
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
4
4
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
package/dist/index.js CHANGED
@@ -1054,6 +1054,54 @@ function createMock(partial) {
1054
1054
  return partial ?? {};
1055
1055
  }
1056
1056
 
1057
+ // src/lib/fixture.ts
1058
+ var FORBIDDEN_KEY = "__proto__";
1059
+ function isPlainRecord(value) {
1060
+ if (typeof value !== "object" || value === null) {
1061
+ return false;
1062
+ }
1063
+ const prototype = Object.getPrototypeOf(value);
1064
+ return prototype === Object.prototype || prototype === null;
1065
+ }
1066
+ function copyValue(value) {
1067
+ if (Array.isArray(value)) {
1068
+ return value.map(copyValue);
1069
+ }
1070
+ return isPlainRecord(value) ? copyRecord(value) : value;
1071
+ }
1072
+ function copyRecord(record) {
1073
+ const copy = {};
1074
+ Object.keys(record).forEach((key) => {
1075
+ if (key !== FORBIDDEN_KEY) {
1076
+ copy[key] = copyValue(record[key]);
1077
+ }
1078
+ });
1079
+ return copy;
1080
+ }
1081
+ function mergeValue(base, override) {
1082
+ if (isPlainRecord(base) && isPlainRecord(override)) {
1083
+ return mergeRecord(base, override);
1084
+ }
1085
+ return copyValue(override);
1086
+ }
1087
+ function mergeRecord(base, override) {
1088
+ const merged = copyRecord(base);
1089
+ Object.keys(override).forEach((key) => {
1090
+ if (key !== FORBIDDEN_KEY) {
1091
+ merged[key] = key in base ? mergeValue(base[key], override[key]) : copyValue(override[key]);
1092
+ }
1093
+ });
1094
+ return merged;
1095
+ }
1096
+ function createFixture(defaults, overrides) {
1097
+ const copy = copyValue(defaults);
1098
+ return overrides === void 0 ? copy : mergeValue(copy, overrides);
1099
+ }
1100
+ function createFixtureFactory(defaults) {
1101
+ const pinned = copyValue(defaults);
1102
+ return (overrides) => createFixture(pinned, overrides);
1103
+ }
1104
+
1057
1105
  // src/lib/mock-deep.ts
1058
1106
  function collectKeys(value) {
1059
1107
  const keys = /* @__PURE__ */ new Set();
@@ -1922,4 +1970,4 @@ function resizeEntry(target, rect = {}) {
1922
1970
  // src/index.ts
1923
1971
  registerMockAdapter(vitestMockAdapter);
1924
1972
 
1925
- export { asInstance, asInstances, asSpy, assertMocked, autoMocked, captureArg, clearAutoSpy, compareTestRuns, countMockedProps, createAutoMock, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockAccessorsProp, mockConstructor, mockDeep, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, restoreMockedProps, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
1973
+ export { asInstance, asInstances, asSpy, assertMocked, autoMocked, captureArg, clearAutoSpy, compareTestRuns, countMockedProps, createAutoMock, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockAccessorsProp, mockConstructor, mockDeep, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, restoreMockedProps, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides };
package/dist/node.cjs CHANGED
@@ -1222,6 +1222,54 @@ function createMock(partial) {
1222
1222
  return partial ?? {};
1223
1223
  }
1224
1224
 
1225
+ // src/lib/fixture.ts
1226
+ var FORBIDDEN_KEY = "__proto__";
1227
+ function isPlainRecord(value) {
1228
+ if (typeof value !== "object" || value === null) {
1229
+ return false;
1230
+ }
1231
+ const prototype = Object.getPrototypeOf(value);
1232
+ return prototype === Object.prototype || prototype === null;
1233
+ }
1234
+ function copyValue(value) {
1235
+ if (Array.isArray(value)) {
1236
+ return value.map(copyValue);
1237
+ }
1238
+ return isPlainRecord(value) ? copyRecord(value) : value;
1239
+ }
1240
+ function copyRecord(record) {
1241
+ const copy = {};
1242
+ Object.keys(record).forEach((key) => {
1243
+ if (key !== FORBIDDEN_KEY) {
1244
+ copy[key] = copyValue(record[key]);
1245
+ }
1246
+ });
1247
+ return copy;
1248
+ }
1249
+ function mergeValue(base, override) {
1250
+ if (isPlainRecord(base) && isPlainRecord(override)) {
1251
+ return mergeRecord(base, override);
1252
+ }
1253
+ return copyValue(override);
1254
+ }
1255
+ function mergeRecord(base, override) {
1256
+ const merged = copyRecord(base);
1257
+ Object.keys(override).forEach((key) => {
1258
+ if (key !== FORBIDDEN_KEY) {
1259
+ merged[key] = key in base ? mergeValue(base[key], override[key]) : copyValue(override[key]);
1260
+ }
1261
+ });
1262
+ return merged;
1263
+ }
1264
+ function createFixture(defaults, overrides) {
1265
+ const copy = copyValue(defaults);
1266
+ return overrides === void 0 ? copy : mergeValue(copy, overrides);
1267
+ }
1268
+ function createFixtureFactory(defaults) {
1269
+ const pinned = copyValue(defaults);
1270
+ return (overrides) => createFixture(pinned, overrides);
1271
+ }
1272
+
1225
1273
  // src/lib/mock-deep.ts
1226
1274
  function collectKeys(value) {
1227
1275
  const keys = /* @__PURE__ */ new Set();
@@ -2276,6 +2324,8 @@ exports.clearAutoSpy = clearAutoSpy;
2276
2324
  exports.compareTestRuns = compareTestRuns;
2277
2325
  exports.countMockedProps = countMockedProps;
2278
2326
  exports.createAutoMock = createAutoMock;
2327
+ exports.createFixture = createFixture;
2328
+ exports.createFixtureFactory = createFixtureFactory;
2279
2329
  exports.createFunctionSpy = createFunctionSpy;
2280
2330
  exports.createMock = createMock;
2281
2331
  exports.createSpyClass = createSpyClass;
package/dist/node.d.cts CHANGED
@@ -18,6 +18,8 @@ export declare const clearAutoSpy: typeof Entry.clearAutoSpy;
18
18
  export declare const compareTestRuns: typeof Entry.compareTestRuns;
19
19
  export declare const countMockedProps: typeof Entry.countMockedProps;
20
20
  export declare const createAutoMock: typeof Entry.createAutoMock;
21
+ export declare const createFixture: typeof Entry.createFixture;
22
+ export declare const createFixtureFactory: typeof Entry.createFixtureFactory;
21
23
  export declare const createFunctionSpy: typeof Entry.createFunctionSpy;
22
24
  export declare const createMock: typeof Entry.createMock;
23
25
  export declare const createSpyClass: typeof Entry.createSpyClass;
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, S as Spy, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
3
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
4
4
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
package/dist/node.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRedefineMockAdapter } from './chunk-NQXXUJPS.js';
2
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
2
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
3
3
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
4
4
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
5
5
  export { createFunctionSpy, errorHandler } from './chunk-3AWKPZCE.js';
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, S as Spy, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
3
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
4
4
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { vitestMockAdapter } from './chunk-MG5EAMZR.js';
2
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
2
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
3
3
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
4
4
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
5
5
  export { createFunctionSpy, errorHandler } from './chunk-3AWKPZCE.js';
package/dist/svelte.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, a as ClassSpyConfiguration, C as ClassType, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, O as OnlyMethodKeysOf, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, S as Spy, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
3
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
4
4
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
package/dist/svelte.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { vitestMockAdapter } from './chunk-MG5EAMZR.js';
2
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
2
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
3
3
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
4
4
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
5
5
  export { createFunctionSpy, errorHandler } from './chunk-3AWKPZCE.js';
package/dist/vue.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { S as Spy, C as ClassType, a as ClassSpyConfiguration, O as OnlyMethodKeysOf } from './types-it6CnDkI.js';
2
2
  export { d as AccessorKeysOf, e as AddAccessorsSpies, f as AddCalledWithObservable, g as AddCalledWithPromise, h as AddCalledWithSpyMethods, A as AddObservableSpyMethods, i as AddPromiseSpyMethods, j as AddSpyMethodsByReturnTypes, k as AddVoidReturnHelpers, b as CompleteValueConfig, D as DeepMockProxy, l as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, m as Mutable, N as NextValueConfig, n as OnlyObservablePropsOf, o as OnlyPropsOf, p as Overload, q as Overloads, P as PropStubValue, r as SpyDisposable, s as SpyOptions, t as StrictSpyConfiguration, U as UnstubbedCall, u as UnstubbedCallHandler, V as ValueConfig, c as ValueConfigPerCall, W as WithMockReturnValue } from './types-it6CnDkI.js';
3
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
3
+ export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, IntersectionObserverStubOptions, MediaElementState, MediaElementStub, MediaElementStubOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, MutationRecordInit, ObserverGlobal, ObserverInstance, ObserverStub, ObserverStubOptions, ResizeEntryRect, TestRunComparison, TestRunReport, TestRunSummary, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, compareTestRuns, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, diffByField, errorHandler, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resetAutoSpy, resizeEntry, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './bun.js';
4
4
  export { A as AutoMockConfiguration, C as CallbackSubscribable, E as EmissionObserver, a as EmissionOptions, b as EmissionSource, S as SubscribableLike, c as autoMocked, d as createAutoMock, e as expectCompletion, f as expectEmission, g as expectEmissions, h as expectError, i as expectNoEmission, s as setEmissionTimeout } from './expect-emission-CuGjE0YR.js';
5
5
  export { A as AccessorImplementations, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as restoreMockedProps } from './prop-mock-IgCwv_40.js';
6
6
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
package/dist/vue.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { vitestMockAdapter } from './chunk-MG5EAMZR.js';
2
- export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-2U3J65A4.js';
2
+ export { asInstance, asInstances, asSpy, assertMocked, captureArg, compareTestRuns, createFixture, createFixtureFactory, createMock, createSpyClass, describeDuplicateCopies, diffByField, expectCompletion, expectEmission, expectEmissions, expectError, expectNoEmission, flushEventLoop, flushEventLoopUntil, formatTestRunComparison, getPackageCopies, intersectionEntry, mockConstructor, mockDeep, moduleNamespace, mutationRecord, narrow, resizeEntry, setEmissionTimeout, settleDynamicImport, stubAbortController, stubConstructor, stubIntersectionObserver, stubMediaElement, stubMutationObserver, stubObserver, stubResizeObserver, summarizeTestRun, withOverrides } from './chunk-FKAXOKP5.js';
3
3
  export { countMockedProps, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, mockValueProp, restoreMockedProps } from './chunk-R4EWAG7Y.js';
4
4
  import { createSpyFromClass } from './chunk-B7PDIHEG.js';
5
5
  export { autoMocked, clearAutoSpy, createAutoMock, createSpyFromClass, resetAutoSpy } from './chunk-B7PDIHEG.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitest-auto-spy",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "description": "Auto-generate fully-typed test spies from a class — across Vitest, Bun and node:test, with Angular/NestJS/React/Vue/Svelte recipes. Drop-in replacement for jest-auto-spies.",
5
5
  "keywords": [
6
6
  "auto-mock",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: vitest-auto-spy
3
- description: Write or fix tests that use vitest-auto-spy — typed spies generated from a class or a type on Vitest, bun:test and node:test. Use when a spec imports `vitest-auto-spy` or any of its subpaths (`/angular`, `/bun-angular`, `/bun`, `/node`, `/rxjs`, `/nestjs`, `/setup`, `/zone`, `/eslint-plugin`), when the user mentions createSpyFromClass, createAutoMock, autoMocked, createMock, mockDeep, createFunctionSpy, provideAutoSpy, provideAutoSpyForToken, injectSpy, renderShallow, createWithAutoSpies, createDirectiveHost, overrideComponentProvider, enableAngularDiagnostics, assertNoPendingRequests, assertNgModuleScopes, setupAngularTestEnv, trackInjections, runEffect, settleResource, mockResourceProp, mockSignalProp, mockReadonlyProp, captureArg, expectEmission, expectError, setupAutoSpy, installPerTest, stubIntersectionObserver, stubMediaElement, stubConstructor, mockSystemTime, assertMocked, moduleNamespace, compareTestRuns, Spy<T>, calledWith, mustBeCalledWith, onlyMethodsToSpyOn, instanceMethodsToSpyOn, observablePropsToSpyOn, strict, onUnstubbedCall, resolveWith or nextWith, when migrating a suite off jest-auto-spies (`npx vitest-auto-spy codemod`), or when a test fails with "No mock adapter registered", "Observable spies require rxjs", "not found on the class prototype", "strict mode is on", "the override did not apply", "is not a constructor", "Expected to be running in 'ProxyZone'" or "Spy<T> is not assignable".
3
+ description: Write or fix tests that use vitest-auto-spy — typed spies generated from a class or a type on Vitest, bun:test and node:test. Use when a spec imports `vitest-auto-spy` or any of its subpaths (`/angular`, `/bun-angular`, `/bun`, `/node`, `/rxjs`, `/nestjs`, `/setup`, `/zone`, `/eslint-plugin`), when the user mentions createSpyFromClass, createAutoMock, autoMocked, createMock, createFixture, createFixtureFactory, mockDeep, createFunctionSpy, provideAutoSpy, provideAutoSpyForToken, injectSpy, renderShallow, createWithAutoSpies, createDirectiveHost, overrideComponentProvider, enableAngularDiagnostics, assertNoPendingRequests, assertNgModuleScopes, assertComponentDefIntact, setupAngularTestEnv, trackInjections, runEffect, settleResource, mockResourceProp, mockSignalProp, mockReadonlyProp, captureArg, expectEmission, expectError, setupAutoSpy, installPerTest, stubIntersectionObserver, stubMediaElement, stubConstructor, mockSystemTime, assertMocked, moduleNamespace, compareTestRuns, Spy<T>, calledWith, mustBeCalledWith, onlyMethodsToSpyOn, instanceMethodsToSpyOn, observablePropsToSpyOn, strict, onUnstubbedCall, resolveWith or nextWith, when migrating a suite off jest-auto-spies (`npx vitest-auto-spy codemod`), or when a test fails with "No mock adapter registered", "Observable spies require rxjs", "not found on the class prototype", "strict mode is on", "the override did not apply", "is not a constructor", "Expected to be running in 'ProxyZone'" or "Spy<T> is not assignable".
4
4
  ---
5
5
 
6
6
  # vitest-auto-spy
@@ -40,6 +40,7 @@ Real class, constructed by you? → createSpyFromClass(Class, config?) → Spy
40
40
  Type only, and it gets CALLED? → createAutoMock<T>(overrides?) → Spy<T>
41
41
  …and calls chain (a.b.c())? → mockDeep<T>(overrides?)
42
42
  Type only, and it is only READ? → createMock<T>(partial?) → plain T, no spies
43
+ …and many specs share it? → createFixtureFactory<T>(defaults) → (overrides?) => T
43
44
  A single function? → createFunctionSpy<Fn>('name')
44
45
  Code does `new Foo()`? → createSpyClass(Foo)
45
46
  ```
@@ -150,6 +151,7 @@ it('loads', async () => {
150
151
  | a dead NgModule import, dead `schemas`, an unflushed HTTP request | `enableAngularDiagnostics()` in the setup file, after `initTestEnvironment` |
151
152
  | "which collaborators did this actually inject?" | `trackInjections([A, TOKEN])` — providers plus the record, not `vi.mock` |
152
153
  | `NG0303` / `NG0301` / `NG0304` from an imported NgModule | `assertNgModuleScopes(Module)` — an AOT bundle stripped its scope |
154
+ | `Cannot read properties of undefined (reading 'provide')` in `di_setup` | `assertComponentDefIntact(Cmp)` — a barrel chunk left a hole in `ɵcmp` |
153
155
  | a focus assertion failing as `expected false to deeply equal true` | `registerFocusMatchers()` + `expect(el).toHaveFocus()` |
154
156
  | a collaborator passed as an argument, then asserted on | `autoMocked<T>()` — typed `T & Spy<T>` |
155
157
  | a `<video>` / `<audio>`: `play()` throws, `duration` is `NaN` | `stubMediaElement({ duration })`, then `media.set(el, …)` |
@@ -167,6 +169,7 @@ it('loads', async () => {
167
169
  | five `asInstance(…)` in one call, found one per `tsc` run | `...asInstances(a, b, c, d, e)` |
168
170
  | `nextWith` demanding `HttpEvent<T>` on a generated client | `asSpy<Client, { overload: 'first' }>(…)` / `Overload<M, 0>` |
169
171
  | a fixture that needs a nested object built by its own call | `createMock<T>({ a: { b: 1 } })` — deep partial, still exact |
172
+ | the same 100-line model literal copied into eight specs (`TS1117`) | one `createFixtureFactory<T>(defaults)`; specs call it with what they change |
170
173
  | `'params' in link` ladders, or a cast, to pick a union branch | `narrow.byKey(link, 'params')` / `narrow.observable(x)` |
171
174
  | `{ ...modelInstance, flag: true }` losing every getter | `withOverrides(modelInstance, { flag: true })` |
172
175
  | `NG0303` / `NG0304` / silence from a directive spec | `createDirectiveHost({ template, scope: [Module] })` |