index.cjs 7.2 KB

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