Просмотр исходного кода

feat: adds empty spies and calls property

e22m4u 1 месяц назад
Родитель
Сommit
0dc91d601e
5 измененных файлов с 104 добавлено и 4 удалено
  1. 34 4
      README.md
  2. 9 0
      dist/cjs/index.cjs
  3. 16 0
      src/create-spy.d.ts
  4. 16 0
      src/create-spy.js
  5. 29 0
      src/create-spy.spec.js

+ 34 - 4
README.md

@@ -13,6 +13,7 @@
   - [createSpy(target, [methodNameOrImpl], [customImplForMethod])](#createspytarget-methodnameorimpl-customimplformethod)
   - [Свойства и методы шпиона](#свойства-и-методы-шпиона)
     - [spy(...args)](#spyargs)
+    - [spy.calls](#spycalls)
     - [spy.called](#spycalled)
     - [spy.callCount](#spycallcount)
     - [spy.getCall(n)](#spygetcalln)
@@ -266,13 +267,42 @@ const result = spy(5);      // result будет 10
 console.log(spy.callCount); // 1
 ```
 
+#### spy.calls
+
+- **Тип:** `CallInfo[]` (только для чтения)
+- **Описание:** Возвращает массив вызовов.
+
+```js
+const fn = (a, b) => a + b;
+const spy = createSpy(fn);
+console.log(spy.calls); // []
+
+spy(4, 2);
+spy(5, 3);
+console.log(spy.calls);
+// [
+//   {
+//     args: [4, 2],
+//     thisArg: undefined,
+//     returnValue: 6,
+//     error: undefined,
+//   },
+//   {
+//     args: [5, 3],
+//     thisArg: undefined,
+//     returnValue: 8,
+//     error: undefined,
+//   }
+// ]
+```
+
 #### spy.called
 
 - **Тип:** `boolean` (только для чтения)
 - **Описание:** Указывает, был ли шпион вызван хотя бы один раз.
 
 ```js
-const spy = createSpy(() => {});
+const spy = createSpy();
 console.log(spy.called); // false
 spy();
 console.log(spy.called); // true
@@ -284,7 +314,7 @@ console.log(spy.called); // true
 - **Описание:** Количество раз, которое шпион был вызван.
 
 ```js
-const spy = createSpy(() => {});
+const spy = createSpy();
 console.log(spy.callCount); // 0
 spy();
 spy();
@@ -342,7 +372,7 @@ try {
 Пример:
 
 ```js
-const spy = createSpy(() => {});
+const spy = createSpy();
 spy(1, 'a', true);
 spy(2, 'b');
 
@@ -373,7 +403,7 @@ console.log(spy.calledWith(2, 'c'));       // false
 Пример:
 
 ```js
-const spy = createSpy(() => {});
+const spy = createSpy();
 spy('first call');
 spy('second call', 123);
 

+ 9 - 0
dist/cjs/index.cjs

@@ -94,6 +94,10 @@ function _parseSpyArgs(target, methodNameOrImplFromSpy, customImplForMethodFromS
 }
 __name(_parseSpyArgs, "_parseSpyArgs");
 function createSpy(target, methodNameOrImpl, customImplForMethod) {
+  if (typeof target === "undefined" && typeof methodNameOrImpl === "undefined" && typeof customImplForMethod === "undefined") {
+    target = /* @__PURE__ */ __name(function() {
+    }, "target");
+  }
   const { originalFn, fnToExecute, isMethodSpy, objToSpyOn, methodName } = _parseSpyArgs(target, methodNameOrImpl, customImplForMethod);
   const callLog = {
     count: 0,
@@ -121,6 +125,11 @@ function createSpy(target, methodNameOrImpl, customImplForMethod) {
       throw e;
     }
   }, "spy");
+  Object.defineProperty(spy, "calls", {
+    get: /* @__PURE__ */ __name(() => callLog.calls, "get"),
+    enumerable: true,
+    configurable: false
+  });
   Object.defineProperty(spy, "callCount", {
     get: /* @__PURE__ */ __name(() => callLog.count, "get"),
     enumerable: true,

+ 16 - 0
src/create-spy.d.ts

@@ -59,8 +59,16 @@ export interface Spy<TFunc extends AnyCallable = AnyCallable> {
    */
   (...args: Parameters<TFunc>): ReturnType<TFunc>;
 
+  /**
+   * Вызовы шпиона.
+   * 
+   * @readonly
+   */
+  readonly calls: CallInfo[];
+
   /**
    * Количество вызовов шпиона.
+   * 
    * @readonly
    */
   readonly callCount: number;
@@ -147,6 +155,14 @@ export interface Spy<TFunc extends AnyCallable = AnyCallable> {
   restore(): void;
 }
 
+/**
+ * Создает шпиона.
+ *
+ * @template TFunc Тип функции-заглушки.
+ * @returns        Функция-шпион.
+ */
+export function createSpy<TFunc extends AnyCallable>(): Spy<TFunc>;
+
 /**
  * Создает шпиона для отдельной функции.
  *

+ 16 - 0
src/create-spy.js

@@ -146,6 +146,15 @@ function _parseSpyArgs(
  * @returns {(function(...[*]): (*|undefined))|*} Шпион-функция.
  */
 export function createSpy(target, methodNameOrImpl, customImplForMethod) {
+  // если аргументы не передавались,
+  // то определяется функция-пустышка
+  if (
+    typeof target === 'undefined' &&
+    typeof methodNameOrImpl === 'undefined' &&
+    typeof customImplForMethod === 'undefined'
+  ) {
+    target = function () {};
+  }
   // получение конфигурации шпиона
   // путем разбора входных аргументов
   const {originalFn, fnToExecute, isMethodSpy, objToSpyOn, methodName} =
@@ -200,6 +209,13 @@ export function createSpy(target, methodNameOrImpl, customImplForMethod) {
       throw e;
     }
   };
+  // определение свойства `calls` на шпионе,
+  // для получения вызовов
+  Object.defineProperty(spy, 'calls', {
+    get: () => callLog.calls,
+    enumerable: true,
+    configurable: false,
+  });
   // определение свойства `callCount` на шпионе
   // для получения количества вызовов
   Object.defineProperty(spy, 'callCount', {

+ 29 - 0
src/create-spy.spec.js

@@ -3,6 +3,14 @@ import {createSpy} from './create-spy.js';
 
 describe('createSpy', function () {
   describe('argument validation', function () {
+    it('should allow to create spy without arguments', function () {
+      const spy = createSpy();
+      expect(spy).to.be.a('function');
+      const res = spy();
+      expect(res).to.be.undefined;
+      expect(spy.calls).to.have.length(1);
+    });
+
     it('should throw when trying to spy on null', function () {
       // проверка генерации ошибки при попытке
       // шпионить за значением null
@@ -317,6 +325,27 @@ describe('createSpy', function () {
       spy = createSpy(targetFn);
     });
 
+    describe('.calls', function () {
+      it('should return an array of CallInfo', function () {
+        expect(spy.calls).to.be.eql([]);
+        spy(1, 2);
+        expect(spy.calls[0]).to.be.eql({
+          args: [1, 2],
+          thisArg: undefined,
+          returnValue: 3,
+          error: undefined,
+        });
+        spy(5, 3);
+        expect(spy.calls[1]).to.be.eql({
+          args: [5, 3],
+          thisArg: undefined,
+          returnValue: 8,
+          error: undefined,
+        });
+        expect(spy.calls).to.have.length(2);
+      });
+    });
+
     describe('.callCount and .called', function () {
       it('should have callCount = 0 and called = false initially', function () {
         // начальное состояние счетчика вызовов