vitest-auto-spy 1.0.1 → 1.2.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/README.md CHANGED
@@ -50,8 +50,33 @@ same API, but spying only on **Vitest** instead of Jest.
50
50
  npm i -D vitest-auto-spy
51
51
  ```
52
52
 
53
- Peer dependencies (provided by your project): `vitest`, `rxjs`, and — for the Angular
54
- helpers `@angular/core`.
53
+ Peer dependencies are all **optional** and provided by your project: `vitest` (required),
54
+ plus `rxjs` and `@angular/core` only if you use the matching entry point. The package itself
55
+ has **zero runtime dependencies**.
56
+
57
+ ### Entry points
58
+
59
+ The library ships a framework-agnostic core and two opt-in layers, so a plain Node / Bun /
60
+ React / Vue project pulls **neither rxjs nor Angular into its runtime bundle**:
61
+
62
+ | Import | Provides | Pulls in |
63
+ | --- | --- | --- |
64
+ | `vitest-auto-spy` | `createSpyFromClass`, `createFunctionSpy`, sync + promise + accessor spies, `errorHandler`, types | `vitest` |
65
+ | `vitest-auto-spy/rxjs` | observable spies (`nextWith`, `nextWithValues`, `observablePropsToSpyOn`, …) + `createObservableWithValues` | `rxjs` |
66
+ | `vitest-auto-spy/angular` | `provideAutoSpy`, `injectSpy`, `mockReadonlyProp*`, `mockAccessorsProp` | `@angular/core` |
67
+
68
+ ```ts
69
+ import { createSpyFromClass } from 'vitest-auto-spy';
70
+ import 'vitest-auto-spy/rxjs'; // once (e.g. in your test setup) — enables observable spies
71
+ import { provideAutoSpy, injectSpy } from 'vitest-auto-spy/angular';
72
+ ```
73
+
74
+ > Using an observable spy (`observablePropsToSpyOn`, `nextWith`, …) without importing
75
+ > `vitest-auto-spy/rxjs` throws a clear hint telling you to add that import.
76
+ >
77
+ > The decoupling is at the **runtime** level. The core's _type_ surface (`Spy<T>`) still
78
+ > references rxjs types, so keep `rxjs` available for type-checking (it's normally already a
79
+ > devDependency); none of it reaches your runtime bundle.
55
80
 
56
81
  ## Why
57
82
 
@@ -87,9 +112,14 @@ The public API is intentionally identical. In most projects the migration is a
87
112
 
88
113
  ```diff
89
114
  - import { createSpyFromClass, provideAutoSpy } from 'jest-auto-spies';
90
- + import { createSpyFromClass, provideAutoSpy } from 'vitest-auto-spy';
115
+ + import { createSpyFromClass } from 'vitest-auto-spy';
116
+ + import { provideAutoSpy } from 'vitest-auto-spy/angular';
117
+ + import 'vitest-auto-spy/rxjs'; // once, if you use observable spies
91
118
  ```
92
119
 
120
+ The only API-shape change from `jest-auto-spies` is that the Angular helpers and the
121
+ observable layer live behind the `/angular` and `/rxjs` subpaths (see [Entry points](#entry-points)).
122
+
93
123
  | jest-auto-spies | vitest-auto-spy | Status |
94
124
  | --- | --- | --- |
95
125
  | `createSpyFromClass` | `createSpyFromClass` | ✅ identical |
@@ -155,7 +185,11 @@ myService.getProducts.calledWith(1).resolveWith(['one']);
155
185
  ## Observable-returning methods & Observable properties
156
186
 
157
187
  Both spied **methods** that return an `Observable` and spied **properties** of type
158
- `Observable` get the same control surface:
188
+ `Observable` get the same control surface. Enable them by importing the rxjs layer once:
189
+
190
+ ```ts
191
+ import 'vitest-auto-spy/rxjs';
192
+ ```
159
193
 
160
194
  ```ts
161
195
  myService.getProducts$.nextWith([{ name: 'Product 1' }]); // emit, stream stays open
@@ -187,7 +221,7 @@ myService.getProducts$.calledWith(1).nextWith([{ name: 'Product 1' }]);
187
221
  ### Standalone observable builder
188
222
 
189
223
  ```ts
190
- import { createObservableWithValues } from 'vitest-auto-spy';
224
+ import { createObservableWithValues } from 'vitest-auto-spy/rxjs';
191
225
 
192
226
  const fake$ = createObservableWithValues([{ value: 1 }, { value: 2 }, { complete: true }]);
193
227
 
@@ -217,7 +251,7 @@ expect(spy.accessorSpies.setters.userName).toHaveBeenCalledWith('New Name');
217
251
  `provideAutoSpy` is the shorthand for providing an auto-spy in a `TestBed`:
218
252
 
219
253
  ```ts
220
- import { provideAutoSpy, injectSpy } from 'vitest-auto-spy';
254
+ import { provideAutoSpy, injectSpy } from 'vitest-auto-spy/angular';
221
255
 
222
256
  TestBed.configureTestingModule({
223
257
  providers: [
@@ -243,7 +277,7 @@ beforeEach(() => {
243
277
  ### Signal / readonly property mocking (bonus)
244
278
 
245
279
  ```ts
246
- import { mockReadonlyProp, mockReadonlyPropGetter, mockAccessorsProp } from 'vitest-auto-spy';
280
+ import { mockReadonlyProp, mockReadonlyPropGetter, mockAccessorsProp } from 'vitest-auto-spy/angular';
247
281
 
248
282
  mockReadonlyProp(service, 'isReady', true); // static value (incl. signals)
249
283
  mockReadonlyPropGetter(service, 'label', () => 'A'); // dynamic getter
@@ -286,6 +320,10 @@ npm run test:coverage # 100% thresholds enforced
286
320
  npm run build
287
321
  ```
288
322
 
323
+ Releases are automated: merging a PR into `master` bumps the version from the
324
+ Conventional Commit types and publishes to npm — see
325
+ [CONTRIBUTING.md → Releases](./CONTRIBUTING.md#releases).
326
+
289
327
  If this package saved you time, a ⭐ on [GitHub](https://github.com/ASDAlexey/vitest-auto-spy)
290
328
  helps others find it.
291
329
 
@@ -0,0 +1 @@
1
+ 'use strict';var testing=require('@angular/core/testing'),vitest=require('vitest');function g(e,t){Object.defineProperty(e,t,{get(){},set(r){},configurable:true});}function T(e,t,r){let n=t;return r==="setter"?vitest.vi.spyOn(e,n,"set"):vitest.vi.spyOn(e,n,"get")}function b(e,t,r){let n={getters:{},setters:{}};e.accessorSpies=n,t.forEach(o=>{g(e,o),n.getters[o]=T(e,o,"getter");}),r.forEach(o=>{Object.prototype.hasOwnProperty.call(e,o)||g(e,o),n.setters[o]=T(e,o,"setter");});}function A(e){return `'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`}function M(e,t){return Object.entries(e).map(([r,n])=>`${r}:${i(n,t)}`).join(",")}function W(e,t){return `new Map([${[...e.entries()].map(([n,o])=>`[${i(n,t)},${i(o,t)}]`).join(",")}])`}function F(e,t){if(t.has(e))return "[Circular]";t.add(e);let r;return e instanceof Date?r=`new Date(${e.getTime()})`:e instanceof Map?r=W(e,t):e instanceof Set?r=`new Set([${[...e].map(n=>i(n,t)).join(",")}])`:Array.isArray(e)?r=`[${e.map(n=>i(n,t)).join(",")}]`:r=`{${M(e,t)}}`,t.delete(e),r}function i(e,t=new WeakSet){return typeof e=="string"?A(e):typeof e=="bigint"?`${e}n`:typeof e=="symbol"?e.toString():typeof e=="function"?`[Function: ${e.name}]`:typeof e=="object"&&e!==null?F(e,t):Object.is(e,-0)?"-0":String(e)}var l=class{#e={};set(t,r){this.#e[this.#t(t)]=r;}get(t){return this.#e[this.#t(t)]}#t(t){return i(t)}};var E=e=>`The function '${e}' was configured with 'mustBeCalledWith' and expects to be called with specific arguments. `,_="But the function was called without any arguments.",$=e=>{let t=i(e);return `But the actual arguments were: ${t.substring(1,t.length-1)}`},m={throwArgumentsError(e,t){let r=e.length===0?_:$(e);throw new Error(E(t)+r)}};var H="Observable spies require rxjs. Import 'vitest-auto-spy/rxjs' once (e.g. in your test setup) to enable observablePropsToSpyOn / nextWith / nextWithValues / throwWith / complete / returnSubject.";function S(){throw new Error(H);}function a(e,t){return Object.assign(e,t)}function K(e){return e.map(t=>({wrappedValue:t.delay===void 0?Promise.resolve(t.value):new Promise(r=>setTimeout(()=>r(t.value),t.delay))}))}function O(e,t){a(e,{resolveWith:r=>{t({value:Promise.resolve(r)});},rejectWith:r=>{t({value:r,_isRejectedPromise:true});},resolveWithPerCall:r=>{r.length!==0&&t({value:void 0,valuesPerCalls:K(r)});}});}function C(e,t){O(e,r=>{t.value=r.value,t._isRejectedPromise=r._isRejectedPromise??false,t.valuesPerCalls=r.valuesPerCalls??[];});}function j(e,t){O(e,r=>{e.argsToValuesMap.set(t,r);});}function B(e){return typeof e=="object"&&e!==null&&"value"in e}function v(e){if(e._isRejectedPromise)return Promise.reject(e.value);let t=e.valuesPerCalls?.shift();return t?t.wrappedValue:e.value}function h(e,t){let r=e.argsToValuesMap.get(t);return B(r)?{found:true,value:v(r)}:{found:false,value:void 0}}function I(e,t,r,n,o){if(e.wasConfigured){let s=h(e,n);if(s.found)return s.value}if(t.wasConfigured){let s=h(t,n);if(s.found)return s.value;m.throwArgumentsError(n,o);}return v(r)}function w(e,t){return e.wasConfigured=true,a(e,{mockReturnValue:r=>{e.argsToValuesMap.set(t,{value:r});}}),j(e,t),e}function k(){return {wasConfigured:false,argsToValuesMap:new l}}function P(e){let t=k(),r=k(),n={value:void 0},o=vitest.vi.fn((...u)=>I(t,r,n,u,e));o.mockName(e),C(o,n);let s=a(o,{calledWith:(...u)=>w(t,u),mustBeCalledWith:(...u)=>w(r,u)});return s}var R={methodsToSpyOn:[],observablePropsToSpyOn:[],settersToSpyOn:[],gettersToSpyOn:[]};function G(e){let t=Object.getOwnPropertyDescriptors(e);return Object.keys(t).filter(r=>r!=="constructor"&&!t[r]?.get)}function q(e){let t=new Set,r=e;for(;r;){let n=Object.getPrototypeOf(r);n&&G(r).forEach(o=>t.add(o)),r=n;}return [...t]}function D(e){return e?Array.isArray(e)?{...R,methodsToSpyOn:e}:{methodsToSpyOn:e.methodsToSpyOn??[],observablePropsToSpyOn:e.observablePropsToSpyOn??[],settersToSpyOn:e.settersToSpyOn??[],gettersToSpyOn:e.gettersToSpyOn??[]}:{...R}}function x(e,t){let{methodsToSpyOn:r,observablePropsToSpyOn:n,settersToSpyOn:o,gettersToSpyOn:s}=D(t),u=r.length>0?r:q(e.prototype),p={};return n.forEach(c=>{p[c]=S().createPropSpy();}),b(p,s,o),u.forEach(c=>{p[c]=P(c);}),p}function L(e,t){return {provide:e,useValue:x(e,t)}}function N(e){return testing.TestBed.inject(e)}function J(e,t,r){Object.defineProperty(e,t,{get:()=>r,configurable:true});}function X(e,t,r){Object.defineProperty(e,t,{get:r,configurable:true});}function Y(e,t){Object.defineProperty(e,t,{get:vitest.vi.fn(),set:vitest.vi.fn(),configurable:true});}exports.injectSpy=N;exports.mockAccessorsProp=Y;exports.mockReadonlyProp=J;exports.mockReadonlyPropGetter=X;exports.provideAutoSpy=L;
@@ -0,0 +1,21 @@
1
+ import { C as ClassType, S as Spy, a as ClassSpyConfiguration, O as OnlyMethodKeysOf } from './types-Cg9eZmvm.cjs';
2
+ import 'rxjs';
3
+ import 'vitest';
4
+
5
+ /** `{ provide, useValue }` shape consumed by Angular's `providers`. */
6
+ type AngularValueProvider<T> = {
7
+ provide: ClassType<T>;
8
+ useValue: Spy<T>;
9
+ };
10
+ /** Shorthand Angular provider: `{ provide, useValue: createSpyFromClass(...) }`. */
11
+ declare function provideAutoSpy<T>(ObjectClass: ClassType<T>, methodsToSpyOnOrConfig?: ClassSpyConfiguration<T> | OnlyMethodKeysOf<T>[]): AngularValueProvider<T>;
12
+ /** Inject a service from Angular's `TestBed`, already typed as `Spy<T>`. */
13
+ declare function injectSpy<T>(token: ClassType<T> | (abstract new (...args: never[]) => T)): Spy<T>;
14
+ /** Override a readonly property (incl. `signal()` / `computed()`) with a static value. */
15
+ declare function mockReadonlyProp<T, K extends keyof T>(object: T, property: K, value: T[K]): void;
16
+ /** Override a readonly property with a dynamic getter. */
17
+ declare function mockReadonlyPropGetter<T, K extends keyof T>(object: T, property: K, getter: () => unknown): void;
18
+ /** Replace a property with spied `get`/`set` accessors (`vi.fn()`). */
19
+ declare function mockAccessorsProp<T, K extends keyof T>(object: T, property: K): void;
20
+
21
+ export { type AngularValueProvider, injectSpy, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, provideAutoSpy };
@@ -0,0 +1,21 @@
1
+ import { C as ClassType, S as Spy, a as ClassSpyConfiguration, O as OnlyMethodKeysOf } from './types-Cg9eZmvm.js';
2
+ import 'rxjs';
3
+ import 'vitest';
4
+
5
+ /** `{ provide, useValue }` shape consumed by Angular's `providers`. */
6
+ type AngularValueProvider<T> = {
7
+ provide: ClassType<T>;
8
+ useValue: Spy<T>;
9
+ };
10
+ /** Shorthand Angular provider: `{ provide, useValue: createSpyFromClass(...) }`. */
11
+ declare function provideAutoSpy<T>(ObjectClass: ClassType<T>, methodsToSpyOnOrConfig?: ClassSpyConfiguration<T> | OnlyMethodKeysOf<T>[]): AngularValueProvider<T>;
12
+ /** Inject a service from Angular's `TestBed`, already typed as `Spy<T>`. */
13
+ declare function injectSpy<T>(token: ClassType<T> | (abstract new (...args: never[]) => T)): Spy<T>;
14
+ /** Override a readonly property (incl. `signal()` / `computed()`) with a static value. */
15
+ declare function mockReadonlyProp<T, K extends keyof T>(object: T, property: K, value: T[K]): void;
16
+ /** Override a readonly property with a dynamic getter. */
17
+ declare function mockReadonlyPropGetter<T, K extends keyof T>(object: T, property: K, getter: () => unknown): void;
18
+ /** Replace a property with spied `get`/`set` accessors (`vi.fn()`). */
19
+ declare function mockAccessorsProp<T, K extends keyof T>(object: T, property: K): void;
20
+
21
+ export { type AngularValueProvider, injectSpy, mockAccessorsProp, mockReadonlyProp, mockReadonlyPropGetter, provideAutoSpy };
@@ -0,0 +1 @@
1
+ import {c as c$1}from'./chunk-6S2BI3IA.js';import'./chunk-7IUYJ6ZW.js';import {TestBed}from'@angular/core/testing';import {vi}from'vitest';function i(e,o){return {provide:e,useValue:c$1(e,o)}}function s(e){return TestBed.inject(e)}function y(e,o,r){Object.defineProperty(e,o,{get:()=>r,configurable:true});}function a(e,o,r){Object.defineProperty(e,o,{get:r,configurable:true});}function c(e,o){Object.defineProperty(e,o,{get:vi.fn(),set:vi.fn(),configurable:true});}export{s as injectSpy,c as mockAccessorsProp,y as mockReadonlyProp,a as mockReadonlyPropGetter,i as provideAutoSpy};
@@ -0,0 +1 @@
1
+ import {b as b$1,d,c}from'./chunk-7IUYJ6ZW.js';import {vi}from'vitest';function M(e){return `'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`}function v(e,t){return Object.entries(e).map(([n,r])=>`${n}:${i(r,t)}`).join(",")}function V(e,t){return `new Map([${[...e.entries()].map(([r,o])=>`[${i(r,t)},${i(o,t)}]`).join(",")}])`}function A(e,t){if(t.has(e))return "[Circular]";t.add(e);let n;return e instanceof Date?n=`new Date(${e.getTime()})`:e instanceof Map?n=V(e,t):e instanceof Set?n=`new Set([${[...e].map(r=>i(r,t)).join(",")}])`:Array.isArray(e)?n=`[${e.map(r=>i(r,t)).join(",")}]`:n=`{${v(e,t)}}`,t.delete(e),n}function i(e,t=new WeakSet){return typeof e=="string"?M(e):typeof e=="bigint"?`${e}n`:typeof e=="symbol"?e.toString():typeof e=="function"?`[Function: ${e.name}]`:typeof e=="object"&&e!==null?A(e,t):Object.is(e,-0)?"-0":String(e)}var W=e=>`The function '${e}' was configured with 'mustBeCalledWith' and expects to be called with specific arguments. `,E="But the function was called without any arguments.",F=e=>{let t=i(e);return `But the actual arguments were: ${t.substring(1,t.length-1)}`},y={throwArgumentsError(e,t){let n=e.length===0?E:F(e);throw new Error(W(t)+n)}};var l=class{#e={};set(t,n){this.#e[this.#t(t)]=n;}get(t){return this.#e[this.#t(t)]}#t(t){return i(t)}};function $(e){return e.map(t=>({wrappedValue:t.delay===void 0?Promise.resolve(t.value):new Promise(n=>setTimeout(()=>n(t.value),t.delay))}))}function g(e,t){d(e,{resolveWith:n=>{t({value:Promise.resolve(n)});},rejectWith:n=>{t({value:n,_isRejectedPromise:true});},resolveWithPerCall:n=>{n.length!==0&&t({value:void 0,valuesPerCalls:$(n)});}});}function m(e,t){g(e,n=>{t.value=n.value,t._isRejectedPromise=n._isRejectedPromise??false,t.valuesPerCalls=n.valuesPerCalls??[];});}function T(e,t){g(e,n=>{e.argsToValuesMap.set(t,n);});}function _(e){return typeof e=="object"&&e!==null&&"value"in e}function C(e){if(e._isRejectedPromise)return Promise.reject(e.value);let t=e.valuesPerCalls?.shift();return t?t.wrappedValue:e.value}function b(e,t){let n=e.argsToValuesMap.get(t);return _(n)?{found:true,value:C(n)}:{found:false,value:void 0}}function z(e,t,n,r,o){if(e.wasConfigured){let s=b(e,r);if(s.found)return s.value}if(t.wasConfigured){let s=b(t,r);if(s.found)return s.value;y.throwArgumentsError(r,o);}return C(n)}function w(e,t){return e.wasConfigured=true,d(e,{mockReturnValue:n=>{e.argsToValuesMap.set(t,{value:n});}}),T(e,t),b$1()?.addToCalledWithObject(e,t),e}function S(){return {wasConfigured:false,argsToValuesMap:new l}}function h(e){let t=S(),n=S(),r={value:void 0},o=vi.fn((...u)=>z(t,n,r,u,e));o.mockName(e),m(o,r),b$1()?.addToFunctionSpy(o,r);let s=d(o,{calledWith:(...u)=>w(t,u),mustBeCalledWith:(...u)=>w(n,u)});return s}function O(e,t){Object.defineProperty(e,t,{get(){},set(n){},configurable:true});}function k(e,t,n){let r=t;return n==="setter"?vi.spyOn(e,r,"set"):vi.spyOn(e,r,"get")}function P(e,t,n){let r={getters:{},setters:{}};e.accessorSpies=r,t.forEach(o=>{O(e,o),r.getters[o]=k(e,o,"getter");}),n.forEach(o=>{Object.prototype.hasOwnProperty.call(e,o)||O(e,o),r.setters[o]=k(e,o,"setter");});}var R={methodsToSpyOn:[],observablePropsToSpyOn:[],settersToSpyOn:[],gettersToSpyOn:[]};function B(e){let t=Object.getOwnPropertyDescriptors(e);return Object.keys(t).filter(n=>n!=="constructor"&&!t[n]?.get)}function H(e){let t=new Set,n=e;for(;n;){let r=Object.getPrototypeOf(n);r&&B(n).forEach(o=>t.add(o)),n=r;}return [...t]}function I(e){return e?Array.isArray(e)?{...R,methodsToSpyOn:e}:{methodsToSpyOn:e.methodsToSpyOn??[],observablePropsToSpyOn:e.observablePropsToSpyOn??[],settersToSpyOn:e.settersToSpyOn??[],gettersToSpyOn:e.gettersToSpyOn??[]}:{...R}}function ue(e,t){let{methodsToSpyOn:n,observablePropsToSpyOn:r,settersToSpyOn:o,gettersToSpyOn:s}=I(t),u=n.length>0?n:H(e.prototype),c$1={};return r.forEach(p=>{c$1[p]=c().createPropSpy();}),P(c$1,s,o),u.forEach(p=>{c$1[p]=h(p);}),c$1}export{y as a,h as b,ue as c};
@@ -0,0 +1 @@
1
+ var e;function n(t){e=t;}function p(){return e}var o="Observable spies require rxjs. Import 'vitest-auto-spy/rxjs' once (e.g. in your test setup) to enable observablePropsToSpyOn / nextWith / nextWithValues / throwWith / complete / returnSubject.";function a(){if(!e)throw new Error(o);return e}function u(t,r){return Object.assign(t,r)}export{n as a,p as b,a as c,u as d};
package/dist/index.cjs CHANGED
@@ -1,369 +1 @@
1
- 'use strict';
2
-
3
- var rxjs = require('rxjs');
4
- var operators = require('rxjs/operators');
5
- var testing = require('@angular/core/testing');
6
- var javascriptStringify = require('javascript-stringify');
7
- var vitest = require('vitest');
8
-
9
- // src/auto-spy.ts
10
- var ArgsMap = class {
11
- constructor() {
12
- this.map = {};
13
- }
14
- // `stringify` always serializes an argument array to a string, so the cast is safe.
15
- set(key, value) {
16
- this.map[javascriptStringify.stringify(key)] = value;
17
- }
18
- get(key) {
19
- return this.map[javascriptStringify.stringify(key)];
20
- }
21
- };
22
- var errorHandler = {
23
- throwArgumentsError(actualArgs, functionName) {
24
- let errorMessage = `The function '${functionName}' was configured with 'mustBeCalledWith' and expects to be called with specific arguments. `;
25
- if (actualArgs.length === 0) {
26
- errorMessage += `But the function was called without any arguments.`;
27
- } else {
28
- let formattedArgs = javascriptStringify.stringify(actualArgs);
29
- formattedArgs = formattedArgs.substring(1, formattedArgs.length - 1);
30
- errorMessage += `But the actual arguments were: ${formattedArgs}`;
31
- }
32
- throw new Error(errorMessage);
33
- }
34
- };
35
- function createReplaySubject() {
36
- return new rxjs.ReplaySubject(1);
37
- }
38
- function mergeSubjectWithDefaultValues(subject, valuesConfigs) {
39
- const onCompleteSubject = new rxjs.ReplaySubject(1);
40
- const results$ = rxjs.from(valuesConfigs).pipe(
41
- operators.concatMap((valueConfig) => {
42
- if ("complete" in valueConfig && valueConfig.complete && valueConfig.delay) {
43
- return rxjs.of(valueConfig).pipe(operators.delay(valueConfig.delay));
44
- }
45
- return rxjs.of(valueConfig);
46
- }),
47
- operators.takeWhile((valueConfig) => {
48
- if (!("complete" in valueConfig)) {
49
- return true;
50
- }
51
- if (valueConfig.complete) {
52
- onCompleteSubject.next();
53
- return false;
54
- }
55
- return true;
56
- }),
57
- operators.concatMap((valueConfig) => {
58
- if ("value" in valueConfig && valueConfig.value) {
59
- if (valueConfig.delay) {
60
- return rxjs.of(valueConfig.value).pipe(operators.delay(valueConfig.delay));
61
- }
62
- return rxjs.of(valueConfig.value);
63
- }
64
- if ("errorValue" in valueConfig && valueConfig.errorValue) {
65
- if (valueConfig.delay) {
66
- return rxjs.timer(valueConfig.delay).pipe(operators.switchMap(() => rxjs.throwError(() => valueConfig.errorValue)));
67
- }
68
- return rxjs.throwError(() => valueConfig.errorValue);
69
- }
70
- return rxjs.EMPTY;
71
- })
72
- );
73
- return rxjs.merge(results$, subject.pipe(operators.takeUntil(onCompleteSubject)));
74
- }
75
- function addObservableHelpers(objectToDecorate, providedSubject, onSubjectConfigured) {
76
- objectToDecorate.nextWith = (value) => {
77
- providedSubject.next(value);
78
- onSubjectConfigured(providedSubject);
79
- };
80
- objectToDecorate.nextOneTimeWith = (value) => {
81
- providedSubject.next(value);
82
- providedSubject.complete();
83
- onSubjectConfigured(providedSubject);
84
- };
85
- objectToDecorate.nextWithValues = (valuesConfigs) => {
86
- if (valuesConfigs.length === 0) {
87
- return;
88
- }
89
- onSubjectConfigured(mergeSubjectWithDefaultValues(providedSubject, valuesConfigs));
90
- };
91
- objectToDecorate.throwWith = (value) => {
92
- providedSubject.error(value);
93
- onSubjectConfigured(providedSubject);
94
- };
95
- objectToDecorate.complete = () => {
96
- providedSubject.complete();
97
- onSubjectConfigured(providedSubject);
98
- };
99
- objectToDecorate.returnSubject = () => {
100
- onSubjectConfigured(providedSubject);
101
- return providedSubject;
102
- };
103
- }
104
- function addNextWithPerCall(objectToDecorate, returnValueContainer, onConfigured = () => void 0) {
105
- objectToDecorate.nextWithPerCall = (valueConfigsPerCall) => {
106
- const returnedSubjects = [];
107
- if (valueConfigsPerCall.length === 0) {
108
- return returnedSubjects;
109
- }
110
- returnValueContainer.valuesPerCalls = [];
111
- valueConfigsPerCall.forEach((valueConfiguration) => {
112
- const replaySubject = new rxjs.ReplaySubject(1);
113
- replaySubject.next(valueConfiguration.value);
114
- returnedSubjects.push(replaySubject);
115
- let returnedObservable = replaySubject.asObservable();
116
- if (valueConfiguration.delay) {
117
- returnedObservable = returnedObservable.pipe(operators.delay(valueConfiguration.delay));
118
- }
119
- if (!valueConfiguration.doNotComplete) {
120
- returnedObservable = returnedObservable.pipe(operators.take(1));
121
- }
122
- returnValueContainer.valuesPerCalls.push({ wrappedValue: returnedObservable });
123
- });
124
- onConfigured(returnValueContainer);
125
- return returnedSubjects;
126
- };
127
- }
128
- function addObservableHelpersToFunctionSpy(spyFunction, valueContainer) {
129
- const subject = createReplaySubject();
130
- addObservableHelpers(spyFunction, subject, (configuredSubject) => {
131
- valueContainer.value = configuredSubject;
132
- });
133
- addNextWithPerCall(spyFunction, valueContainer);
134
- }
135
- function addObservableHelpersToCalledWithObject(calledWithObject, calledWithArgs) {
136
- const subject = createReplaySubject();
137
- const returnValueContainer = { value: void 0 };
138
- addObservableHelpers(calledWithObject, subject, (configuredSubject) => {
139
- returnValueContainer.value = configuredSubject;
140
- calledWithObject.argsToValuesMap.set(calledWithArgs, returnValueContainer);
141
- });
142
- addNextWithPerCall(calledWithObject, returnValueContainer, (configured) => {
143
- calledWithObject.argsToValuesMap.set(calledWithArgs, configured);
144
- });
145
- }
146
- function createObservableWithValues(valuesConfigs, config) {
147
- const subject = createReplaySubject();
148
- const values$ = mergeSubjectWithDefaultValues(subject, valuesConfigs);
149
- if (config && config.returnSubject) {
150
- return { values$, subject };
151
- }
152
- return values$;
153
- }
154
- function createObservablePropSpy() {
155
- let subject = createReplaySubject();
156
- const observableSpy = rxjs.defer(() => subject);
157
- addObservableHelpers(observableSpy, subject, (configuredSubject) => {
158
- subject = configuredSubject;
159
- });
160
- return observableSpy;
161
- }
162
- function addPromiseHelpersToFunctionSpy(spyFunction, valueContainer) {
163
- spyFunction.resolveWith = (value) => {
164
- valueContainer.value = Promise.resolve(value);
165
- };
166
- spyFunction.rejectWith = (value) => {
167
- valueContainer.value = value;
168
- valueContainer._isRejectedPromise = true;
169
- };
170
- spyFunction.resolveWithPerCall = (valueConfigsPerCall) => {
171
- if (valueConfigsPerCall.length === 0) {
172
- return;
173
- }
174
- valueContainer.valuesPerCalls = [];
175
- valueConfigsPerCall.forEach((valueConfiguration) => {
176
- valueContainer.valuesPerCalls.push({
177
- wrappedValue: Promise.resolve(valueConfiguration.value),
178
- delay: valueConfiguration.delay
179
- });
180
- });
181
- };
182
- }
183
- function addPromiseHelpersToCalledWithObject(calledWithObject, calledWithArgs) {
184
- calledWithObject.resolveWith = (value) => {
185
- calledWithObject.argsToValuesMap.set(calledWithArgs, { value: Promise.resolve(value) });
186
- };
187
- calledWithObject.rejectWith = (value) => {
188
- calledWithObject.argsToValuesMap.set(calledWithArgs, { value, _isRejectedPromise: true });
189
- };
190
- calledWithObject.resolveWithPerCall = (valueConfigsPerCall) => {
191
- if (valueConfigsPerCall.length === 0) {
192
- return;
193
- }
194
- const valueContainer = { value: void 0, valuesPerCalls: [] };
195
- valueConfigsPerCall.forEach((valueConfiguration) => {
196
- valueContainer.valuesPerCalls.push({
197
- wrappedValue: Promise.resolve(valueConfiguration.value),
198
- delay: valueConfiguration.delay
199
- });
200
- });
201
- calledWithObject.argsToValuesMap.set(calledWithArgs, valueContainer);
202
- };
203
- }
204
- function getNextCallValue(valueContainer) {
205
- const wrapped = valueContainer.valuesPerCalls.shift();
206
- let returnedValue = wrapped?.wrappedValue;
207
- if (wrapped && wrapped.delay) {
208
- returnedValue = returnedValue.then(
209
- (value) => new Promise((resolve) => setTimeout(() => resolve(value), wrapped.delay))
210
- );
211
- }
212
- return returnedValue;
213
- }
214
- function returnTheCorrectFakeValue(calledWithObject, mustBeCalledWithObject, valueContainer, actualArgs, functionName) {
215
- if (calledWithObject.wasConfigured) {
216
- const configured = calledWithObject.argsToValuesMap.get(actualArgs);
217
- if (configured) {
218
- return unwrapContainer(configured);
219
- }
220
- }
221
- if (mustBeCalledWithObject.wasConfigured) {
222
- const configured = mustBeCalledWithObject.argsToValuesMap.get(actualArgs);
223
- if (configured) {
224
- return unwrapContainer(configured);
225
- }
226
- errorHandler.throwArgumentsError(actualArgs, functionName);
227
- }
228
- return unwrapContainer(valueContainer);
229
- }
230
- function unwrapContainer(container) {
231
- if (container._isRejectedPromise) {
232
- return Promise.reject(container.value);
233
- }
234
- if (container.valuesPerCalls?.length) {
235
- return getNextCallValue(container);
236
- }
237
- return container.value;
238
- }
239
- function addMethodsToCalledWith(calledWith, calledWithArgs) {
240
- calledWith.wasConfigured = true;
241
- calledWith.mockReturnValue = (value) => {
242
- calledWith.argsToValuesMap.set(calledWithArgs, { value });
243
- };
244
- addPromiseHelpersToCalledWithObject(calledWith, calledWithArgs);
245
- addObservableHelpersToCalledWithObject(calledWith, calledWithArgs);
246
- return calledWith;
247
- }
248
- function createFunctionSpy(name) {
249
- const calledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };
250
- const mustBeCalledWithObject = { wasConfigured: false, argsToValuesMap: new ArgsMap() };
251
- const valueContainer = { value: void 0 };
252
- const functionSpy = vitest.vi.fn(
253
- (...actualArgs) => returnTheCorrectFakeValue(calledWithObject, mustBeCalledWithObject, valueContainer, actualArgs, name)
254
- );
255
- functionSpy.mockName(name);
256
- addPromiseHelpersToFunctionSpy(functionSpy, valueContainer);
257
- addObservableHelpersToFunctionSpy(functionSpy, valueContainer);
258
- functionSpy.calledWith = (...calledWithArgs) => addMethodsToCalledWith(calledWithObject, calledWithArgs);
259
- functionSpy.mustBeCalledWith = (...calledWithArgs) => addMethodsToCalledWith(mustBeCalledWithObject, calledWithArgs);
260
- return functionSpy;
261
- }
262
- function defineWithEmptyAccessors(obj, prop) {
263
- Object.defineProperty(obj, prop, {
264
- get() {
265
- return void 0;
266
- },
267
- set(_value) {
268
- },
269
- configurable: true
270
- });
271
- }
272
- function accessorSpyFactory(autoSpy, accessorName, accessorType) {
273
- if (accessorType === "setter") {
274
- return vitest.vi.spyOn(autoSpy, accessorName, "set");
275
- }
276
- return vitest.vi.spyOn(autoSpy, accessorName, "get");
277
- }
278
- function createAccessorsSpies(autoSpy, gettersToSpyOn, settersToSpyOn) {
279
- autoSpy.accessorSpies = { getters: {}, setters: {} };
280
- gettersToSpyOn.forEach((getterName) => {
281
- defineWithEmptyAccessors(autoSpy, getterName);
282
- autoSpy.accessorSpies.getters[getterName] = accessorSpyFactory(autoSpy, getterName, "getter");
283
- });
284
- settersToSpyOn.forEach((setterName) => {
285
- if (!Object.prototype.hasOwnProperty.call(autoSpy, setterName)) {
286
- defineWithEmptyAccessors(autoSpy, setterName);
287
- }
288
- autoSpy.accessorSpies.setters[setterName] = accessorSpyFactory(autoSpy, setterName, "setter");
289
- });
290
- }
291
- function extractMethodsFromObject(obj) {
292
- const descriptors = Object.getOwnPropertyDescriptors(obj);
293
- return Object.keys(descriptors).reduce((names, name) => {
294
- if (name !== "constructor" && !descriptors[name].get) {
295
- names.push(name);
296
- }
297
- return names;
298
- }, []);
299
- }
300
- function getAllMethodNames(obj) {
301
- let methods = [];
302
- while (obj) {
303
- const parentObj = Object.getPrototypeOf(obj);
304
- if (parentObj) {
305
- methods = methods.concat(extractMethodsFromObject(obj));
306
- }
307
- obj = parentObj;
308
- }
309
- return methods;
310
- }
311
- function createSpyFromClass(ObjectClass, methodsToSpyOnOrConfig) {
312
- const methodNames = getAllMethodNames(ObjectClass.prototype);
313
- let methodsToSpyOn = [];
314
- let observablePropsToSpyOn = [];
315
- let settersToSpyOn = [];
316
- let gettersToSpyOn = [];
317
- if (methodsToSpyOnOrConfig) {
318
- if (Array.isArray(methodsToSpyOnOrConfig)) {
319
- methodsToSpyOn = methodsToSpyOnOrConfig;
320
- } else {
321
- methodsToSpyOn = methodsToSpyOnOrConfig.methodsToSpyOn || [];
322
- observablePropsToSpyOn = methodsToSpyOnOrConfig.observablePropsToSpyOn || [];
323
- settersToSpyOn = methodsToSpyOnOrConfig.settersToSpyOn || [];
324
- gettersToSpyOn = methodsToSpyOnOrConfig.gettersToSpyOn || [];
325
- }
326
- }
327
- if (methodsToSpyOn.length > 0) {
328
- methodNames.push(...methodsToSpyOn);
329
- }
330
- const autoSpy = {};
331
- observablePropsToSpyOn.forEach((observablePropName) => {
332
- autoSpy[observablePropName] = createObservablePropSpy();
333
- });
334
- createAccessorsSpies(autoSpy, gettersToSpyOn, settersToSpyOn);
335
- methodNames.forEach((methodName) => {
336
- autoSpy[methodName] = createFunctionSpy(methodName);
337
- });
338
- return autoSpy;
339
- }
340
- function provideAutoSpy(ObjectClass, methodsToSpyOnOrConfig) {
341
- return {
342
- provide: ObjectClass,
343
- useValue: createSpyFromClass(ObjectClass, methodsToSpyOnOrConfig)
344
- };
345
- }
346
- function injectSpy(token) {
347
- return testing.TestBed.inject(token);
348
- }
349
- function mockReadonlyProp(object, property, value) {
350
- Object.defineProperty(object, property, { get: () => value, configurable: true });
351
- }
352
- function mockReadonlyPropGetter(object, property, getter) {
353
- Object.defineProperty(object, property, { get: getter, configurable: true });
354
- }
355
- function mockAccessorsProp(object, property) {
356
- Object.defineProperty(object, property, { get: vitest.vi.fn(), set: vitest.vi.fn(), configurable: true });
357
- }
358
-
359
- exports.createFunctionSpy = createFunctionSpy;
360
- exports.createObservableWithValues = createObservableWithValues;
361
- exports.createSpyFromClass = createSpyFromClass;
362
- exports.errorHandler = errorHandler;
363
- exports.injectSpy = injectSpy;
364
- exports.mockAccessorsProp = mockAccessorsProp;
365
- exports.mockReadonlyProp = mockReadonlyProp;
366
- exports.mockReadonlyPropGetter = mockReadonlyPropGetter;
367
- exports.provideAutoSpy = provideAutoSpy;
368
- //# sourceMappingURL=index.cjs.map
369
- //# sourceMappingURL=index.cjs.map
1
+ 'use strict';var vitest=require('vitest');function m(e,t){Object.defineProperty(e,t,{get(){},set(r){},configurable:true});}function S(e,t,r){let n=t;return r==="setter"?vitest.vi.spyOn(e,n,"set"):vitest.vi.spyOn(e,n,"get")}function T(e,t,r){let n={getters:{},setters:{}};e.accessorSpies=n,t.forEach(o=>{m(e,o),n.getters[o]=S(e,o,"getter");}),r.forEach(o=>{Object.prototype.hasOwnProperty.call(e,o)||m(e,o),n.setters[o]=S(e,o,"setter");});}function x(e){return `'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`}function V(e,t){return Object.entries(e).map(([r,n])=>`${r}:${i(n,t)}`).join(",")}function W(e,t){return `new Map([${[...e.entries()].map(([n,o])=>`[${i(n,t)},${i(o,t)}]`).join(",")}])`}function M(e,t){if(t.has(e))return "[Circular]";t.add(e);let r;return e instanceof Date?r=`new Date(${e.getTime()})`:e instanceof Map?r=W(e,t):e instanceof Set?r=`new Set([${[...e].map(n=>i(n,t)).join(",")}])`:Array.isArray(e)?r=`[${e.map(n=>i(n,t)).join(",")}]`:r=`{${V(e,t)}}`,t.delete(e),r}function i(e,t=new WeakSet){return typeof e=="string"?x(e):typeof e=="bigint"?`${e}n`:typeof e=="symbol"?e.toString():typeof e=="function"?`[Function: ${e.name}]`:typeof e=="object"&&e!==null?M(e,t):Object.is(e,-0)?"-0":String(e)}var l=class{#e={};set(t,r){this.#e[this.#t(t)]=r;}get(t){return this.#e[this.#t(t)]}#t(t){return i(t)}};var A=e=>`The function '${e}' was configured with 'mustBeCalledWith' and expects to be called with specific arguments. `,F="But the function was called without any arguments.",E=e=>{let t=i(e);return `But the actual arguments were: ${t.substring(1,t.length-1)}`},d={throwArgumentsError(e,t){let r=e.length===0?F:E(e);throw new Error(A(t)+r)}};var H="Observable spies require rxjs. Import 'vitest-auto-spy/rxjs' once (e.g. in your test setup) to enable observablePropsToSpyOn / nextWith / nextWithValues / throwWith / complete / returnSubject.";function O(){throw new Error(H);}function a(e,t){return Object.assign(e,t)}function _(e){return e.map(t=>({wrappedValue:t.delay===void 0?Promise.resolve(t.value):new Promise(r=>setTimeout(()=>r(t.value),t.delay))}))}function h(e,t){a(e,{resolveWith:r=>{t({value:Promise.resolve(r)});},rejectWith:r=>{t({value:r,_isRejectedPromise:true});},resolveWithPerCall:r=>{r.length!==0&&t({value:void 0,valuesPerCalls:_(r)});}});}function w(e,t){h(e,r=>{t.value=r.value,t._isRejectedPromise=r._isRejectedPromise??false,t.valuesPerCalls=r.valuesPerCalls??[];});}function C(e,t){h(e,r=>{e.argsToValuesMap.set(t,r);});}function z(e){return typeof e=="object"&&e!==null&&"value"in e}function P(e){if(e._isRejectedPromise)return Promise.reject(e.value);let t=e.valuesPerCalls?.shift();return t?t.wrappedValue:e.value}function j(e,t){let r=e.argsToValuesMap.get(t);return z(r)?{found:true,value:P(r)}:{found:false,value:void 0}}function I(e,t,r,n,o){if(e.wasConfigured){let s=j(e,n);if(s.found)return s.value}if(t.wasConfigured){let s=j(t,n);if(s.found)return s.value;d.throwArgumentsError(n,o);}return P(r)}function k(e,t){return e.wasConfigured=true,a(e,{mockReturnValue:r=>{e.argsToValuesMap.set(t,{value:r});}}),C(e,t),e}function v(){return {wasConfigured:false,argsToValuesMap:new l}}function b(e){let t=v(),r=v(),n={value:void 0},o=vitest.vi.fn((...u)=>I(t,r,n,u,e));o.mockName(e),w(o,n);let s=a(o,{calledWith:(...u)=>k(t,u),mustBeCalledWith:(...u)=>k(r,u)});return s}var R={methodsToSpyOn:[],observablePropsToSpyOn:[],settersToSpyOn:[],gettersToSpyOn:[]};function B(e){let t=Object.getOwnPropertyDescriptors(e);return Object.keys(t).filter(r=>r!=="constructor"&&!t[r]?.get)}function q(e){let t=new Set,r=e;for(;r;){let n=Object.getPrototypeOf(r);n&&B(r).forEach(o=>t.add(o)),r=n;}return [...t]}function D(e){return e?Array.isArray(e)?{...R,methodsToSpyOn:e}:{methodsToSpyOn:e.methodsToSpyOn??[],observablePropsToSpyOn:e.observablePropsToSpyOn??[],settersToSpyOn:e.settersToSpyOn??[],gettersToSpyOn:e.gettersToSpyOn??[]}:{...R}}function G(e,t){let{methodsToSpyOn:r,observablePropsToSpyOn:n,settersToSpyOn:o,gettersToSpyOn:s}=D(t),u=r.length>0?r:q(e.prototype),p={};return n.forEach(c=>{p[c]=O().createPropSpy();}),T(p,s,o),u.forEach(c=>{p[c]=b(c);}),p}exports.createFunctionSpy=b;exports.createSpyFromClass=G;exports.errorHandler=d;