vitest-auto-spy 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +38 -5
  2. package/README.md +100 -67
  3. package/dist/angular.d.ts +1 -1
  4. package/dist/angular.js +224 -142
  5. package/dist/bun-angular.d.ts +2 -2
  6. package/dist/bun-angular.js +36 -19
  7. package/dist/bun.d.ts +49 -3
  8. package/dist/bun.js +6 -6
  9. package/dist/{chunk-JJ2JA2E3.js → chunk-5AOJI3BM.js} +3 -2
  10. package/dist/{chunk-ED4EVQKA.js → chunk-6YI3G3CH.js} +2 -3
  11. package/dist/{chunk-XRVVZXOM.js → chunk-75GDWUIT.js} +28 -1
  12. package/dist/{chunk-KE3LEHPW.js → chunk-DBDXQXS3.js} +15 -8
  13. package/dist/{chunk-XAS66AWX.js → chunk-EGU3YJJN.js} +2 -29
  14. package/dist/{chunk-J33KX6XT.js → chunk-JOODFKWS.js} +47 -26
  15. package/dist/{chunk-URZIJ5CL.js → chunk-NLDPCJKC.js} +4 -4
  16. package/dist/{chunk-GOG2CJOY.js → chunk-OYQ2PHBU.js} +1 -1
  17. package/dist/{chunk-5TUDM4DS.js → chunk-QY4UO4BB.js} +67 -19
  18. package/dist/{chunk-NHSUUN3D.js → chunk-WWO6CUEJ.js} +1 -1
  19. package/dist/cli.js +51 -10
  20. package/dist/console.js +4 -4
  21. package/dist/dom-stubs.js +70 -50
  22. package/dist/eslint-plugin.cjs +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +172 -98
  25. package/dist/jasmine.js +6 -6
  26. package/dist/nestjs.js +12 -12
  27. package/dist/node.cjs +118 -87
  28. package/dist/node.d.ts +1 -1
  29. package/dist/node.js +8 -7
  30. package/dist/react.d.ts +1 -1
  31. package/dist/react.js +7 -7
  32. package/dist/rstest.d.ts +1 -1
  33. package/dist/rstest.js +9 -8
  34. package/dist/rxjs.js +11 -6
  35. package/dist/setup.js +6 -6
  36. package/dist/shared-state.js +1 -53
  37. package/dist/svelte.d.ts +1 -1
  38. package/dist/svelte.js +7 -7
  39. package/dist/vue.d.ts +1 -1
  40. package/dist/vue.js +8 -8
  41. package/dist/{zoneless-BerZbxtu.d.ts → zoneless-DM1AWQV2.d.ts} +6 -1
  42. package/package.json +3 -2
  43. package/skills/vitest-auto-spy/SKILL.md +10 -3
package/dist/angular.js CHANGED
@@ -1,4 +1,4 @@
1
- import { guardAccessorSpies, registerMockAdapter, getMockAdapter, getObservableSupport, getJasmineSupport, emissionTimeout, requireObservableSupport } from './shared-state.js';
1
+ import { registerMockAdapter, getMockAdapter, getObservableSupport, getJasmineSupport, emissionTimeout, requireObservableSupport } from './shared-state.js';
2
2
  export { setEmissionTimeout } from './shared-state.js';
3
3
  import { vi, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
4
4
  import { TestBed, getTestBed } from '@angular/core/testing';
@@ -23,6 +23,33 @@ function installDisposeSymbol(host) {
23
23
  }
24
24
  var DISPOSE = installDisposeSymbol(Symbol);
25
25
 
26
+ // src/lib/docs-links.ts
27
+ var DOCS = "https://asdalexey.github.io/vitest-auto-spy";
28
+ var DOCS_LINKS = {
29
+ angular: `${DOCS}/adapters/angular`,
30
+ // Their own pages rather than anchors on `adapters/angular`: a reader who hits one of these arrived
31
+ // from a failure, not from reading, and the page they want is the one about that check — not the
32
+ // one about the adapter that hosts it.
33
+ angularDiagnostics: `${DOCS}/adapters/angular-diagnostics`,
34
+ angularOverrides: `${DOCS}/adapters/angular-overrides`,
35
+ createSpyFromClass: `${DOCS}/core/create-spy-from-class`,
36
+ controlHelpers: `${DOCS}/core/control-helpers`,
37
+ // The recipe for the one failure no spy library can work around: a binding the bundler already
38
+ // inlined. Deep-linked to the section rather than the page, because the page's first half is
39
+ // about the *silent* half of the same problem and the reader arriving here has the loud one.
40
+ realSeam: `${DOCS}/utilities/module-mocks#provide-a-real-seam`,
41
+ setup: `${DOCS}/utilities/setup`,
42
+ // Its own page rather than a section of the factory's: the reader arriving here was thrown at by a
43
+ // double they configured somewhere else entirely, and the question they have is what counts as
44
+ // configured — which is the whole page, not a paragraph of another one.
45
+ strictMode: `${DOCS}/core/strict-mode`,
46
+ trackInjections: `${DOCS}/utilities/track-injections`
47
+ };
48
+ function withDocs(message, link) {
49
+ return `${message}
50
+ Docs: ${link}`;
51
+ }
52
+
26
53
  // src/lib/spy-probe.ts
27
54
  var FAST_SPY_BRAND = /* @__PURE__ */ Symbol.for("vitest-auto-spy.fastSpy");
28
55
  function isFastSpy(value) {
@@ -35,6 +62,34 @@ function isThenable(value) {
35
62
  return typeof Reflect.get(value, "then") === "function";
36
63
  }
37
64
 
65
+ // src/lib/spy-decoration.ts
66
+ function detachedHelperError(helper) {
67
+ return new Error(
68
+ withDocs(
69
+ `[vitest-auto-spy] ${helper} was called off its spy: \`const { ${helper} } = spy.method\` loses the spy it configures. Call it as a method \u2014 spy.method.${helper}(\u2026) \u2014 or bind it first.`,
70
+ DOCS_LINKS.controlHelpers
71
+ )
72
+ );
73
+ }
74
+ function decorate(target, helpers) {
75
+ return Object.assign(target, helpers);
76
+ }
77
+ var shareOnPrototype;
78
+ function setSharedHelperSink(share) {
79
+ shareOnPrototype = share;
80
+ }
81
+ var shared = /* @__PURE__ */ new WeakSet();
82
+ function attachHelpers(target, helpers) {
83
+ if (shareOnPrototype === void 0 || !isFastSpy(target)) {
84
+ return decorate(target, helpers);
85
+ }
86
+ if (!shared.has(helpers)) {
87
+ shared.add(helpers);
88
+ shareOnPrototype(helpers);
89
+ }
90
+ return target;
91
+ }
92
+
38
93
  // src/lib/fast-spy.ts
39
94
  var clearEpoch = 0;
40
95
  var resetEpoch = 0;
@@ -50,51 +105,52 @@ var STATE = /* @__PURE__ */ Symbol("vitest-auto-spy.fastSpy.state");
50
105
  var invocationCallCounter = 1;
51
106
  var FastMockStateImpl = class {
52
107
  constructor(owner) {
53
- this.owner = owner;
54
108
  this.recordedCalls = [];
55
109
  this.recordedContexts = [];
56
110
  this.recordedInstances = [];
57
111
  this.recordedOrder = [];
58
112
  this.recordedResults = [];
59
113
  this.recordedSettledResults = [];
114
+ this.#owner = owner;
60
115
  }
116
+ #owner;
61
117
  get calls() {
62
- syncEpochs(this.owner);
118
+ syncEpochs(this.#owner);
63
119
  return this.recordedCalls;
64
120
  }
65
121
  set calls(value) {
66
122
  this.recordedCalls = value;
67
123
  }
68
124
  get contexts() {
69
- syncEpochs(this.owner);
125
+ syncEpochs(this.#owner);
70
126
  return this.recordedContexts;
71
127
  }
72
128
  set contexts(value) {
73
129
  this.recordedContexts = value;
74
130
  }
75
131
  get instances() {
76
- syncEpochs(this.owner);
132
+ syncEpochs(this.#owner);
77
133
  return this.recordedInstances;
78
134
  }
79
135
  set instances(value) {
80
136
  this.recordedInstances = value;
81
137
  }
82
138
  get invocationCallOrder() {
83
- syncEpochs(this.owner);
139
+ syncEpochs(this.#owner);
84
140
  return this.recordedOrder;
85
141
  }
86
142
  set invocationCallOrder(value) {
87
143
  this.recordedOrder = value;
88
144
  }
89
145
  get results() {
90
- syncEpochs(this.owner);
146
+ syncEpochs(this.#owner);
91
147
  return this.recordedResults;
92
148
  }
93
149
  set results(value) {
94
150
  this.recordedResults = value;
95
151
  }
96
152
  get settledResults() {
97
- syncEpochs(this.owner);
153
+ syncEpochs(this.#owner);
98
154
  return this.recordedSettledResults;
99
155
  }
100
156
  set settledResults(value) {
@@ -153,6 +209,12 @@ function definePrototypeMember(key, value) {
153
209
  }
154
210
  definePrototypeMember(FAST_SPY_BRAND, true);
155
211
  definePrototypeMember("_isMockFunction", true);
212
+ function shareFastSpyHelpers(helpers) {
213
+ for (const key of Object.keys(helpers)) {
214
+ definePrototypeMember(key, helpers[key]);
215
+ }
216
+ }
217
+ setSharedHelperSink(shareFastSpyHelpers);
156
218
  Object.defineProperty(FAST_SPY_PROTOTYPE, "mock", {
157
219
  get() {
158
220
  const spy = self(this);
@@ -375,6 +437,33 @@ function createFastSpy(implementation, name) {
375
437
  return spy;
376
438
  }
377
439
 
440
+ // src/lib/redefine-failure.ts
441
+ var CANNOT_REDEFINE = "Cannot redefine property";
442
+ function isCannotRedefine(error) {
443
+ return error instanceof TypeError && error.message.includes(CANNOT_REDEFINE);
444
+ }
445
+ function describeSpyTarget(target) {
446
+ if (Reflect.get(target, Symbol.toStringTag) === "Module") {
447
+ return "an ES module namespace";
448
+ }
449
+ if (Object.isFrozen(target)) {
450
+ return "a frozen object";
451
+ }
452
+ const constructor = Reflect.get(target, "constructor");
453
+ const name = typeof constructor === "function" ? constructor.name : void 0;
454
+ return name === void 0 || name === "Object" ? "a plain object" : `an instance of ${name}`;
455
+ }
456
+ var REDEFINE_ADVICE = "An ES module namespace is what a bundler leaves behind once it has inlined a barrel or a workspace alias (`@angular/build:unit-test`, a pre-bundled `vite-node` entry): the export is a live binding, not a writable property, and no spy library \u2014 this one, `vi.spyOn`, `jest.spyOn` \u2014 can replace it. `vi.mock()` of the same module is the silent version of this failure, not the fix.\nGive the code under test a real seam and spy on that: inject the dependency, pass it in as an argument, or reach it through a class or object your own code owns.";
457
+ function redefineFailure(lead, target, cause) {
458
+ return new Error(
459
+ withDocs(`[vitest-auto-spy] ${lead} The target is ${describeSpyTarget(target)}.
460
+ ${REDEFINE_ADVICE}`, DOCS_LINKS.realSeam),
461
+ {
462
+ cause
463
+ }
464
+ );
465
+ }
466
+
378
467
  // src/lib/redefine-accessor-spy.ts
379
468
  function spyOnAccessorByRedefine(createMockFn, target, property, type) {
380
469
  const existing = Object.getOwnPropertyDescriptor(target, property);
@@ -395,6 +484,27 @@ function spyOnAccessorByRedefine(createMockFn, target, property, type) {
395
484
  Object.defineProperty(target, property, descriptor);
396
485
  return mock;
397
486
  }
487
+ function spyOrExplain(spy, target, property, accessor) {
488
+ try {
489
+ return spy();
490
+ } catch (error) {
491
+ if (isCannotRedefine(error)) {
492
+ throw redefineFailure(
493
+ `Cannot spy on the '${accessor}' accessor of '${property}': the property is not configurable, so it cannot be redefined.`,
494
+ target,
495
+ error
496
+ );
497
+ }
498
+ throw error;
499
+ }
500
+ }
501
+ function guardAccessorSpies(adapter) {
502
+ return {
503
+ ...adapter,
504
+ spyOnGetter: (target, property) => spyOrExplain(() => adapter.spyOnGetter(target, property), target, property, "get"),
505
+ spyOnSetter: (target, property) => spyOrExplain(() => adapter.spyOnSetter(target, property), target, property, "set")
506
+ };
507
+ }
398
508
 
399
509
  // src/lib/vitest-adapter.ts
400
510
  function asVitestMock(mock) {
@@ -462,33 +572,6 @@ function useVitestAdapter() {
462
572
  registerMockAdapter(vitestMockAdapter);
463
573
  }
464
574
 
465
- // src/lib/docs-links.ts
466
- var DOCS = "https://asdalexey.github.io/vitest-auto-spy";
467
- var DOCS_LINKS = {
468
- angular: `${DOCS}/adapters/angular`,
469
- // Their own pages rather than anchors on `adapters/angular`: a reader who hits one of these arrived
470
- // from a failure, not from reading, and the page they want is the one about that check — not the
471
- // one about the adapter that hosts it.
472
- angularDiagnostics: `${DOCS}/adapters/angular-diagnostics`,
473
- angularOverrides: `${DOCS}/adapters/angular-overrides`,
474
- createSpyFromClass: `${DOCS}/core/create-spy-from-class`,
475
- controlHelpers: `${DOCS}/core/control-helpers`,
476
- // The recipe for the one failure no spy library can work around: a binding the bundler already
477
- // inlined. Deep-linked to the section rather than the page, because the page's first half is
478
- // about the *silent* half of the same problem and the reader arriving here has the loud one.
479
- realSeam: `${DOCS}/utilities/module-mocks#provide-a-real-seam`,
480
- setup: `${DOCS}/utilities/setup`,
481
- // Its own page rather than a section of the factory's: the reader arriving here was thrown at by a
482
- // double they configured somewhere else entirely, and the question they have is what counts as
483
- // configured — which is the whole page, not a paragraph of another one.
484
- strictMode: `${DOCS}/core/strict-mode`,
485
- trackInjections: `${DOCS}/utilities/track-injections`
486
- };
487
- function withDocs(message, link) {
488
- return `${message}
489
- Docs: ${link}`;
490
- }
491
-
492
575
  // src/lib/serialize-args.ts
493
576
  function createContext() {
494
577
  return { seen: /* @__PURE__ */ new WeakSet(), cache: /* @__PURE__ */ new Map(), circularHits: 0 };
@@ -851,19 +934,6 @@ Actual: ${actualCall(functionName, actualArgs)}`;
851
934
  })
852
935
  };
853
936
 
854
- // src/lib/spy-decoration.ts
855
- function detachedHelperError(helper) {
856
- return new Error(
857
- withDocs(
858
- `[vitest-auto-spy] ${helper} was called off its spy: \`const { ${helper} } = spy.method\` loses the spy it configures. Call it as a method \u2014 spy.method.${helper}(\u2026) \u2014 or bind it first.`,
859
- DOCS_LINKS.controlHelpers
860
- )
861
- );
862
- }
863
- function decorate(target, helpers) {
864
- return Object.assign(target, helpers);
865
- }
866
-
867
937
  // src/lib/promise-spy.ts
868
938
  function toResolvedPerCallValues(valueConfigsPerCall) {
869
939
  return valueConfigsPerCall.map(
@@ -1077,13 +1147,25 @@ function ensureCalledWithObject(state, chain) {
1077
1147
  return created;
1078
1148
  }
1079
1149
  var FunctionSpyInternals = class {
1150
+ /** Built on the first stream helper, not on every spy — see {@link ObservableSupport.streamForFunctionSpy}. */
1151
+ #observable = void 0;
1080
1152
  constructor(state, valueContainer, host, dispatch, recorder) {
1081
1153
  this.state = state;
1082
1154
  this.valueContainer = valueContainer;
1083
1155
  this.host = host;
1084
1156
  this.dispatch = dispatch;
1085
1157
  this.recorder = recorder;
1086
- this.observable = void 0;
1158
+ }
1159
+ /**
1160
+ * The rxjs layer's state for this spy, materialised on first use.
1161
+ *
1162
+ * Reaching it means a stream helper is running, which means the `/rxjs` entry is loaded — so this
1163
+ * requires the support rather than testing for it, and a spy that never sees a stream helper never
1164
+ * pays for the object.
1165
+ */
1166
+ get observable() {
1167
+ this.#observable ??= requireObservableSupport().streamForFunctionSpy(this.valueContainer);
1168
+ return this.#observable;
1087
1169
  }
1088
1170
  /**
1089
1171
  * `resetAutoSpy` reverts this spy's configuration; the state lives here, where the host runner's
@@ -1098,7 +1180,7 @@ var FunctionSpyInternals = class {
1098
1180
  delete valueContainer._isRejectedPromise;
1099
1181
  delete valueContainer._isThrown;
1100
1182
  delete valueContainer.valuesPerCalls;
1101
- this.observable?.reset();
1183
+ this.#observable?.reset();
1102
1184
  getMockAdapter().restoreImplementation(this.host, this.dispatch);
1103
1185
  }
1104
1186
  /** Empties the polyfilled `settledResults` on `clearAutoSpy` / `resetAutoSpy` (a no-op on Vitest, where the host clears its native array). */
@@ -1150,8 +1232,8 @@ function createFunctionSpy(name, unstubbed) {
1150
1232
  const recorder = installSettledResultsPolyfill(functionSpy);
1151
1233
  settledResultsRecorder = recorder.record;
1152
1234
  const internals = new FunctionSpyInternals(state, valueContainer, functionSpy, dispatch, recorder);
1153
- const spy = decorate(functionSpy, SPY_HELPERS);
1154
- internals.observable = getObservableSupport()?.addToFunctionSpy(spy, valueContainer);
1235
+ const spy = attachHelpers(functionSpy, SPY_HELPERS);
1236
+ getObservableSupport()?.addToFunctionSpy(spy);
1155
1237
  getJasmineSupport()?.addToFunctionSpy(spy, {
1156
1238
  name,
1157
1239
  restoreDispatch: () => {
@@ -1225,18 +1307,6 @@ function readStoredAccessor(store, key, receiver) {
1225
1307
  }
1226
1308
  return accessor.get?.call(receiver);
1227
1309
  }
1228
- function storeWriteTraps(store) {
1229
- return {
1230
- set(_target, key, value, receiver) {
1231
- if (!writeStoredAccessor(store, key, value, receiver)) {
1232
- writeStoredValue(store, key, value);
1233
- }
1234
- return true;
1235
- },
1236
- defineProperty: (_target, key, descriptor) => storeDefinedProp(store, key, descriptor),
1237
- deleteProperty: (_target, key) => dropStoredProp(store, key)
1238
- };
1239
- }
1240
1310
  var NOT_STORED = /* @__PURE__ */ Symbol("vitest-auto-spy.notStored");
1241
1311
  var PROTOCOL_KEYS = /* @__PURE__ */ new Set(["schedule", "lift", "@@observable", "getReader"]);
1242
1312
  function isProtocolKey(key) {
@@ -1301,7 +1371,8 @@ function attachDispose(spy) {
1301
1371
  // src/lib/auto-mock.ts
1302
1372
  function createAutoMock(overrides, config) {
1303
1373
  const unstubbed = resolveUnstubbedGuard(void 0, { strict: config?.strict, onUnstubbedCall: config?.onUnstubbedCall });
1304
- const mock = new Proxy({}, createAutoMockHandler(overrides ?? {}, unstubbed));
1374
+ const target = { [INTERNALS]: { store: createProxyPropStore(overrides ?? {}), unstubbed } };
1375
+ const mock = new Proxy(target, AUTO_MOCK_HANDLER);
1305
1376
  applyObservableProps(mock, config?.observablePropsToSpyOn);
1306
1377
  applyMockReturns(mock, config?.returns);
1307
1378
  return mock;
@@ -1340,20 +1411,35 @@ function applyMockReturns(mock, returns) {
1340
1411
  adapter.restoreImplementation(spy, () => value);
1341
1412
  }
1342
1413
  }
1343
- function createAutoMockHandler(seed, unstubbed) {
1344
- const store = createProxyPropStore(seed);
1345
- return {
1346
- get: (_target, key, receiver) => readKey(store, key, receiver, unstubbed),
1347
- ...storeWriteTraps(store),
1348
- has(_target, key) {
1349
- return key === AUTO_SPY_MARK || key === DISPOSE || hasStoredProp(store, key);
1350
- },
1351
- ownKeys() {
1352
- return [.../* @__PURE__ */ new Set([...store.values.keys(), ...store.accessors.keys()])];
1353
- },
1354
- getOwnPropertyDescriptor: (_target, key) => describeStoredProp(store, key)
1355
- };
1414
+ var INTERNALS = /* @__PURE__ */ Symbol("vitest-auto-spy.autoMock.internals");
1415
+ function internalsOf2(target) {
1416
+ return Reflect.get(target, INTERNALS);
1356
1417
  }
1418
+ var AUTO_MOCK_HANDLER = {
1419
+ get(target, key, receiver) {
1420
+ const { store, unstubbed } = internalsOf2(target);
1421
+ return readKey(store, key, receiver, unstubbed);
1422
+ },
1423
+ // The traps that route every write into the store — see `proxy-props.ts` for why their absence
1424
+ // was silent rather than loud.
1425
+ set(target, key, value, receiver) {
1426
+ const { store } = internalsOf2(target);
1427
+ if (!writeStoredAccessor(store, key, value, receiver)) {
1428
+ writeStoredValue(store, key, value);
1429
+ }
1430
+ return true;
1431
+ },
1432
+ defineProperty: (target, key, descriptor) => storeDefinedProp(internalsOf2(target).store, key, descriptor),
1433
+ deleteProperty: (target, key) => dropStoredProp(internalsOf2(target).store, key),
1434
+ has(target, key) {
1435
+ return key === AUTO_SPY_MARK || key === DISPOSE || hasStoredProp(internalsOf2(target).store, key);
1436
+ },
1437
+ ownKeys(target) {
1438
+ const { store } = internalsOf2(target);
1439
+ return [.../* @__PURE__ */ new Set([...store.values.keys(), ...store.accessors.keys()])];
1440
+ },
1441
+ getOwnPropertyDescriptor: (target, key) => describeStoredProp(internalsOf2(target).store, key)
1442
+ };
1357
1443
  function readKey(store, key, receiver, unstubbed) {
1358
1444
  const patched = readStoredAccessor(store, key, receiver);
1359
1445
  if (patched !== NOT_STORED) {
@@ -1375,15 +1461,13 @@ function readKey(store, key, receiver, unstubbed) {
1375
1461
  store.values.set(key, spy);
1376
1462
  return spy;
1377
1463
  }
1464
+ var NOOP_GETTER = function noopGetter() {
1465
+ return void 0;
1466
+ };
1467
+ var NOOP_SETTER = function noopSetter(_value) {
1468
+ };
1378
1469
  function defineWithEmptyAccessors(obj, prop) {
1379
- Object.defineProperty(obj, prop, {
1380
- get() {
1381
- return void 0;
1382
- },
1383
- set(_value) {
1384
- },
1385
- configurable: true
1386
- });
1470
+ Object.defineProperty(obj, prop, { get: NOOP_GETTER, set: NOOP_SETTER, configurable: true });
1387
1471
  }
1388
1472
  function spyOnAccessor(autoSpy, accessorName, accessorType) {
1389
1473
  const adapter = getMockAdapter();
@@ -1781,35 +1865,6 @@ function hasNothingToRead(ObjectClass, accessors, config) {
1781
1865
  // conflict: they ask for names to be present, which the proxy already guarantees.
1782
1866
  config.onlyMethodsToSpyOn.length === 0;
1783
1867
  }
1784
-
1785
- // src/lib/redefine-failure.ts
1786
- var CANNOT_REDEFINE = "Cannot redefine property";
1787
- function isCannotRedefine(error) {
1788
- return error instanceof TypeError && error.message.includes(CANNOT_REDEFINE);
1789
- }
1790
- function describeSpyTarget(target) {
1791
- if (Reflect.get(target, Symbol.toStringTag) === "Module") {
1792
- return "an ES module namespace";
1793
- }
1794
- if (Object.isFrozen(target)) {
1795
- return "a frozen object";
1796
- }
1797
- const constructor = Reflect.get(target, "constructor");
1798
- const name = typeof constructor === "function" ? constructor.name : void 0;
1799
- return name === void 0 || name === "Object" ? "a plain object" : `an instance of ${name}`;
1800
- }
1801
- var REDEFINE_ADVICE = "An ES module namespace is what a bundler leaves behind once it has inlined a barrel or a workspace alias (`@angular/build:unit-test`, a pre-bundled `vite-node` entry): the export is a live binding, not a writable property, and no spy library \u2014 this one, `vi.spyOn`, `jest.spyOn` \u2014 can replace it. `vi.mock()` of the same module is the silent version of this failure, not the fix.\nGive the code under test a real seam and spy on that: inject the dependency, pass it in as an argument, or reach it through a class or object your own code owns.";
1802
- function redefineFailure(lead, target, cause) {
1803
- return new Error(
1804
- withDocs(`[vitest-auto-spy] ${lead} The target is ${describeSpyTarget(target)}.
1805
- ${REDEFINE_ADVICE}`, DOCS_LINKS.realSeam),
1806
- {
1807
- cause
1808
- }
1809
- );
1810
- }
1811
-
1812
- // src/lib/prop-mock.ts
1813
1868
  var sharedEpoch;
1814
1869
  function propEpoch() {
1815
1870
  return sharedEpoch ??= globalThis.__vitestAutoSpyPropEpoch__ ??= { current: 0 };
@@ -2262,8 +2317,9 @@ function readProperty(value, key) {
2262
2317
  return Reflect.get(value, key);
2263
2318
  }
2264
2319
  function isEmptyList(value) {
2265
- return value === void 0 || Array.isArray(value) && value.flat(Infinity).length === 0;
2320
+ return value === void 0 || Array.isArray(value) && value.every((entry) => Array.isArray(entry) && isEmptyList(entry));
2266
2321
  }
2322
+ var deadModuleVerdicts = /* @__PURE__ */ new WeakMap();
2267
2323
  function hasEmptyRuntimeScope(module) {
2268
2324
  const definition = readProperty(module, "\u0275mod");
2269
2325
  if (definition === void 0) {
@@ -2272,11 +2328,18 @@ function hasEmptyRuntimeScope(module) {
2272
2328
  return isEmptyList(readProperty(definition, "declarations")) && isEmptyList(readProperty(definition, "exports"));
2273
2329
  }
2274
2330
  function isDeadNgModuleImport(module) {
2275
- if (!hasEmptyRuntimeScope(module)) {
2331
+ const definition = readProperty(module, "\u0275mod");
2332
+ if (typeof definition !== "object" || definition === null) {
2276
2333
  return false;
2277
2334
  }
2335
+ const cached = deadModuleVerdicts.get(definition);
2336
+ if (cached !== void 0) {
2337
+ return cached;
2338
+ }
2278
2339
  const injector = readProperty(module, "\u0275inj");
2279
- return isEmptyList(readProperty(injector, "providers")) && isEmptyList(readProperty(injector, "imports"));
2340
+ const dead = isEmptyList(readProperty(definition, "declarations")) && isEmptyList(readProperty(definition, "exports")) && isEmptyList(readProperty(injector, "providers")) && isEmptyList(readProperty(injector, "imports"));
2341
+ deadModuleVerdicts.set(definition, dead);
2342
+ return dead;
2280
2343
  }
2281
2344
  function moduleName(module) {
2282
2345
  const name = readProperty(module, "name");
@@ -2388,17 +2451,20 @@ Drop the \`schemas\` entry, then put the missing directive, component or pipe in
2388
2451
  );
2389
2452
  }
2390
2453
  var HTTP_TESTING_CONTROLLER = "HttpTestingController";
2391
- function flattenProviders(value, into) {
2454
+ function forEachProvider(value, visit) {
2392
2455
  if (Array.isArray(value)) {
2393
- value.forEach((entry) => flattenProviders(entry, into));
2456
+ value.forEach((entry) => forEachProvider(entry, visit));
2394
2457
  return;
2395
2458
  }
2396
2459
  const wrapped = readProperty(value, "\u0275providers");
2397
2460
  if (wrapped === void 0) {
2398
- into.push(value);
2461
+ visit(value);
2399
2462
  return;
2400
2463
  }
2401
- flattenProviders(wrapped, into);
2464
+ forEachProvider(wrapped, visit);
2465
+ }
2466
+ function flattenProviders(value, into) {
2467
+ forEachProvider(value, (provider) => into.push(provider));
2402
2468
  }
2403
2469
  function findControllerToken(providers) {
2404
2470
  const flat = [];
@@ -2472,16 +2538,15 @@ Flush each one (\`controller.expectOne('/url').flush(body)\`), or call \`control
2472
2538
  );
2473
2539
  }
2474
2540
  var moduleDoubles = /* @__PURE__ */ new Map();
2541
+ function rememberModuleDouble(provider) {
2542
+ const token = readProperty(provider, "provide");
2543
+ const useValue = readProperty(provider, "useValue");
2544
+ if (token !== void 0 && isAutoSpyLike(useValue) && readProperty(provider, "multi") !== true) {
2545
+ moduleDoubles.set(token, useValue);
2546
+ }
2547
+ }
2475
2548
  function collectModuleDoubles(config) {
2476
- const flat = [];
2477
- flattenProviders(readProperty(config, "providers"), flat);
2478
- flat.forEach((provider) => {
2479
- const token = readProperty(provider, "provide");
2480
- const useValue = readProperty(provider, "useValue");
2481
- if (token !== void 0 && isAutoSpyLike(useValue) && readProperty(provider, "multi") !== true) {
2482
- moduleDoubles.set(token, useValue);
2483
- }
2484
- });
2549
+ forEachProvider(readProperty(config, "providers"), rememberModuleDouble);
2485
2550
  }
2486
2551
  function tokenName(token) {
2487
2552
  const name = readProperty(token, "name");
@@ -2747,27 +2812,44 @@ function createWithAutoSpies(target, options = {}) {
2747
2812
  }
2748
2813
  };
2749
2814
  }
2750
- function isStandalone3(component) {
2751
- const definition = Reflect.get(component, "\u0275cmp");
2815
+ var PERMISSIVE_SCHEMAS = [NO_ERRORS_SCHEMA];
2816
+ var NOTHING = [];
2817
+ function isStandalone3(definition) {
2752
2818
  return typeof definition === "object" && definition !== null && Reflect.get(definition, "standalone") === true;
2753
2819
  }
2754
- function buildOverride(component, options) {
2820
+ function importsOf(definition) {
2821
+ const dependencies = Reflect.get(definition, "dependencies");
2822
+ return dependencies();
2823
+ }
2824
+ function isChildComponent(dependency) {
2825
+ return Reflect.get(dependency, "\u0275cmp") !== void 0;
2826
+ }
2827
+ function keptScope(definition, options) {
2828
+ const kept = importsOf(definition).filter((dependency) => !isChildComponent(dependency));
2829
+ kept.push(...options.keepChildren ?? NOTHING);
2830
+ return kept;
2831
+ }
2832
+ function buildOverride(definition, options) {
2755
2833
  const override = {};
2756
- if (isStandalone3(component)) {
2757
- override.imports = options.keepChildren ?? [];
2758
- override.schemas = [NO_ERRORS_SCHEMA];
2834
+ if (isStandalone3(definition)) {
2835
+ override.imports = options.keepTemplate ? keptScope(definition, options) : options.keepChildren ?? NOTHING;
2836
+ override.schemas = PERMISSIVE_SCHEMAS;
2759
2837
  }
2760
2838
  if (!options.keepTemplate) {
2761
2839
  override.template = options.template ?? "";
2762
- override.styles = [];
2840
+ override.styles = NOTHING;
2763
2841
  }
2764
2842
  return override;
2765
2843
  }
2766
2844
  function applyInputs(fixture, inputs) {
2767
- Object.entries(inputs ?? {}).forEach(([name, value]) => fixture.componentRef.setInput(name, value));
2845
+ if (inputs === void 0) {
2846
+ return;
2847
+ }
2848
+ Object.entries(inputs).forEach(([name, value]) => fixture.componentRef.setInput(name, value));
2768
2849
  }
2769
2850
  function renderShallow(component, options = {}) {
2770
- const standalone = isStandalone3(component);
2851
+ const definition = Reflect.get(component, "\u0275cmp");
2852
+ const standalone = isStandalone3(definition);
2771
2853
  TestBed.configureTestingModule({
2772
2854
  imports: standalone ? [component, ...options.imports ?? []] : options.imports ?? [],
2773
2855
  declarations: standalone ? [] : [component],
@@ -2775,9 +2857,9 @@ function renderShallow(component, options = {}) {
2775
2857
  // Only where it can do something. A standalone component carries its own dependency scope, so a
2776
2858
  // module-level schema never reaches its template — and `enableAngularDiagnostics({ deadSchemas })`
2777
2859
  // is right to report one, which made these two features of the same package cancel each other out.
2778
- ...standalone ? {} : { schemas: [NO_ERRORS_SCHEMA] }
2860
+ ...standalone ? {} : { schemas: PERMISSIVE_SCHEMAS }
2779
2861
  });
2780
- TestBed.overrideComponent(component, { set: buildOverride(component, options) });
2862
+ TestBed.overrideComponent(component, { set: buildOverride(definition, options) });
2781
2863
  options.beforeCreate?.();
2782
2864
  const fixture = TestBed.createComponent(component);
2783
2865
  applyInputs(fixture, options.inputs);
@@ -1,9 +1,9 @@
1
1
  export { A as AccessorKeysOf, a as AddAccessorsSpies, b as AddCalledWithObservable, c as AddCalledWithPromise, d as AddCalledWithSpyMethods, e as AddObservableSpyMethods, f as AddPromiseSpyMethods, g as AddSpyMethodsByReturnTypes, h as AddThrowHelper, i as AddVoidReturnHelpers, j as AutoSpyRxjsTypes, k as ClassSpyConfiguration, C as ClassType, l as CompleteValueConfig, D as DeepMockProxy, m as DeepPartial, E as ErrorValueConfig, F as Func, M as MethodReturns, n as Mutable, N as NextValueConfig, O as ObservableLike, o as OnlyMethodKeysOf, p as OnlyObservablePropsOf, q as OnlyPropsOf, r as Overload, s as OverloadChoice, t as Overloads, P as PropStubValue, S as Spy, u as SpyDisposable, v as SpyOptions, w as StrictSpyConfiguration, x as SubjectLike, y as SubjectOf, U as UnstubbedCall, z as UnstubbedCallHandler, V as ValueConfig, B as ValueConfigPerCall, W as WithMockReturnValue } from './types-DTi4dIeN.js';
2
- export { ArgCaptor, AsInstances, AssertMockedOptions, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, clearAutoSpyDefaults, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, createSpyFromInstance, errorHandler, flushEventLoop, flushEventLoopUntil, mockConstructor, mockDeep, moduleNamespace, narrow, registerAutoSpyDefaults, resetAutoSpy, restoreSpiedInstance, settleDynamicImport, stubConstructor, withOverrides } from './bun.js';
2
+ export { ArgCaptor, AsInstances, AssertMockedOptions, AutoSpyDefaultEntry, ConstructorMock, ConstructorSpy, FixtureFactory, FlushUntilOptions, MockDeepOptions, ModuleNamespace, ModuleNamespaceOptions, asInstance, asInstances, asSpy, assertMocked, captureArg, clearAutoSpy, clearAutoSpyDefaults, createFixture, createFixtureFactory, createFunctionSpy, createMock, createSpyClass, createSpyFromClass, createSpyFromInstance, errorHandler, flushEventLoop, flushEventLoopUntil, mockConstructor, mockDeep, moduleNamespace, narrow, registerAutoSpyDefaults, resetAutoSpy, restoreSpiedInstance, settleDynamicImport, stubConstructor, 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-DYtyyKM5.js';
4
4
  export { A as AccessorImplementations, O as OutsideHookReaction, R as RestoreProp, c as countMockedProps, m as mockAccessorsProp, a as mockReadonlyProp, b as mockReadonlyPropGetter, d as mockValueProp, r as reportPropsOutsideHooks, e as restoreMockedProps } from './prop-mock-DmM-rPcG.js';
5
5
  export { d as describeDuplicateCopies, g as getPackageCopies } from './package-identity-B1pqa-Sh.js';
6
- export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-BerZbxtu.js';
6
+ export { A as AngularValueProvider, a as AutoSpiedInstance, C as ComponentInputs, b as CreateWithAutoSpiesOptions, R as RenderShallowOptions, c as ResourceStatusLike, S as SettleResourceOptions, d as ShallowRender, e as SpyRegistry, f as StableOptions, g as createWithAutoSpies, h as flushEffects, i as injectSpy, p as provideAutoSpy, r as renderShallow, j as runEffect, s as settleResource, k as stable } from './zoneless-DM1AWQV2.js';
7
7
  import 'vitest';
8
8
  import '@angular/core';
9
9
  import '@angular/core/testing';