vitest-auto-spy 1.0.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/dist/index.js ADDED
@@ -0,0 +1,359 @@
1
+ import { ReplaySubject, from, of, timer, throwError, EMPTY, merge, defer } from 'rxjs';
2
+ import { concatMap, delay, takeWhile, switchMap, takeUntil, take } from 'rxjs/operators';
3
+ import { TestBed } from '@angular/core/testing';
4
+ import { stringify } from 'javascript-stringify';
5
+ import { vi } from 'vitest';
6
+
7
+ // src/auto-spy.ts
8
+ var ArgsMap = class {
9
+ constructor() {
10
+ this.map = {};
11
+ }
12
+ // `stringify` always serializes an argument array to a string, so the cast is safe.
13
+ set(key, value) {
14
+ this.map[stringify(key)] = value;
15
+ }
16
+ get(key) {
17
+ return this.map[stringify(key)];
18
+ }
19
+ };
20
+ var errorHandler = {
21
+ throwArgumentsError(actualArgs, functionName) {
22
+ let errorMessage = `The function '${functionName}' was configured with 'mustBeCalledWith' and expects to be called with specific arguments. `;
23
+ if (actualArgs.length === 0) {
24
+ errorMessage += `But the function was called without any arguments.`;
25
+ } else {
26
+ let formattedArgs = stringify(actualArgs);
27
+ formattedArgs = formattedArgs.substring(1, formattedArgs.length - 1);
28
+ errorMessage += `But the actual arguments were: ${formattedArgs}`;
29
+ }
30
+ throw new Error(errorMessage);
31
+ }
32
+ };
33
+ function createReplaySubject() {
34
+ return new ReplaySubject(1);
35
+ }
36
+ function mergeSubjectWithDefaultValues(subject, valuesConfigs) {
37
+ const onCompleteSubject = new ReplaySubject(1);
38
+ const results$ = from(valuesConfigs).pipe(
39
+ concatMap((valueConfig) => {
40
+ if ("complete" in valueConfig && valueConfig.complete && valueConfig.delay) {
41
+ return of(valueConfig).pipe(delay(valueConfig.delay));
42
+ }
43
+ return of(valueConfig);
44
+ }),
45
+ takeWhile((valueConfig) => {
46
+ if (!("complete" in valueConfig)) {
47
+ return true;
48
+ }
49
+ if (valueConfig.complete) {
50
+ onCompleteSubject.next();
51
+ return false;
52
+ }
53
+ return true;
54
+ }),
55
+ concatMap((valueConfig) => {
56
+ if ("value" in valueConfig && valueConfig.value) {
57
+ if (valueConfig.delay) {
58
+ return of(valueConfig.value).pipe(delay(valueConfig.delay));
59
+ }
60
+ return of(valueConfig.value);
61
+ }
62
+ if ("errorValue" in valueConfig && valueConfig.errorValue) {
63
+ if (valueConfig.delay) {
64
+ return timer(valueConfig.delay).pipe(switchMap(() => throwError(() => valueConfig.errorValue)));
65
+ }
66
+ return throwError(() => valueConfig.errorValue);
67
+ }
68
+ return EMPTY;
69
+ })
70
+ );
71
+ return merge(results$, subject.pipe(takeUntil(onCompleteSubject)));
72
+ }
73
+ function addObservableHelpers(objectToDecorate, providedSubject, onSubjectConfigured) {
74
+ objectToDecorate.nextWith = (value) => {
75
+ providedSubject.next(value);
76
+ onSubjectConfigured(providedSubject);
77
+ };
78
+ objectToDecorate.nextOneTimeWith = (value) => {
79
+ providedSubject.next(value);
80
+ providedSubject.complete();
81
+ onSubjectConfigured(providedSubject);
82
+ };
83
+ objectToDecorate.nextWithValues = (valuesConfigs) => {
84
+ if (valuesConfigs.length === 0) {
85
+ return;
86
+ }
87
+ onSubjectConfigured(mergeSubjectWithDefaultValues(providedSubject, valuesConfigs));
88
+ };
89
+ objectToDecorate.throwWith = (value) => {
90
+ providedSubject.error(value);
91
+ onSubjectConfigured(providedSubject);
92
+ };
93
+ objectToDecorate.complete = () => {
94
+ providedSubject.complete();
95
+ onSubjectConfigured(providedSubject);
96
+ };
97
+ objectToDecorate.returnSubject = () => {
98
+ onSubjectConfigured(providedSubject);
99
+ return providedSubject;
100
+ };
101
+ }
102
+ function addNextWithPerCall(objectToDecorate, returnValueContainer, onConfigured = () => void 0) {
103
+ objectToDecorate.nextWithPerCall = (valueConfigsPerCall) => {
104
+ const returnedSubjects = [];
105
+ if (valueConfigsPerCall.length === 0) {
106
+ return returnedSubjects;
107
+ }
108
+ returnValueContainer.valuesPerCalls = [];
109
+ valueConfigsPerCall.forEach((valueConfiguration) => {
110
+ const replaySubject = new ReplaySubject(1);
111
+ replaySubject.next(valueConfiguration.value);
112
+ returnedSubjects.push(replaySubject);
113
+ let returnedObservable = replaySubject.asObservable();
114
+ if (valueConfiguration.delay) {
115
+ returnedObservable = returnedObservable.pipe(delay(valueConfiguration.delay));
116
+ }
117
+ if (!valueConfiguration.doNotComplete) {
118
+ returnedObservable = returnedObservable.pipe(take(1));
119
+ }
120
+ returnValueContainer.valuesPerCalls.push({ wrappedValue: returnedObservable });
121
+ });
122
+ onConfigured(returnValueContainer);
123
+ return returnedSubjects;
124
+ };
125
+ }
126
+ function addObservableHelpersToFunctionSpy(spyFunction, valueContainer) {
127
+ const subject = createReplaySubject();
128
+ addObservableHelpers(spyFunction, subject, (configuredSubject) => {
129
+ valueContainer.value = configuredSubject;
130
+ });
131
+ addNextWithPerCall(spyFunction, valueContainer);
132
+ }
133
+ function addObservableHelpersToCalledWithObject(calledWithObject, calledWithArgs) {
134
+ const subject = createReplaySubject();
135
+ const returnValueContainer = { value: void 0 };
136
+ addObservableHelpers(calledWithObject, subject, (configuredSubject) => {
137
+ returnValueContainer.value = configuredSubject;
138
+ calledWithObject.argsToValuesMap.set(calledWithArgs, returnValueContainer);
139
+ });
140
+ addNextWithPerCall(calledWithObject, returnValueContainer, (configured) => {
141
+ calledWithObject.argsToValuesMap.set(calledWithArgs, configured);
142
+ });
143
+ }
144
+ function createObservableWithValues(valuesConfigs, config) {
145
+ const subject = createReplaySubject();
146
+ const values$ = mergeSubjectWithDefaultValues(subject, valuesConfigs);
147
+ if (config && config.returnSubject) {
148
+ return { values$, subject };
149
+ }
150
+ return values$;
151
+ }
152
+ function createObservablePropSpy() {
153
+ let subject = createReplaySubject();
154
+ const observableSpy = defer(() => subject);
155
+ addObservableHelpers(observableSpy, subject, (configuredSubject) => {
156
+ subject = configuredSubject;
157
+ });
158
+ return observableSpy;
159
+ }
160
+ function addPromiseHelpersToFunctionSpy(spyFunction, valueContainer) {
161
+ spyFunction.resolveWith = (value) => {
162
+ valueContainer.value = Promise.resolve(value);
163
+ };
164
+ spyFunction.rejectWith = (value) => {
165
+ valueContainer.value = value;
166
+ valueContainer._isRejectedPromise = true;
167
+ };
168
+ spyFunction.resolveWithPerCall = (valueConfigsPerCall) => {
169
+ if (valueConfigsPerCall.length === 0) {
170
+ return;
171
+ }
172
+ valueContainer.valuesPerCalls = [];
173
+ valueConfigsPerCall.forEach((valueConfiguration) => {
174
+ valueContainer.valuesPerCalls.push({
175
+ wrappedValue: Promise.resolve(valueConfiguration.value),
176
+ delay: valueConfiguration.delay
177
+ });
178
+ });
179
+ };
180
+ }
181
+ function addPromiseHelpersToCalledWithObject(calledWithObject, calledWithArgs) {
182
+ calledWithObject.resolveWith = (value) => {
183
+ calledWithObject.argsToValuesMap.set(calledWithArgs, { value: Promise.resolve(value) });
184
+ };
185
+ calledWithObject.rejectWith = (value) => {
186
+ calledWithObject.argsToValuesMap.set(calledWithArgs, { value, _isRejectedPromise: true });
187
+ };
188
+ calledWithObject.resolveWithPerCall = (valueConfigsPerCall) => {
189
+ if (valueConfigsPerCall.length === 0) {
190
+ return;
191
+ }
192
+ const valueContainer = { value: void 0, valuesPerCalls: [] };
193
+ valueConfigsPerCall.forEach((valueConfiguration) => {
194
+ valueContainer.valuesPerCalls.push({
195
+ wrappedValue: Promise.resolve(valueConfiguration.value),
196
+ delay: valueConfiguration.delay
197
+ });
198
+ });
199
+ calledWithObject.argsToValuesMap.set(calledWithArgs, valueContainer);
200
+ };
201
+ }
202
+ function getNextCallValue(valueContainer) {
203
+ const wrapped = valueContainer.valuesPerCalls.shift();
204
+ let returnedValue = wrapped?.wrappedValue;
205
+ if (wrapped && wrapped.delay) {
206
+ returnedValue = returnedValue.then(
207
+ (value) => new Promise((resolve) => setTimeout(() => resolve(value), wrapped.delay))
208
+ );
209
+ }
210
+ return returnedValue;
211
+ }
212
+ function returnTheCorrectFakeValue(calledWithObject, mustBeCalledWithObject, valueContainer, actualArgs, functionName) {
213
+ if (calledWithObject.wasConfigured) {
214
+ const configured = calledWithObject.argsToValuesMap.get(actualArgs);
215
+ if (configured) {
216
+ return unwrapContainer(configured);
217
+ }
218
+ }
219
+ if (mustBeCalledWithObject.wasConfigured) {
220
+ const configured = mustBeCalledWithObject.argsToValuesMap.get(actualArgs);
221
+ if (configured) {
222
+ return unwrapContainer(configured);
223
+ }
224
+ errorHandler.throwArgumentsError(actualArgs, functionName);
225
+ }
226
+ return unwrapContainer(valueContainer);
227
+ }
228
+ function unwrapContainer(container) {
229
+ if (container._isRejectedPromise) {
230
+ return Promise.reject(container.value);
231
+ }
232
+ if (container.valuesPerCalls?.length) {
233
+ return getNextCallValue(container);
234
+ }
235
+ return container.value;
236
+ }
237
+ function addMethodsToCalledWith(calledWith, calledWithArgs) {
238
+ calledWith.wasConfigured = true;
239
+ calledWith.mockReturnValue = (value) => {
240
+ calledWith.argsToValuesMap.set(calledWithArgs, { value });
241
+ };
242
+ addPromiseHelpersToCalledWithObject(calledWith, calledWithArgs);
243
+ addObservableHelpersToCalledWithObject(calledWith, calledWithArgs);
244
+ return calledWith;
245
+ }
246
+ function createFunctionSpy(name) {
247
+ const calledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };
248
+ const mustBeCalledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };
249
+ const valueContainer = { value: void 0 };
250
+ const functionSpy = vi.fn(
251
+ (...actualArgs) => returnTheCorrectFakeValue(calledWithObject, mustBeCalledWithObject, valueContainer, actualArgs, name)
252
+ );
253
+ functionSpy.mockName(name);
254
+ addPromiseHelpersToFunctionSpy(functionSpy, valueContainer);
255
+ addObservableHelpersToFunctionSpy(functionSpy, valueContainer);
256
+ functionSpy.calledWith = (...calledWithArgs) => addMethodsToCalledWith(calledWithObject, calledWithArgs);
257
+ functionSpy.mustBeCalledWith = (...calledWithArgs) => addMethodsToCalledWith(mustBeCalledWithObject, calledWithArgs);
258
+ return functionSpy;
259
+ }
260
+ function defineWithEmptyAccessors(obj, prop) {
261
+ Object.defineProperty(obj, prop, {
262
+ get() {
263
+ return void 0;
264
+ },
265
+ set(_value) {
266
+ },
267
+ configurable: true
268
+ });
269
+ }
270
+ function accessorSpyFactory(autoSpy, accessorName, accessorType) {
271
+ if (accessorType === "setter") {
272
+ return vi.spyOn(autoSpy, accessorName, "set");
273
+ }
274
+ return vi.spyOn(autoSpy, accessorName, "get");
275
+ }
276
+ function createAccessorsSpies(autoSpy, gettersToSpyOn, settersToSpyOn) {
277
+ autoSpy.accessorSpies = { getters: {}, setters: {} };
278
+ gettersToSpyOn.forEach((getterName) => {
279
+ defineWithEmptyAccessors(autoSpy, getterName);
280
+ autoSpy.accessorSpies.getters[getterName] = accessorSpyFactory(autoSpy, getterName, "getter");
281
+ });
282
+ settersToSpyOn.forEach((setterName) => {
283
+ if (!Object.prototype.hasOwnProperty.call(autoSpy, setterName)) {
284
+ defineWithEmptyAccessors(autoSpy, setterName);
285
+ }
286
+ autoSpy.accessorSpies.setters[setterName] = accessorSpyFactory(autoSpy, setterName, "setter");
287
+ });
288
+ }
289
+ function extractMethodsFromObject(obj) {
290
+ const descriptors = Object.getOwnPropertyDescriptors(obj);
291
+ return Object.keys(descriptors).reduce((names, name) => {
292
+ if (name !== "constructor" && !descriptors[name].get) {
293
+ names.push(name);
294
+ }
295
+ return names;
296
+ }, []);
297
+ }
298
+ function getAllMethodNames(obj) {
299
+ let methods = [];
300
+ while (obj) {
301
+ const parentObj = Object.getPrototypeOf(obj);
302
+ if (parentObj) {
303
+ methods = methods.concat(extractMethodsFromObject(obj));
304
+ }
305
+ obj = parentObj;
306
+ }
307
+ return methods;
308
+ }
309
+ function createSpyFromClass(ObjectClass, methodsToSpyOnOrConfig) {
310
+ const methodNames = getAllMethodNames(ObjectClass.prototype);
311
+ let methodsToSpyOn = [];
312
+ let observablePropsToSpyOn = [];
313
+ let settersToSpyOn = [];
314
+ let gettersToSpyOn = [];
315
+ if (methodsToSpyOnOrConfig) {
316
+ if (Array.isArray(methodsToSpyOnOrConfig)) {
317
+ methodsToSpyOn = methodsToSpyOnOrConfig;
318
+ } else {
319
+ methodsToSpyOn = methodsToSpyOnOrConfig.methodsToSpyOn || [];
320
+ observablePropsToSpyOn = methodsToSpyOnOrConfig.observablePropsToSpyOn || [];
321
+ settersToSpyOn = methodsToSpyOnOrConfig.settersToSpyOn || [];
322
+ gettersToSpyOn = methodsToSpyOnOrConfig.gettersToSpyOn || [];
323
+ }
324
+ }
325
+ if (methodsToSpyOn.length > 0) {
326
+ methodNames.push(...methodsToSpyOn);
327
+ }
328
+ const autoSpy = {};
329
+ observablePropsToSpyOn.forEach((observablePropName) => {
330
+ autoSpy[observablePropName] = createObservablePropSpy();
331
+ });
332
+ createAccessorsSpies(autoSpy, gettersToSpyOn, settersToSpyOn);
333
+ methodNames.forEach((methodName) => {
334
+ autoSpy[methodName] = createFunctionSpy(methodName);
335
+ });
336
+ return autoSpy;
337
+ }
338
+ function provideAutoSpy(ObjectClass, methodsToSpyOnOrConfig) {
339
+ return {
340
+ provide: ObjectClass,
341
+ useValue: createSpyFromClass(ObjectClass, methodsToSpyOnOrConfig)
342
+ };
343
+ }
344
+ function injectSpy(token) {
345
+ return TestBed.inject(token);
346
+ }
347
+ function mockReadonlyProp(object, property, value) {
348
+ Object.defineProperty(object, property, { get: () => value, configurable: true });
349
+ }
350
+ function mockReadonlyPropGetter(object, property, getter) {
351
+ Object.defineProperty(object, property, { get: getter, configurable: true });
352
+ }
353
+ function mockAccessorsProp(object, property) {
354
+ Object.defineProperty(object, property, { get: vi.fn(), set: vi.fn(), configurable: true });
355
+ }
356
+
357
+ export { createFunctionSpy, createObservableWithValues, createSpyFromClass, errorHandler, injectSpy, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, provideAutoSpy };
358
+ //# sourceMappingURL=index.js.map
359
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auto-spy.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * vitest-auto-spy\n * ===============\n *\n * Create automatic, fully-typed test spies from a class — powered by Vitest's\n * `vi.fn()`. A drop-in replacement for [`jest-auto-spies`](https://www.npmjs.com/package/jest-auto-spies),\n * with the exact same API surface but spying only on Vitest.\n *\n * ```ts\n * import { createSpyFromClass, provideAutoSpy } from 'vitest-auto-spy';\n * ```\n *\n * --------------------------------------------------------------------------\n * ## createSpyFromClass — the core\n * --------------------------------------------------------------------------\n *\n * ```ts\n * let myService: Spy<MyService>;\n *\n * beforeEach(() => {\n * // every method of MyService becomes a vi.fn()\n * myService = createSpyFromClass(MyService);\n * });\n * ```\n *\n * Restrict what gets spied, or add observable/getter/setter spies:\n *\n * ```ts\n * createSpyFromClass(MyService, ['getName', 'getAge']);\n *\n * createSpyFromClass(MyService, {\n * methodsToSpyOn: ['getName'],\n * observablePropsToSpyOn: ['products$'],\n * gettersToSpyOn: ['userName'],\n * settersToSpyOn: ['userName'],\n * });\n * ```\n *\n * --------------------------------------------------------------------------\n * ## Synchronous methods\n * --------------------------------------------------------------------------\n *\n * ```ts\n * // standard vi.fn() API\n * myService.getName.mockReturnValue('Fake Name');\n *\n * // conditional return by arguments\n * myService.getName.calledWith(1).mockReturnValue('Fake Name');\n *\n * // throw if called with the \"wrong\" arguments\n * myService.getName.mustBeCalledWith(1).mockReturnValue('Fake Name');\n * ```\n *\n * --------------------------------------------------------------------------\n * ## Promise-returning methods\n * --------------------------------------------------------------------------\n *\n * ```ts\n * myService.getProducts.resolveWith([{ name: 'Product 1' }]);\n * myService.getProducts.rejectWith('FAKE ERROR');\n *\n * myService.getProducts.calledWith(1).resolveWith([{ name: 'Product 1' }]);\n * ```\n *\n * --------------------------------------------------------------------------\n * ## Observable-returning methods / observable properties\n * --------------------------------------------------------------------------\n *\n * ```ts\n * myService.getProducts$.nextWith([{ name: 'Product 1' }]); // emit, stays open\n * myService.getProducts$.nextOneTimeWith([{ name: 'X' }]); // emit + complete\n * myService.getProducts$.throwWith('FAKE ERROR'); // error the stream\n * myService.getProducts$.complete(); // complete the stream\n *\n * // emit a precise sequence (values, errors, completion, delays)\n * myService.getProducts$.nextWithValues([\n * { value: [{ name: 'Product 1' }] },\n * { errorValue: 'FAKE ERROR' },\n * { complete: true },\n * ]);\n *\n * // grab the underlying Subject for manual control\n * const subject = myService.getProducts$.returnSubject();\n * ```\n *\n * --------------------------------------------------------------------------\n * ## Getters & setters\n * --------------------------------------------------------------------------\n *\n * ```ts\n * const spy = createSpyFromClass(MyService, {\n * gettersToSpyOn: ['userName'],\n * settersToSpyOn: ['userName'],\n * });\n *\n * spy.accessorSpies.getters.userName.mockReturnValue('Fake Name');\n * expect(spy.userName).toBe('Fake Name');\n *\n * spy.userName = 'New Name';\n * expect(spy.accessorSpies.setters.userName).toHaveBeenCalledWith('New Name');\n * ```\n *\n * --------------------------------------------------------------------------\n * ## Angular helpers (bonus)\n * --------------------------------------------------------------------------\n *\n * ```ts\n * TestBed.configureTestingModule({\n * providers: [provideAutoSpy(MyService)],\n * });\n *\n * const service = injectSpy(MyService);\n *\n * // signals / readonly / accessor property mocking\n * mockReadonlyProp(service, 'isReady', true);\n * mockReadonlyPropGetter(service, 'label', () => 'A');\n * mockAccessorsProp(service, 'theme');\n * ```\n */\n\nimport { defer, EMPTY, from, merge, Observable, of, ReplaySubject, Subject, throwError, timer } from 'rxjs';\nimport { concatMap, delay, switchMap, take, takeUntil, takeWhile } from 'rxjs/operators';\nimport { TestBed } from '@angular/core/testing';\nimport { stringify } from 'javascript-stringify';\nimport { type Mock, type MockInstance, vi } from 'vitest';\n\n// ===========================================================================\n// Shared types (mirrors @hirez_io/auto-spies-core)\n// ===========================================================================\n\nexport type Func = (...args: any[]) => any;\n\nexport type ClassType<T> = { new (...args: any[]): T; [key: string]: any };\n\ntype StringKeysForPropertyType<ObjectType, PropType> = Extract<\n { [Key in keyof ObjectType]: ObjectType[Key] extends PropType ? Key : never }[keyof ObjectType],\n string\n>;\n\nexport type OnlyMethodKeysOf<T> = StringKeysForPropertyType<T, (...args: any[]) => any>;\nexport type OnlyObservablePropsOf<T> = StringKeysForPropertyType<T, Observable<any>>;\nexport type OnlyPropsOf<ObjectType> = Extract<\n { [Key in keyof ObjectType]: ObjectType[Key] extends Func ? never : Key }[keyof ObjectType],\n string\n>;\n\nexport type ValueConfigPerCall<T> = { value: T; delay?: number; doNotComplete?: boolean };\n\nexport type NextValueConfig<T> = { value: T; delay?: number };\nexport type ErrorValueConfig = { errorValue: any; delay?: number };\nexport type CompleteValueConfig = { complete?: boolean; delay?: number };\nexport type ValueConfig<T> = NextValueConfig<T> | ErrorValueConfig | CompleteValueConfig;\n\nexport interface AddObservableSpyMethods<T> {\n nextWith(value?: T): void;\n /** emit one value then complete */\n nextOneTimeWith(value?: T): void;\n nextWithValues(valuesConfigs: ValueConfig<T>[]): void;\n nextWithPerCall(valuesPerCall?: ValueConfigPerCall<T>[]): Subject<T>[];\n throwWith(value: any): void;\n complete(): void;\n returnSubject(): Subject<T>;\n}\n\nexport interface AddPromiseSpyMethods<T> {\n resolveWith(value?: T): void;\n rejectWith(value?: any): void;\n resolveWithPerCall(valuesPerCall: ValueConfigPerCall<T>[]): void;\n}\n\nexport interface AddCalledWithSpyMethods<Method extends Func> {\n calledWith(...args: Parameters<Method>): { mockReturnValue: (value: ReturnType<Method>) => void };\n mustBeCalledWith(...args: Parameters<Method>): { mockReturnValue: (value: ReturnType<Method>) => void };\n}\n\ntype AddCalledWithObservable<O> = {\n calledWith(...args: any[]): AddObservableSpyMethods<O>;\n mustBeCalledWith(...args: any[]): AddObservableSpyMethods<O>;\n};\ntype AddCalledWithPromise<P> = {\n calledWith(...args: any[]): AddPromiseSpyMethods<P>;\n mustBeCalledWith(...args: any[]): AddPromiseSpyMethods<P>;\n};\n\n/** Wrap a method's spy with helpers chosen by its return type. */\nexport type AddSpyMethodsByReturnTypes<Method extends Func> = Method &\n Mock &\n (Method extends (...args: any[]) => infer ReturnType\n ? ReturnType extends Promise<infer P>\n ? AddPromiseSpyMethods<P> & AddCalledWithPromise<P>\n : ReturnType extends Observable<infer O>\n ? AddObservableSpyMethods<O> & AddCalledWithObservable<O>\n : AddCalledWithSpyMethods<Method>\n : never);\n\nexport type AddAccessorsSpies<T> = {\n accessorSpies: {\n getters: { [K in keyof T]: Mock };\n setters: { [K in keyof T]: Mock };\n };\n};\n\n/** Fully-typed spy of `T`. */\nexport type Spy<T> = {\n [K in keyof T]: T[K] extends Func\n ? AddSpyMethodsByReturnTypes<T[K]>\n : T[K] extends Observable<infer O>\n ? T[K] & AddObservableSpyMethods<O>\n : T[K];\n} & AddAccessorsSpies<T>;\n\nexport interface ClassSpyConfiguration<T> {\n methodsToSpyOn?: OnlyMethodKeysOf<T>[];\n observablePropsToSpyOn?: OnlyObservablePropsOf<T>[];\n settersToSpyOn?: OnlyPropsOf<T>[];\n gettersToSpyOn?: OnlyPropsOf<T>[];\n}\n\n// ===========================================================================\n// ArgsMap — serialize argument lists into stable keys\n// ===========================================================================\n\nclass ArgsMap {\n private map: { [key: string]: any } = {};\n\n // `stringify` always serializes an argument array to a string, so the cast is safe.\n set(key: unknown, value: unknown): void {\n this.map[stringify(key) as string] = value;\n }\n\n get(key: unknown): any {\n return this.map[stringify(key) as string];\n }\n}\n\n// ===========================================================================\n// Error handler — used by mustBeCalledWith\n// ===========================================================================\n\nexport const errorHandler = {\n throwArgumentsError(actualArgs: any[], functionName: string): void {\n let errorMessage =\n `The function '${functionName}' was configured with 'mustBeCalledWith' ` +\n `and expects to be called with specific arguments. `;\n\n if (actualArgs.length === 0) {\n errorMessage += `But the function was called without any arguments.`;\n } else {\n let formattedArgs = stringify(actualArgs) as string;\n formattedArgs = formattedArgs.substring(1, formattedArgs.length - 1);\n errorMessage += `But the actual arguments were: ${formattedArgs}`;\n }\n\n throw new Error(errorMessage);\n },\n};\n\n// ===========================================================================\n// Internal value containers\n// ===========================================================================\n\ninterface ReturnValueContainer {\n value: any;\n _isRejectedPromise?: boolean;\n valuesPerCalls?: { wrappedValue: Promise<any> | Observable<any>; delay?: number }[];\n}\n\ninterface CalledWithObject {\n wasConfigured: boolean;\n argsToValuesMap: ArgsMap;\n [extra: string]: any;\n}\n\n// ===========================================================================\n// Observable helpers\n// ===========================================================================\n\nfunction createReplaySubject<T>(): ReplaySubject<T> {\n return new ReplaySubject<T>(1);\n}\n\nfunction mergeSubjectWithDefaultValues<T>(\n subject: ReplaySubject<T>,\n valuesConfigs: ValueConfig<T>[],\n): Observable<T> {\n const onCompleteSubject = new ReplaySubject<void>(1);\n const results$ = from(valuesConfigs).pipe(\n concatMap((valueConfig) => {\n if ('complete' in valueConfig && valueConfig.complete && valueConfig.delay) {\n return of(valueConfig).pipe(delay(valueConfig.delay));\n }\n return of(valueConfig);\n }),\n takeWhile((valueConfig) => {\n if (!('complete' in valueConfig)) {\n return true;\n }\n if (valueConfig.complete) {\n onCompleteSubject.next();\n return false;\n }\n return true;\n }),\n concatMap((valueConfig) => {\n if ('value' in valueConfig && valueConfig.value) {\n if (valueConfig.delay) {\n return of(valueConfig.value).pipe(delay(valueConfig.delay));\n }\n return of(valueConfig.value);\n }\n if ('errorValue' in valueConfig && valueConfig.errorValue) {\n if (valueConfig.delay) {\n return timer(valueConfig.delay).pipe(switchMap(() => throwError(() => valueConfig.errorValue)));\n }\n return throwError(() => valueConfig.errorValue);\n }\n return EMPTY;\n }),\n );\n return merge(results$, subject.pipe(takeUntil(onCompleteSubject)));\n}\n\nfunction addObservableHelpers<T>(\n objectToDecorate: any,\n providedSubject: ReplaySubject<T>,\n onSubjectConfigured: (subject: Observable<T>) => void,\n): void {\n objectToDecorate.nextWith = (value: T): void => {\n providedSubject.next(value);\n onSubjectConfigured(providedSubject);\n };\n objectToDecorate.nextOneTimeWith = (value: T): void => {\n providedSubject.next(value);\n providedSubject.complete();\n onSubjectConfigured(providedSubject);\n };\n objectToDecorate.nextWithValues = (valuesConfigs: ValueConfig<T>[]): void => {\n if (valuesConfigs.length === 0) {\n return;\n }\n onSubjectConfigured(mergeSubjectWithDefaultValues(providedSubject, valuesConfigs));\n };\n objectToDecorate.throwWith = (value: any): void => {\n providedSubject.error(value);\n onSubjectConfigured(providedSubject);\n };\n objectToDecorate.complete = (): void => {\n providedSubject.complete();\n onSubjectConfigured(providedSubject);\n };\n objectToDecorate.returnSubject = (): ReplaySubject<T> => {\n onSubjectConfigured(providedSubject);\n return providedSubject;\n };\n}\n\nfunction addNextWithPerCall(\n objectToDecorate: any,\n returnValueContainer: ReturnValueContainer,\n onConfigured: (c: ReturnValueContainer) => void = () => undefined,\n): void {\n objectToDecorate.nextWithPerCall = (valueConfigsPerCall: ValueConfigPerCall<any>[]): ReplaySubject<any>[] => {\n const returnedSubjects: ReplaySubject<any>[] = [];\n if (valueConfigsPerCall.length === 0) {\n return returnedSubjects;\n }\n returnValueContainer.valuesPerCalls = [];\n valueConfigsPerCall.forEach((valueConfiguration) => {\n const replaySubject = new ReplaySubject<any>(1);\n replaySubject.next(valueConfiguration.value);\n returnedSubjects.push(replaySubject);\n\n let returnedObservable: Observable<any> = replaySubject.asObservable();\n if (valueConfiguration.delay) {\n returnedObservable = returnedObservable.pipe(delay(valueConfiguration.delay));\n }\n if (!valueConfiguration.doNotComplete) {\n returnedObservable = returnedObservable.pipe(take(1));\n }\n returnValueContainer.valuesPerCalls!.push({ wrappedValue: returnedObservable });\n });\n onConfigured(returnValueContainer);\n return returnedSubjects;\n };\n}\n\nfunction addObservableHelpersToFunctionSpy(spyFunction: any, valueContainer: ReturnValueContainer): void {\n const subject = createReplaySubject();\n addObservableHelpers(spyFunction, subject, (configuredSubject) => {\n valueContainer.value = configuredSubject;\n });\n addNextWithPerCall(spyFunction, valueContainer);\n}\n\nfunction addObservableHelpersToCalledWithObject(calledWithObject: CalledWithObject, calledWithArgs: any[]): void {\n const subject = createReplaySubject();\n const returnValueContainer: ReturnValueContainer = { value: undefined };\n addObservableHelpers(calledWithObject, subject, (configuredSubject) => {\n returnValueContainer.value = configuredSubject;\n calledWithObject.argsToValuesMap.set(calledWithArgs, returnValueContainer);\n });\n addNextWithPerCall(calledWithObject, returnValueContainer, (configured) => {\n calledWithObject.argsToValuesMap.set(calledWithArgs, configured);\n });\n}\n\n/** Build a standalone Observable that emits the provided value configs. */\nexport function createObservableWithValues<T>(valuesConfigs: ValueConfig<T>[]): Observable<T>;\nexport function createObservableWithValues<T>(\n valuesConfigs: ValueConfig<T>[],\n config: { returnSubject: true },\n): { values$: Observable<T>; subject: ReplaySubject<T> };\nexport function createObservableWithValues<T>(\n valuesConfigs: ValueConfig<T>[],\n config?: { returnSubject: boolean },\n): Observable<T> | { values$: Observable<T>; subject: ReplaySubject<T> } {\n const subject = createReplaySubject<T>();\n const values$ = mergeSubjectWithDefaultValues(subject, valuesConfigs);\n if (config && config.returnSubject) {\n return { values$, subject };\n }\n return values$;\n}\n\n/** Create an observable property spy (deferred subscription to a controllable subject). */\nfunction createObservablePropSpy<T>(): Observable<T> & AddObservableSpyMethods<T> {\n let subject = createReplaySubject<T>();\n const observableSpy: any = defer(() => subject);\n addObservableHelpers(observableSpy, subject, (configuredSubject) => {\n subject = configuredSubject as ReplaySubject<T>;\n });\n return observableSpy;\n}\n\n// ===========================================================================\n// Promise helpers\n// ===========================================================================\n\nfunction addPromiseHelpersToFunctionSpy(spyFunction: any, valueContainer: ReturnValueContainer): void {\n spyFunction.resolveWith = (value?: any): void => {\n valueContainer.value = Promise.resolve(value);\n };\n spyFunction.rejectWith = (value?: any): void => {\n valueContainer.value = value;\n valueContainer._isRejectedPromise = true;\n };\n spyFunction.resolveWithPerCall = (valueConfigsPerCall: ValueConfigPerCall<any>[]): void => {\n if (valueConfigsPerCall.length === 0) {\n return;\n }\n valueContainer.valuesPerCalls = [];\n valueConfigsPerCall.forEach((valueConfiguration) => {\n valueContainer.valuesPerCalls!.push({\n wrappedValue: Promise.resolve(valueConfiguration.value),\n delay: valueConfiguration.delay,\n });\n });\n };\n}\n\nfunction addPromiseHelpersToCalledWithObject(calledWithObject: CalledWithObject, calledWithArgs: any[]): void {\n calledWithObject.resolveWith = (value?: any): void => {\n calledWithObject.argsToValuesMap.set(calledWithArgs, { value: Promise.resolve(value) });\n };\n calledWithObject.rejectWith = (value?: any): void => {\n calledWithObject.argsToValuesMap.set(calledWithArgs, { value, _isRejectedPromise: true });\n };\n calledWithObject.resolveWithPerCall = (valueConfigsPerCall: ValueConfigPerCall<any>[]): void => {\n if (valueConfigsPerCall.length === 0) {\n return;\n }\n const valueContainer: ReturnValueContainer = { value: undefined, valuesPerCalls: [] };\n valueConfigsPerCall.forEach((valueConfiguration) => {\n valueContainer.valuesPerCalls!.push({\n wrappedValue: Promise.resolve(valueConfiguration.value),\n delay: valueConfiguration.delay,\n });\n });\n calledWithObject.argsToValuesMap.set(calledWithArgs, valueContainer);\n };\n}\n\n// ===========================================================================\n// Function spy factory\n// ===========================================================================\n\nfunction getNextCallValue(valueContainer: ReturnValueContainer): any {\n const wrapped = valueContainer.valuesPerCalls!.shift();\n let returnedValue = wrapped?.wrappedValue;\n if (wrapped && wrapped.delay) {\n returnedValue = (returnedValue as Promise<any>).then(\n (value) => new Promise((resolve) => setTimeout(() => resolve(value), wrapped.delay)),\n );\n }\n return returnedValue;\n}\n\nfunction returnTheCorrectFakeValue(\n calledWithObject: CalledWithObject,\n mustBeCalledWithObject: CalledWithObject,\n valueContainer: ReturnValueContainer,\n actualArgs: any[],\n functionName: string,\n): any {\n if (calledWithObject.wasConfigured) {\n const configured = calledWithObject.argsToValuesMap.get(actualArgs);\n if (configured) {\n return unwrapContainer(configured);\n }\n }\n\n if (mustBeCalledWithObject.wasConfigured) {\n const configured = mustBeCalledWithObject.argsToValuesMap.get(actualArgs);\n if (configured) {\n return unwrapContainer(configured);\n }\n errorHandler.throwArgumentsError(actualArgs, functionName);\n }\n\n return unwrapContainer(valueContainer);\n}\n\nfunction unwrapContainer(container: ReturnValueContainer): any {\n if (container._isRejectedPromise) {\n return Promise.reject(container.value);\n }\n if (container.valuesPerCalls?.length) {\n return getNextCallValue(container);\n }\n return container.value;\n}\n\nfunction addMethodsToCalledWith(calledWith: CalledWithObject, calledWithArgs: any[]): CalledWithObject {\n calledWith.wasConfigured = true;\n calledWith.mockReturnValue = (value: any): void => {\n calledWith.argsToValuesMap.set(calledWithArgs, { value });\n };\n addPromiseHelpersToCalledWithObject(calledWith, calledWithArgs);\n addObservableHelpersToCalledWithObject(calledWith, calledWithArgs);\n return calledWith;\n}\n\n/** Create a single Vitest-backed function spy with all return-type helpers attached. */\nexport function createFunctionSpy<FunctionType extends Func>(name: string): AddSpyMethodsByReturnTypes<FunctionType> {\n const calledWithObject: CalledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };\n const mustBeCalledWithObject: CalledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };\n const valueContainer: ReturnValueContainer = { value: undefined };\n\n const functionSpy = vi.fn((...actualArgs: any[]) =>\n returnTheCorrectFakeValue(calledWithObject, mustBeCalledWithObject, valueContainer, actualArgs, name),\n );\n functionSpy.mockName(name);\n\n addPromiseHelpersToFunctionSpy(functionSpy, valueContainer);\n addObservableHelpersToFunctionSpy(functionSpy, valueContainer);\n\n (functionSpy as any).calledWith = (...calledWithArgs: any[]) =>\n addMethodsToCalledWith(calledWithObject, calledWithArgs);\n (functionSpy as any).mustBeCalledWith = (...calledWithArgs: any[]) =>\n addMethodsToCalledWith(mustBeCalledWithObject, calledWithArgs);\n\n return functionSpy as unknown as AddSpyMethodsByReturnTypes<FunctionType>;\n}\n\n// ===========================================================================\n// Accessor (getter / setter) spies\n// ===========================================================================\n\nfunction defineWithEmptyAccessors(obj: any, prop: string): void {\n Object.defineProperty(obj, prop, {\n get() {\n return undefined;\n },\n set(_value: unknown) {\n /* noop */\n },\n configurable: true,\n });\n}\n\nfunction accessorSpyFactory(autoSpy: any, accessorName: string, accessorType: 'getter' | 'setter'): MockInstance {\n if (accessorType === 'setter') {\n return vi.spyOn(autoSpy, accessorName as never, 'set');\n }\n return vi.spyOn(autoSpy, accessorName as never, 'get');\n}\n\nfunction createAccessorsSpies(autoSpy: any, gettersToSpyOn: string[], settersToSpyOn: string[]): void {\n autoSpy.accessorSpies = { getters: {}, setters: {} };\n\n gettersToSpyOn.forEach((getterName) => {\n defineWithEmptyAccessors(autoSpy, getterName);\n autoSpy.accessorSpies.getters[getterName] = accessorSpyFactory(autoSpy, getterName, 'getter');\n });\n\n settersToSpyOn.forEach((setterName) => {\n if (!Object.prototype.hasOwnProperty.call(autoSpy, setterName)) {\n defineWithEmptyAccessors(autoSpy, setterName);\n }\n autoSpy.accessorSpies.setters[setterName] = accessorSpyFactory(autoSpy, setterName, 'setter');\n });\n}\n\n// ===========================================================================\n// createSpyFromClass — assemble the full auto-spy\n// ===========================================================================\n\nfunction extractMethodsFromObject(obj: any): string[] {\n const descriptors = Object.getOwnPropertyDescriptors(obj);\n return Object.keys(descriptors).reduce<string[]>((names, name) => {\n if (name !== 'constructor' && !descriptors[name].get) {\n names.push(name);\n }\n return names;\n }, []);\n}\n\nfunction getAllMethodNames(obj: any): string[] {\n let methods: string[] = [];\n while (obj) {\n const parentObj = Object.getPrototypeOf(obj);\n if (parentObj) {\n methods = methods.concat(extractMethodsFromObject(obj));\n }\n obj = parentObj;\n }\n return methods;\n}\n\n/** Generate a fully-typed auto-spy from a class. */\nexport function createSpyFromClass<T>(\n ObjectClass: ClassType<T>,\n methodsToSpyOnOrConfig?: OnlyMethodKeysOf<T>[] | ClassSpyConfiguration<T>,\n): Spy<T> {\n const methodNames = getAllMethodNames(ObjectClass.prototype);\n\n let methodsToSpyOn: string[] = [];\n let observablePropsToSpyOn: string[] = [];\n let settersToSpyOn: string[] = [];\n let gettersToSpyOn: string[] = [];\n\n if (methodsToSpyOnOrConfig) {\n if (Array.isArray(methodsToSpyOnOrConfig)) {\n methodsToSpyOn = methodsToSpyOnOrConfig as string[];\n } else {\n methodsToSpyOn = (methodsToSpyOnOrConfig.methodsToSpyOn as string[]) || [];\n observablePropsToSpyOn = (methodsToSpyOnOrConfig.observablePropsToSpyOn as string[]) || [];\n settersToSpyOn = (methodsToSpyOnOrConfig.settersToSpyOn as string[]) || [];\n gettersToSpyOn = (methodsToSpyOnOrConfig.gettersToSpyOn as string[]) || [];\n }\n }\n if (methodsToSpyOn.length > 0) {\n methodNames.push(...methodsToSpyOn);\n }\n\n const autoSpy: any = {};\n\n observablePropsToSpyOn.forEach((observablePropName) => {\n autoSpy[observablePropName] = createObservablePropSpy();\n });\n\n createAccessorsSpies(autoSpy, gettersToSpyOn, settersToSpyOn);\n\n methodNames.forEach((methodName) => {\n autoSpy[methodName] = createFunctionSpy(methodName);\n });\n\n return autoSpy as Spy<T>;\n}\n\n// ===========================================================================\n// Angular helpers\n// ===========================================================================\n\nexport type AngularValueProvider<T> = { provide: ClassType<T>; useValue: Spy<T> };\n\n/** Shorthand Angular provider: `{ provide, useValue: createSpyFromClass(...) }`. */\nexport function provideAutoSpy<T>(\n ObjectClass: ClassType<T>,\n methodsToSpyOnOrConfig?: OnlyMethodKeysOf<T>[] | ClassSpyConfiguration<T>,\n): AngularValueProvider<T> {\n return {\n provide: ObjectClass,\n useValue: createSpyFromClass(ObjectClass, methodsToSpyOnOrConfig),\n };\n}\n\n// ===========================================================================\n// Bonus: TestBed + property mocking helpers\n// ===========================================================================\n\n/** Inject a service from Angular's `TestBed`, already typed as `Spy<T>`. */\nexport function injectSpy<T>(token: ClassType<T> | (abstract new (...args: never[]) => T)): Spy<T> {\n return TestBed.inject(token as never) as Spy<T>;\n}\n\n/** Override a readonly property (incl. `signal()` / `computed()`) with a static value. */\nexport function mockReadonlyProp<T, K extends keyof T>(object: T, property: K, value: unknown): void {\n Object.defineProperty(object, property, { get: () => value, configurable: true });\n}\n\n/** Override a readonly property with a dynamic getter. */\nexport function mockReadonlyPropGetter<T, K extends keyof T>(object: T, property: K, getter: () => unknown): void {\n Object.defineProperty(object, property, { get: getter, configurable: true });\n}\n\n/** Replace a property with spied `get`/`set` accessors (`vi.fn()`). */\nexport function mockAccessorsProp<T, K extends keyof T>(object: T, property: K): void {\n Object.defineProperty(object, property, { get: vi.fn(), set: vi.fn(), configurable: true });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "vitest-auto-spy",
3
+ "version": "1.0.0",
4
+ "description": "Auto-spy utilities for Vitest + Angular (works with both zoneless and zone.js). Drop-in replacement for jest-auto-spies.",
5
+ "keywords": [
6
+ "vitest",
7
+ "angular",
8
+ "testing",
9
+ "spy",
10
+ "mock",
11
+ "auto-spy",
12
+ "jest-auto-spies",
13
+ "zoneless"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Alexey Popov <asdalexey@yandex.ru>",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/ASDAlexey/vitest-auto-spy.git"
20
+ },
21
+ "homepage": "https://github.com/ASDAlexey/vitest-auto-spy#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/ASDAlexey/vitest-auto-spy/issues"
24
+ },
25
+ "type": "module",
26
+ "main": "./dist/index.cjs",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "require": "./dist/index.cjs"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "sideEffects": false,
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "typecheck": "tsc --noEmit",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "test:coverage": "vitest run --coverage",
48
+ "prepublishOnly": "npm run build"
49
+ },
50
+ "peerDependencies": {
51
+ "@angular/core": ">=16.0.0",
52
+ "rxjs": ">=7.0.0",
53
+ "vitest": ">=1.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@analogjs/vite-plugin-angular": "^2.2.0",
57
+ "@analogjs/vitest-angular": "^2.2.0",
58
+ "@angular/build": "^21.2.16",
59
+ "@angular/common": "^21.2.17",
60
+ "@angular/compiler": "^21.2.17",
61
+ "@angular/compiler-cli": "^21.2.17",
62
+ "@angular/core": "^21.0.0",
63
+ "@angular/platform-browser": "^21.2.17",
64
+ "@angular/platform-browser-dynamic": "^21.2.17",
65
+ "@types/node": "^20.19.43",
66
+ "@vitest/coverage-v8": "^4.1.9",
67
+ "jsdom": "^29.1.1",
68
+ "rxjs": "^7.8.0",
69
+ "tsup": "^8.3.0",
70
+ "typescript": "^5.6.0",
71
+ "vitest": "^4.1.9"
72
+ },
73
+ "dependencies": {
74
+ "javascript-stringify": "^2.1.0"
75
+ }
76
+ }