index.cjs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. "use strict";
  2. var __defProp = Object.defineProperty;
  3. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  4. var __getOwnPropNames = Object.getOwnPropertyNames;
  5. var __hasOwnProp = Object.prototype.hasOwnProperty;
  6. var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
  7. var __export = (target, all) => {
  8. for (var name in all)
  9. __defProp(target, name, { get: all[name], enumerable: true });
  10. };
  11. var __copyProps = (to, from, except, desc) => {
  12. if (from && typeof from === "object" || typeof from === "function") {
  13. for (let key of __getOwnPropNames(from))
  14. if (!__hasOwnProp.call(to, key) && key !== except)
  15. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  16. }
  17. return to;
  18. };
  19. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  20. // src/index.js
  21. var index_exports = {};
  22. __export(index_exports, {
  23. SpiesGroup: () => SpiesGroup,
  24. createSpiesGroup: () => createSpiesGroup,
  25. createSpy: () => createSpy
  26. });
  27. module.exports = __toCommonJS(index_exports);
  28. // src/create-spy.js
  29. function _parseSpyArgs(target, methodNameOrImpl, customImplForMethod) {
  30. let originalFn;
  31. let customImplementation;
  32. let isMethodSpy = false;
  33. let objToSpyOn;
  34. let methodName;
  35. let hasOwnMethod = false;
  36. const isLikelyFunctionSpy = typeof target === "function" && customImplForMethod === void 0;
  37. const isLikelyMethodSpy = typeof target === "object" && target !== null && typeof methodNameOrImpl === "string";
  38. if (isLikelyFunctionSpy) {
  39. originalFn = target;
  40. if (methodNameOrImpl !== void 0) {
  41. if (typeof methodNameOrImpl !== "function") {
  42. throw new TypeError(
  43. "When spying on a function, the second argument (custom implementation) must be a function if provided."
  44. );
  45. }
  46. customImplementation = methodNameOrImpl;
  47. }
  48. } else if (isLikelyMethodSpy) {
  49. methodName = methodNameOrImpl;
  50. objToSpyOn = target;
  51. isMethodSpy = true;
  52. hasOwnMethod = Object.prototype.hasOwnProperty.call(objToSpyOn, methodName);
  53. if (!(methodName in target)) {
  54. throw new TypeError(
  55. `Attempted to spy on a non-existent property: "${methodName}"`
  56. );
  57. }
  58. const propertyToSpyOn = target[methodName];
  59. if (typeof propertyToSpyOn !== "function") {
  60. throw new TypeError(
  61. `Attempted to spy on "${methodName}" which is not a function. It is a "${typeof propertyToSpyOn}".`
  62. );
  63. }
  64. originalFn = propertyToSpyOn;
  65. if (customImplForMethod !== void 0) {
  66. if (typeof customImplForMethod !== "function") {
  67. throw new TypeError(
  68. "When spying on a method, the third argument (custom implementation) must be a function if provided."
  69. );
  70. }
  71. customImplementation = customImplForMethod;
  72. }
  73. } else {
  74. if (target === null && methodNameOrImpl === void 0 && customImplForMethod === void 0) {
  75. throw new TypeError("Attempted to spy on null.");
  76. }
  77. if (methodNameOrImpl === void 0 && typeof target !== "function") {
  78. throw new TypeError(
  79. "Attempted to spy on a non-function value. To spy on an object method, you must provide the method name as the second argument."
  80. );
  81. }
  82. throw new Error(
  83. "Invalid arguments. Valid signatures:\n createSpy(function, [customImplementationFunction])\n createSpy(object, methodNameString, [customImplementationFunction])"
  84. );
  85. }
  86. return {
  87. originalFn,
  88. // определение функции для выполнения шпионом: либо
  89. // пользовательская реализация, либо оригинальная функция
  90. fnToExecute: customImplementation || originalFn,
  91. isMethodSpy,
  92. objToSpyOn,
  93. methodName,
  94. hasOwnMethod
  95. };
  96. }
  97. __name(_parseSpyArgs, "_parseSpyArgs");
  98. function createSpy(target = void 0, methodNameOrImpl = void 0, customImplForMethod = void 0) {
  99. if (typeof target === "undefined" && typeof methodNameOrImpl === "undefined" && typeof customImplForMethod === "undefined") {
  100. target = /* @__PURE__ */ __name(function() {
  101. }, "target");
  102. }
  103. const {
  104. originalFn,
  105. fnToExecute,
  106. isMethodSpy,
  107. objToSpyOn,
  108. methodName,
  109. hasOwnMethod
  110. } = _parseSpyArgs(target, methodNameOrImpl, customImplForMethod);
  111. const callLog = {
  112. count: 0,
  113. calls: []
  114. };
  115. const spy = /* @__PURE__ */ __name(function(...args) {
  116. callLog.count++;
  117. const callInfo = {
  118. // сохранение аргументов, с которыми
  119. // был вызван шпион
  120. args: [...args],
  121. // сохранение контекста (this)
  122. // вызова шпиона
  123. thisArg: this,
  124. returnValue: void 0,
  125. error: void 0
  126. };
  127. try {
  128. callInfo.returnValue = fnToExecute.apply(this, args);
  129. callLog.calls.push(callInfo);
  130. return callInfo.returnValue;
  131. } catch (e) {
  132. callInfo.error = e;
  133. callLog.calls.push(callInfo);
  134. throw e;
  135. }
  136. }, "spy");
  137. Object.defineProperty(spy, "calls", {
  138. get: /* @__PURE__ */ __name(() => callLog.calls, "get"),
  139. enumerable: true,
  140. configurable: false
  141. });
  142. Object.defineProperty(spy, "callCount", {
  143. get: /* @__PURE__ */ __name(() => callLog.count, "get"),
  144. enumerable: true,
  145. configurable: false
  146. });
  147. Object.defineProperty(spy, "called", {
  148. get: /* @__PURE__ */ __name(() => callLog.count > 0, "get"),
  149. enumerable: true,
  150. configurable: false
  151. });
  152. spy.restore = () => {
  153. if (isMethodSpy && objToSpyOn) {
  154. if (originalFn !== void 0) {
  155. if (hasOwnMethod) {
  156. objToSpyOn[methodName] = originalFn;
  157. } else {
  158. delete objToSpyOn[methodName];
  159. }
  160. }
  161. }
  162. callLog.count = 0;
  163. callLog.calls = [];
  164. };
  165. if (isMethodSpy && objToSpyOn) {
  166. objToSpyOn[methodName] = spy;
  167. }
  168. spy.__isSpy = true;
  169. return spy;
  170. }
  171. __name(createSpy, "createSpy");
  172. // src/create-spies-group.js
  173. var _SpiesGroup = class _SpiesGroup {
  174. /**
  175. * Constructor.
  176. */
  177. constructor() {
  178. this.spies = [];
  179. }
  180. /**
  181. * Создает шпиона для отдельной функции
  182. * или метода объекта и добавляет его в группу.
  183. *
  184. * @param {Function|object} [target]
  185. * @param {Function|string} [methodNameOrImpl]
  186. * @param {Function} [customImplForMethod]
  187. * @returns {Function}
  188. */
  189. on(target, methodNameOrImpl, customImplForMethod) {
  190. const spy = createSpy(target, methodNameOrImpl, customImplForMethod);
  191. this.spies.push(spy);
  192. return spy;
  193. }
  194. /**
  195. * Восстановление всех оригинальных методов объектов,
  196. * для которых были созданы шпионы в этой группе,
  197. * и сброс истории вызовов для всех шпионов в группе.
  198. * Очищает внутренний список шпионов.
  199. *
  200. * @returns {this}
  201. */
  202. restore() {
  203. this.spies.forEach((spy) => spy.restore());
  204. this.spies = [];
  205. return this;
  206. }
  207. };
  208. __name(_SpiesGroup, "SpiesGroup");
  209. var SpiesGroup = _SpiesGroup;
  210. function createSpiesGroup() {
  211. return new SpiesGroup();
  212. }
  213. __name(createSpiesGroup, "createSpiesGroup");
  214. // Annotate the CommonJS export names for ESM import in node:
  215. 0 && (module.exports = {
  216. SpiesGroup,
  217. createSpiesGroup,
  218. createSpy
  219. });