index.cjs 7.7 KB

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