index.cjs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. var __defProp = Object.defineProperty;
  2. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  3. var __getOwnPropNames = Object.getOwnPropertyNames;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
  6. var __export = (target, all) => {
  7. for (var name in all)
  8. __defProp(target, name, { get: all[name], enumerable: true });
  9. };
  10. var __copyProps = (to, from, except, desc) => {
  11. if (from && typeof from === "object" || typeof from === "function") {
  12. for (let key of __getOwnPropNames(from))
  13. if (!__hasOwnProp.call(to, key) && key !== except)
  14. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  15. }
  16. return to;
  17. };
  18. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  19. // src/index.js
  20. var index_exports = {};
  21. __export(index_exports, {
  22. createSpy: () => createSpy
  23. });
  24. module.exports = __toCommonJS(index_exports);
  25. // src/create-spy.js
  26. function _parseSpyArgs(target, methodNameOrImplFromSpy, customImplForMethodFromSpy) {
  27. let originalFn;
  28. let customImplementation;
  29. let isMethodSpy = false;
  30. let objToSpyOn;
  31. let methodName;
  32. const isLikelyFunctionSpy = typeof target === "function" && customImplForMethodFromSpy === void 0;
  33. const isLikelyMethodSpy = typeof target === "object" && target !== null && typeof methodNameOrImplFromSpy === "string";
  34. if (isLikelyFunctionSpy) {
  35. originalFn = target;
  36. if (methodNameOrImplFromSpy !== void 0) {
  37. if (typeof methodNameOrImplFromSpy !== "function") {
  38. throw new TypeError(
  39. "When spying on a function, the second argument (custom implementation) must be a function if provided."
  40. );
  41. }
  42. customImplementation = methodNameOrImplFromSpy;
  43. }
  44. } else if (isLikelyMethodSpy) {
  45. methodName = methodNameOrImplFromSpy;
  46. objToSpyOn = target;
  47. isMethodSpy = true;
  48. if (!(methodName in target)) {
  49. throw new TypeError(
  50. `Attempted to spy on a non-existent property: "${methodName}"`
  51. );
  52. }
  53. const propertyToSpyOn = target[methodName];
  54. if (typeof propertyToSpyOn !== "function") {
  55. throw new TypeError(
  56. `Attempted to spy on "${methodName}" which is not a function. It is a "${typeof propertyToSpyOn}".`
  57. );
  58. }
  59. originalFn = propertyToSpyOn;
  60. if (customImplForMethodFromSpy !== void 0) {
  61. if (typeof customImplForMethodFromSpy !== "function") {
  62. throw new TypeError(
  63. "When spying on a method, the third argument (custom implementation) must be a function if provided."
  64. );
  65. }
  66. customImplementation = customImplForMethodFromSpy;
  67. }
  68. } else {
  69. if (target === null && methodNameOrImplFromSpy === void 0 && customImplForMethodFromSpy === void 0) {
  70. throw new TypeError("Attempted to spy on null.");
  71. }
  72. if (methodNameOrImplFromSpy === void 0 && typeof target !== "function") {
  73. throw new TypeError(
  74. `Attempted to spy on a ${typeof target} which is not a function.`
  75. );
  76. }
  77. throw new Error(
  78. "Invalid arguments. Valid signatures:\n createSpy(function, [customImplementationFunction])\n createSpy(object, methodNameString, [customImplementationFunction])"
  79. );
  80. }
  81. return {
  82. originalFn,
  83. // определение функции для выполнения шпионом: либо
  84. // пользовательская реализация, либо оригинальная функция
  85. fnToExecute: customImplementation || originalFn,
  86. isMethodSpy,
  87. objToSpyOn,
  88. methodName
  89. };
  90. }
  91. __name(_parseSpyArgs, "_parseSpyArgs");
  92. function createSpy(target, methodNameOrImpl, customImplForMethod) {
  93. const { originalFn, fnToExecute, isMethodSpy, objToSpyOn, methodName } = _parseSpyArgs(target, methodNameOrImpl, customImplForMethod);
  94. const callLog = {
  95. count: 0,
  96. calls: []
  97. };
  98. const spy = /* @__PURE__ */ __name(function(...args) {
  99. callLog.count++;
  100. const callInfo = {
  101. // сохранение аргументов, с которыми
  102. // был вызван шпион
  103. args: [...args],
  104. // сохранение контекста (this)
  105. // вызова шпиона
  106. thisArg: this,
  107. returnValue: void 0,
  108. error: void 0
  109. };
  110. try {
  111. callInfo.returnValue = fnToExecute.apply(this, args);
  112. callLog.calls.push(callInfo);
  113. return callInfo.returnValue;
  114. } catch (e) {
  115. callInfo.error = e;
  116. callLog.calls.push(callInfo);
  117. throw e;
  118. }
  119. }, "spy");
  120. Object.defineProperty(spy, "callCount", {
  121. get: /* @__PURE__ */ __name(() => callLog.count, "get"),
  122. enumerable: true,
  123. configurable: false
  124. });
  125. Object.defineProperty(spy, "called", {
  126. get: /* @__PURE__ */ __name(() => callLog.count > 0, "get"),
  127. enumerable: true,
  128. configurable: false
  129. });
  130. spy.getCall = (n) => {
  131. if (typeof n !== "number" || n < 0 || n >= callLog.calls.length) {
  132. throw new RangeError(
  133. `Invalid call index ${n}. Spy has ${callLog.calls.length} call(s).`
  134. );
  135. }
  136. return callLog.calls[n];
  137. };
  138. spy.calledWith = (...expectedArgs) => {
  139. return callLog.calls.some(
  140. (call) => call.args.length === expectedArgs.length && call.args.every((arg, i) => Object.is(arg, expectedArgs[i]))
  141. );
  142. };
  143. spy.nthCalledWith = (n, ...expectedArgs) => {
  144. const call = spy.getCall(n);
  145. return call.args.length === expectedArgs.length && call.args.every((arg, i) => Object.is(arg, expectedArgs[i]));
  146. };
  147. spy.nthCallReturned = (n, expectedReturnValue) => {
  148. const call = spy.getCall(n);
  149. if (call.error) return false;
  150. return Object.is(call.returnValue, expectedReturnValue);
  151. };
  152. spy.nthCallThrew = (n, expectedError) => {
  153. const call = spy.getCall(n);
  154. if (call.error === void 0) return false;
  155. if (expectedError === void 0) return true;
  156. if (call.error === expectedError) return true;
  157. if (typeof expectedError === "string") {
  158. return call.error && typeof call.error.message === "string" && call.error.message === expectedError;
  159. }
  160. if (typeof expectedError === "function" && call.error instanceof expectedError) {
  161. return true;
  162. }
  163. if (expectedError instanceof Error && call.error instanceof Error) {
  164. return call.error.name === expectedError.name && call.error.message === expectedError.message;
  165. }
  166. return Object.is(call.error, expectedError);
  167. };
  168. spy.restore = () => {
  169. if (isMethodSpy && objToSpyOn) {
  170. objToSpyOn[methodName] = originalFn;
  171. }
  172. };
  173. if (isMethodSpy && objToSpyOn) {
  174. objToSpyOn[methodName] = spy;
  175. }
  176. return spy;
  177. }
  178. __name(createSpy, "createSpy");
  179. // Annotate the CommonJS export names for ESM import in node:
  180. 0 && (module.exports = {
  181. createSpy
  182. });