1 | 'use strict';
|
2 |
|
3 | function _defineProperty(obj, key, value) {
|
4 | if (key in obj) {
|
5 | Object.defineProperty(obj, key, {
|
6 | value: value,
|
7 | enumerable: true,
|
8 | configurable: true,
|
9 | writable: true
|
10 | });
|
11 | } else {
|
12 | obj[key] = value;
|
13 | }
|
14 | return obj;
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | const MOCK_CONSTRUCTOR_NAME = 'mockConstructor';
|
38 | const FUNCTION_NAME_RESERVED_PATTERN = /[\s!-\/:-@\[-`{-~]/;
|
39 | const FUNCTION_NAME_RESERVED_REPLACE = new RegExp(
|
40 | FUNCTION_NAME_RESERVED_PATTERN.source,
|
41 | 'g'
|
42 | );
|
43 | const RESERVED_KEYWORDS = new Set([
|
44 | 'arguments',
|
45 | 'await',
|
46 | 'break',
|
47 | 'case',
|
48 | 'catch',
|
49 | 'class',
|
50 | 'const',
|
51 | 'continue',
|
52 | 'debugger',
|
53 | 'default',
|
54 | 'delete',
|
55 | 'do',
|
56 | 'else',
|
57 | 'enum',
|
58 | 'eval',
|
59 | 'export',
|
60 | 'extends',
|
61 | 'false',
|
62 | 'finally',
|
63 | 'for',
|
64 | 'function',
|
65 | 'if',
|
66 | 'implements',
|
67 | 'import',
|
68 | 'in',
|
69 | 'instanceof',
|
70 | 'interface',
|
71 | 'let',
|
72 | 'new',
|
73 | 'null',
|
74 | 'package',
|
75 | 'private',
|
76 | 'protected',
|
77 | 'public',
|
78 | 'return',
|
79 | 'static',
|
80 | 'super',
|
81 | 'switch',
|
82 | 'this',
|
83 | 'throw',
|
84 | 'true',
|
85 | 'try',
|
86 | 'typeof',
|
87 | 'var',
|
88 | 'void',
|
89 | 'while',
|
90 | 'with',
|
91 | 'yield'
|
92 | ]);
|
93 |
|
94 | function matchArity(fn, length) {
|
95 | let mockConstructor;
|
96 |
|
97 | switch (length) {
|
98 | case 1:
|
99 | mockConstructor = function (_a) {
|
100 | return fn.apply(this, arguments);
|
101 | };
|
102 |
|
103 | break;
|
104 |
|
105 | case 2:
|
106 | mockConstructor = function (_a, _b) {
|
107 | return fn.apply(this, arguments);
|
108 | };
|
109 |
|
110 | break;
|
111 |
|
112 | case 3:
|
113 | mockConstructor = function (_a, _b, _c) {
|
114 | return fn.apply(this, arguments);
|
115 | };
|
116 |
|
117 | break;
|
118 |
|
119 | case 4:
|
120 | mockConstructor = function (_a, _b, _c, _d) {
|
121 | return fn.apply(this, arguments);
|
122 | };
|
123 |
|
124 | break;
|
125 |
|
126 | case 5:
|
127 | mockConstructor = function (_a, _b, _c, _d, _e) {
|
128 | return fn.apply(this, arguments);
|
129 | };
|
130 |
|
131 | break;
|
132 |
|
133 | case 6:
|
134 | mockConstructor = function (_a, _b, _c, _d, _e, _f) {
|
135 | return fn.apply(this, arguments);
|
136 | };
|
137 |
|
138 | break;
|
139 |
|
140 | case 7:
|
141 | mockConstructor = function (_a, _b, _c, _d, _e, _f, _g) {
|
142 | return fn.apply(this, arguments);
|
143 | };
|
144 |
|
145 | break;
|
146 |
|
147 | case 8:
|
148 | mockConstructor = function (_a, _b, _c, _d, _e, _f, _g, _h) {
|
149 | return fn.apply(this, arguments);
|
150 | };
|
151 |
|
152 | break;
|
153 |
|
154 | case 9:
|
155 | mockConstructor = function (_a, _b, _c, _d, _e, _f, _g, _h, _i) {
|
156 | return fn.apply(this, arguments);
|
157 | };
|
158 |
|
159 | break;
|
160 |
|
161 | default:
|
162 | mockConstructor = function () {
|
163 | return fn.apply(this, arguments);
|
164 | };
|
165 |
|
166 | break;
|
167 | }
|
168 |
|
169 | return mockConstructor;
|
170 | }
|
171 |
|
172 | function getObjectType(value) {
|
173 | return Object.prototype.toString.apply(value).slice(8, -1);
|
174 | }
|
175 |
|
176 | function getType(ref) {
|
177 | const typeName = getObjectType(ref);
|
178 |
|
179 | if (
|
180 | typeName === 'Function' ||
|
181 | typeName === 'AsyncFunction' ||
|
182 | typeName === 'GeneratorFunction'
|
183 | ) {
|
184 | return 'function';
|
185 | } else if (Array.isArray(ref)) {
|
186 | return 'array';
|
187 | } else if (typeName === 'Object') {
|
188 | return 'object';
|
189 | } else if (
|
190 | typeName === 'Number' ||
|
191 | typeName === 'String' ||
|
192 | typeName === 'Boolean' ||
|
193 | typeName === 'Symbol'
|
194 | ) {
|
195 | return 'constant';
|
196 | } else if (
|
197 | typeName === 'Map' ||
|
198 | typeName === 'WeakMap' ||
|
199 | typeName === 'Set'
|
200 | ) {
|
201 | return 'collection';
|
202 | } else if (typeName === 'RegExp') {
|
203 | return 'regexp';
|
204 | } else if (ref === undefined) {
|
205 | return 'undefined';
|
206 | } else if (ref === null) {
|
207 | return 'null';
|
208 | } else {
|
209 | return null;
|
210 | }
|
211 | }
|
212 |
|
213 | function isReadonlyProp(object, prop) {
|
214 | if (
|
215 | prop === 'arguments' ||
|
216 | prop === 'caller' ||
|
217 | prop === 'callee' ||
|
218 | prop === 'name' ||
|
219 | prop === 'length'
|
220 | ) {
|
221 | const typeName = getObjectType(object);
|
222 | return (
|
223 | typeName === 'Function' ||
|
224 | typeName === 'AsyncFunction' ||
|
225 | typeName === 'GeneratorFunction'
|
226 | );
|
227 | }
|
228 |
|
229 | if (
|
230 | prop === 'source' ||
|
231 | prop === 'global' ||
|
232 | prop === 'ignoreCase' ||
|
233 | prop === 'multiline'
|
234 | ) {
|
235 | return getObjectType(object) === 'RegExp';
|
236 | }
|
237 |
|
238 | return false;
|
239 | }
|
240 |
|
241 | class ModuleMockerClass {
|
242 | |
243 |
|
244 |
|
245 |
|
246 |
|
247 | constructor(global) {
|
248 | _defineProperty(this, '_environmentGlobal', void 0);
|
249 |
|
250 | _defineProperty(this, '_mockState', void 0);
|
251 |
|
252 | _defineProperty(this, '_mockConfigRegistry', void 0);
|
253 |
|
254 | _defineProperty(this, '_spyState', void 0);
|
255 |
|
256 | _defineProperty(this, '_invocationCallCounter', void 0);
|
257 |
|
258 | _defineProperty(this, 'ModuleMocker', void 0);
|
259 |
|
260 | this._environmentGlobal = global;
|
261 | this._mockState = new WeakMap();
|
262 | this._mockConfigRegistry = new WeakMap();
|
263 | this._spyState = new Set();
|
264 | this.ModuleMocker = ModuleMockerClass;
|
265 | this._invocationCallCounter = 1;
|
266 | }
|
267 |
|
268 | _getSlots(object) {
|
269 | if (!object) {
|
270 | return [];
|
271 | }
|
272 |
|
273 | const slots = new Set();
|
274 | const EnvObjectProto = this._environmentGlobal.Object.prototype;
|
275 | const EnvFunctionProto = this._environmentGlobal.Function.prototype;
|
276 | const EnvRegExpProto = this._environmentGlobal.RegExp.prototype;
|
277 |
|
278 |
|
279 | const ObjectProto = Object.prototype;
|
280 | const FunctionProto = Function.prototype;
|
281 | const RegExpProto = RegExp.prototype;
|
282 |
|
283 |
|
284 | while (
|
285 | object != null &&
|
286 | object !== EnvObjectProto &&
|
287 | object !== EnvFunctionProto &&
|
288 | object !== EnvRegExpProto &&
|
289 | object !== ObjectProto &&
|
290 | object !== FunctionProto &&
|
291 | object !== RegExpProto
|
292 | ) {
|
293 | const ownNames = Object.getOwnPropertyNames(object);
|
294 |
|
295 | for (let i = 0; i < ownNames.length; i++) {
|
296 | const prop = ownNames[i];
|
297 |
|
298 | if (!isReadonlyProp(object, prop)) {
|
299 | const propDesc = Object.getOwnPropertyDescriptor(object, prop);
|
300 |
|
301 | if ((propDesc !== undefined && !propDesc.get) || object.__esModule) {
|
302 | slots.add(prop);
|
303 | }
|
304 | }
|
305 | }
|
306 |
|
307 | object = Object.getPrototypeOf(object);
|
308 | }
|
309 |
|
310 | return Array.from(slots);
|
311 | }
|
312 |
|
313 | _ensureMockConfig(f) {
|
314 | let config = this._mockConfigRegistry.get(f);
|
315 |
|
316 | if (!config) {
|
317 | config = this._defaultMockConfig();
|
318 |
|
319 | this._mockConfigRegistry.set(f, config);
|
320 | }
|
321 |
|
322 | return config;
|
323 | }
|
324 |
|
325 | _ensureMockState(f) {
|
326 | let state = this._mockState.get(f);
|
327 |
|
328 | if (!state) {
|
329 | state = this._defaultMockState();
|
330 |
|
331 | this._mockState.set(f, state);
|
332 | }
|
333 |
|
334 | return state;
|
335 | }
|
336 |
|
337 | _defaultMockConfig() {
|
338 | return {
|
339 | mockImpl: undefined,
|
340 | mockName: 'jest.fn()',
|
341 | specificMockImpls: [],
|
342 | specificReturnValues: []
|
343 | };
|
344 | }
|
345 |
|
346 | _defaultMockState() {
|
347 | return {
|
348 | calls: [],
|
349 | instances: [],
|
350 | invocationCallOrder: [],
|
351 | results: []
|
352 | };
|
353 | }
|
354 |
|
355 | _makeComponent(metadata, restore) {
|
356 | if (metadata.type === 'object') {
|
357 | return new this._environmentGlobal.Object();
|
358 | } else if (metadata.type === 'array') {
|
359 | return new this._environmentGlobal.Array();
|
360 | } else if (metadata.type === 'regexp') {
|
361 | return new this._environmentGlobal.RegExp('');
|
362 | } else if (
|
363 | metadata.type === 'constant' ||
|
364 | metadata.type === 'collection' ||
|
365 | metadata.type === 'null' ||
|
366 | metadata.type === 'undefined'
|
367 | ) {
|
368 | return metadata.value;
|
369 | } else if (metadata.type === 'function') {
|
370 | const prototype =
|
371 | (metadata.members &&
|
372 | metadata.members.prototype &&
|
373 | metadata.members.prototype.members) ||
|
374 | {};
|
375 |
|
376 | const prototypeSlots = this._getSlots(prototype);
|
377 |
|
378 | const mocker = this;
|
379 | const mockConstructor = matchArity(function (...args) {
|
380 | const mockState = mocker._ensureMockState(f);
|
381 |
|
382 | const mockConfig = mocker._ensureMockConfig(f);
|
383 |
|
384 | mockState.instances.push(this);
|
385 | mockState.calls.push(args);
|
386 |
|
387 |
|
388 |
|
389 |
|
390 | const mockResult = {
|
391 | type: 'incomplete',
|
392 | value: undefined
|
393 | };
|
394 | mockState.results.push(mockResult);
|
395 | mockState.invocationCallOrder.push(mocker._invocationCallCounter++);
|
396 |
|
397 | let finalReturnValue;
|
398 |
|
399 | let thrownError;
|
400 |
|
401 |
|
402 |
|
403 | let callDidThrowError = false;
|
404 |
|
405 | try {
|
406 |
|
407 |
|
408 |
|
409 |
|
410 | finalReturnValue = (() => {
|
411 | if (this instanceof f) {
|
412 |
|
413 | prototypeSlots.forEach(slot => {
|
414 |
|
415 |
|
416 |
|
417 | if (prototype[slot].type === 'function') {
|
418 |
|
419 | const protoImpl = this[slot];
|
420 |
|
421 | this[slot] = mocker.generateFromMetadata(prototype[slot]);
|
422 |
|
423 | this[slot]._protoImpl = protoImpl;
|
424 | }
|
425 | });
|
426 |
|
427 | const mockImpl = mockConfig.specificMockImpls.length
|
428 | ? mockConfig.specificMockImpls.shift()
|
429 | : mockConfig.mockImpl;
|
430 | return mockImpl && mockImpl.apply(this, arguments);
|
431 | }
|
432 |
|
433 |
|
434 | let specificMockImpl = mockConfig.specificMockImpls.shift();
|
435 |
|
436 | if (specificMockImpl === undefined) {
|
437 | specificMockImpl = mockConfig.mockImpl;
|
438 | }
|
439 |
|
440 | if (specificMockImpl) {
|
441 | return specificMockImpl.apply(this, arguments);
|
442 | }
|
443 |
|
444 | if (f._protoImpl) {
|
445 | return f._protoImpl.apply(this, arguments);
|
446 | }
|
447 |
|
448 | return undefined;
|
449 | })();
|
450 | } catch (error) {
|
451 |
|
452 | thrownError = error;
|
453 | callDidThrowError = true;
|
454 | throw error;
|
455 | } finally {
|
456 |
|
457 |
|
458 |
|
459 |
|
460 | mockResult.type = callDidThrowError ? 'throw' : 'return';
|
461 | mockResult.value = callDidThrowError ? thrownError : finalReturnValue;
|
462 | }
|
463 |
|
464 | return finalReturnValue;
|
465 | }, metadata.length || 0);
|
466 |
|
467 | const f = this._createMockFunction(metadata, mockConstructor);
|
468 |
|
469 | f._isMockFunction = true;
|
470 |
|
471 | f.getMockImplementation = () => this._ensureMockConfig(f).mockImpl;
|
472 |
|
473 | if (typeof restore === 'function') {
|
474 | this._spyState.add(restore);
|
475 | }
|
476 |
|
477 | this._mockState.set(f, this._defaultMockState());
|
478 |
|
479 | this._mockConfigRegistry.set(f, this._defaultMockConfig());
|
480 |
|
481 | Object.defineProperty(f, 'mock', {
|
482 | configurable: false,
|
483 | enumerable: true,
|
484 | get: () => this._ensureMockState(f),
|
485 | set: val => this._mockState.set(f, val)
|
486 | });
|
487 |
|
488 | f.mockClear = () => {
|
489 | this._mockState.delete(f);
|
490 |
|
491 | return f;
|
492 | };
|
493 |
|
494 | f.mockReset = () => {
|
495 | f.mockClear();
|
496 |
|
497 | this._mockConfigRegistry.delete(f);
|
498 |
|
499 | return f;
|
500 | };
|
501 |
|
502 | f.mockRestore = () => {
|
503 | f.mockReset();
|
504 | return restore ? restore() : undefined;
|
505 | };
|
506 |
|
507 | f.mockReturnValueOnce = (
|
508 | value
|
509 | ) => f.mockImplementationOnce(() => value);
|
510 |
|
511 | f.mockResolvedValueOnce = value =>
|
512 | f.mockImplementationOnce(() => Promise.resolve(value));
|
513 |
|
514 | f.mockRejectedValueOnce = value =>
|
515 | f.mockImplementationOnce(() => Promise.reject(value));
|
516 |
|
517 | f.mockReturnValue = (
|
518 | value
|
519 | ) => f.mockImplementation(() => value);
|
520 |
|
521 | f.mockResolvedValue = value =>
|
522 | f.mockImplementation(() => Promise.resolve(value));
|
523 |
|
524 | f.mockRejectedValue = value =>
|
525 | f.mockImplementation(() => Promise.reject(value));
|
526 |
|
527 | f.mockImplementationOnce = fn => {
|
528 |
|
529 |
|
530 | const mockConfig = this._ensureMockConfig(f);
|
531 |
|
532 | mockConfig.specificMockImpls.push(fn);
|
533 | return f;
|
534 | };
|
535 |
|
536 | f.mockImplementation = fn => {
|
537 |
|
538 | const mockConfig = this._ensureMockConfig(f);
|
539 |
|
540 | mockConfig.mockImpl = fn;
|
541 | return f;
|
542 | };
|
543 |
|
544 | f.mockReturnThis = () =>
|
545 | f.mockImplementation(function () {
|
546 | return this;
|
547 | });
|
548 |
|
549 | f.mockName = name => {
|
550 | if (name) {
|
551 | const mockConfig = this._ensureMockConfig(f);
|
552 |
|
553 | mockConfig.mockName = name;
|
554 | }
|
555 |
|
556 | return f;
|
557 | };
|
558 |
|
559 | f.getMockName = () => {
|
560 | const mockConfig = this._ensureMockConfig(f);
|
561 |
|
562 | return mockConfig.mockName || 'jest.fn()';
|
563 | };
|
564 |
|
565 | if (metadata.mockImpl) {
|
566 | f.mockImplementation(metadata.mockImpl);
|
567 | }
|
568 |
|
569 | return f;
|
570 | } else {
|
571 | const unknownType = metadata.type || 'undefined type';
|
572 | throw new Error('Unrecognized type ' + unknownType);
|
573 | }
|
574 | }
|
575 |
|
576 | _createMockFunction(metadata, mockConstructor) {
|
577 | let name = metadata.name;
|
578 |
|
579 | if (!name) {
|
580 | return mockConstructor;
|
581 | }
|
582 |
|
583 | const boundFunctionPrefix = 'bound ';
|
584 | let bindCall = '';
|
585 |
|
586 | if (name && name.startsWith(boundFunctionPrefix)) {
|
587 | do {
|
588 | name = name.substring(boundFunctionPrefix.length);
|
589 |
|
590 | bindCall = '.bind(null)';
|
591 | } while (name && name.startsWith(boundFunctionPrefix));
|
592 | }
|
593 |
|
594 |
|
595 | if (name === MOCK_CONSTRUCTOR_NAME) {
|
596 | return mockConstructor;
|
597 | }
|
598 |
|
599 | if (
|
600 |
|
601 |
|
602 | RESERVED_KEYWORDS.has(name) ||
|
603 | /^\d/.test(name)
|
604 | ) {
|
605 | name = '$' + name;
|
606 | }
|
607 |
|
608 |
|
609 | if (FUNCTION_NAME_RESERVED_PATTERN.test(name)) {
|
610 | name = name.replace(FUNCTION_NAME_RESERVED_REPLACE, '$');
|
611 | }
|
612 |
|
613 | const body =
|
614 | 'return function ' +
|
615 | name +
|
616 | '() {' +
|
617 | 'return ' +
|
618 | MOCK_CONSTRUCTOR_NAME +
|
619 | '.apply(this,arguments);' +
|
620 | '}' +
|
621 | bindCall;
|
622 | const createConstructor = new this._environmentGlobal.Function(
|
623 | MOCK_CONSTRUCTOR_NAME,
|
624 | body
|
625 | );
|
626 | return createConstructor(mockConstructor);
|
627 | }
|
628 |
|
629 | _generateMock(metadata, callbacks, refs) {
|
630 |
|
631 |
|
632 |
|
633 | const mock = this._makeComponent(metadata);
|
634 |
|
635 | if (metadata.refID != null) {
|
636 | refs[metadata.refID] = mock;
|
637 | }
|
638 |
|
639 | this._getSlots(metadata.members).forEach(slot => {
|
640 | const slotMetadata = (metadata.members && metadata.members[slot]) || {};
|
641 |
|
642 | if (slotMetadata.ref != null) {
|
643 | callbacks.push(
|
644 | (function (ref) {
|
645 | return () => (mock[slot] = refs[ref]);
|
646 | })(slotMetadata.ref)
|
647 | );
|
648 | } else {
|
649 | mock[slot] = this._generateMock(slotMetadata, callbacks, refs);
|
650 | }
|
651 | });
|
652 |
|
653 | if (
|
654 | metadata.type !== 'undefined' &&
|
655 | metadata.type !== 'null' &&
|
656 | mock.prototype &&
|
657 | typeof mock.prototype === 'object'
|
658 | ) {
|
659 | mock.prototype.constructor = mock;
|
660 | }
|
661 |
|
662 | return mock;
|
663 | }
|
664 | |
665 |
|
666 |
|
667 |
|
668 |
|
669 |
|
670 | generateFromMetadata(_metadata) {
|
671 | const callbacks = [];
|
672 | const refs = {};
|
673 |
|
674 | const mock = this._generateMock(_metadata, callbacks, refs);
|
675 |
|
676 | callbacks.forEach(setter => setter());
|
677 | return mock;
|
678 | }
|
679 | |
680 |
|
681 |
|
682 |
|
683 |
|
684 | getMetadata(component, _refs) {
|
685 | const refs = _refs || new Map();
|
686 | const ref = refs.get(component);
|
687 |
|
688 | if (ref != null) {
|
689 | return {
|
690 | ref
|
691 | };
|
692 | }
|
693 |
|
694 | const type = getType(component);
|
695 |
|
696 | if (!type) {
|
697 | return null;
|
698 | }
|
699 |
|
700 | const metadata = {
|
701 | type
|
702 | };
|
703 |
|
704 | if (
|
705 | type === 'constant' ||
|
706 | type === 'collection' ||
|
707 | type === 'undefined' ||
|
708 | type === 'null'
|
709 | ) {
|
710 | metadata.value = component;
|
711 | return metadata;
|
712 | } else if (type === 'function') {
|
713 |
|
714 | metadata.name = component.name;
|
715 |
|
716 | if (component._isMockFunction === true) {
|
717 |
|
718 | metadata.mockImpl = component.getMockImplementation();
|
719 | }
|
720 | }
|
721 |
|
722 | metadata.refID = refs.size;
|
723 | refs.set(component, metadata.refID);
|
724 | let members = null;
|
725 |
|
726 | if (type !== 'array') {
|
727 | this._getSlots(component).forEach(slot => {
|
728 | if (
|
729 | type === 'function' &&
|
730 | component._isMockFunction === true &&
|
731 | slot.match(/^mock/)
|
732 | ) {
|
733 | return;
|
734 | }
|
735 |
|
736 | const slotMetadata = this.getMetadata(component[slot], refs);
|
737 |
|
738 | if (slotMetadata) {
|
739 | if (!members) {
|
740 | members = {};
|
741 | }
|
742 |
|
743 | members[slot] = slotMetadata;
|
744 | }
|
745 | });
|
746 | }
|
747 |
|
748 | if (members) {
|
749 | metadata.members = members;
|
750 | }
|
751 |
|
752 | return metadata;
|
753 | }
|
754 |
|
755 | isMockFunction(fn) {
|
756 | return !!fn && fn._isMockFunction === true;
|
757 | }
|
758 |
|
759 | fn(implementation) {
|
760 | const length = implementation ? implementation.length : 0;
|
761 |
|
762 | const fn = this._makeComponent({
|
763 | length,
|
764 | type: 'function'
|
765 | });
|
766 |
|
767 | if (implementation) {
|
768 | fn.mockImplementation(implementation);
|
769 | }
|
770 |
|
771 | return fn;
|
772 | }
|
773 |
|
774 | spyOn(object, methodName, accessType) {
|
775 | if (accessType) {
|
776 | return this._spyOnProperty(object, methodName, accessType);
|
777 | }
|
778 |
|
779 | if (typeof object !== 'object' && typeof object !== 'function') {
|
780 | throw new Error(
|
781 | 'Cannot spyOn on a primitive value; ' + this._typeOf(object) + ' given'
|
782 | );
|
783 | }
|
784 |
|
785 | const original = object[methodName];
|
786 |
|
787 | if (!this.isMockFunction(original)) {
|
788 | if (typeof original !== 'function') {
|
789 | throw new Error(
|
790 | 'Cannot spy the ' +
|
791 | methodName +
|
792 | ' property because it is not a function; ' +
|
793 | this._typeOf(original) +
|
794 | ' given instead'
|
795 | );
|
796 | }
|
797 |
|
798 | const isMethodOwner = object.hasOwnProperty(methodName);
|
799 |
|
800 | object[methodName] = this._makeComponent(
|
801 | {
|
802 | type: 'function'
|
803 | },
|
804 | () => {
|
805 | if (isMethodOwner) {
|
806 | object[methodName] = original;
|
807 | } else {
|
808 | delete object[methodName];
|
809 | }
|
810 | }
|
811 | );
|
812 |
|
813 | object[methodName].mockImplementation(function () {
|
814 | return original.apply(this, arguments);
|
815 | });
|
816 | }
|
817 |
|
818 | return object[methodName];
|
819 | }
|
820 |
|
821 | _spyOnProperty(obj, propertyName, accessType = 'get') {
|
822 | if (typeof obj !== 'object' && typeof obj !== 'function') {
|
823 | throw new Error(
|
824 | 'Cannot spyOn on a primitive value; ' + this._typeOf(obj) + ' given'
|
825 | );
|
826 | }
|
827 |
|
828 | if (!obj) {
|
829 | throw new Error(
|
830 | 'spyOn could not find an object to spy upon for ' + propertyName + ''
|
831 | );
|
832 | }
|
833 |
|
834 | if (!propertyName) {
|
835 | throw new Error('No property name supplied');
|
836 | }
|
837 |
|
838 | let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
|
839 | let proto = Object.getPrototypeOf(obj);
|
840 |
|
841 | while (!descriptor && proto !== null) {
|
842 | descriptor = Object.getOwnPropertyDescriptor(proto, propertyName);
|
843 | proto = Object.getPrototypeOf(proto);
|
844 | }
|
845 |
|
846 | if (!descriptor) {
|
847 | throw new Error(propertyName + ' property does not exist');
|
848 | }
|
849 |
|
850 | if (!descriptor.configurable) {
|
851 | throw new Error(propertyName + ' is not declared configurable');
|
852 | }
|
853 |
|
854 | if (!descriptor[accessType]) {
|
855 | throw new Error(
|
856 | 'Property ' + propertyName + ' does not have access type ' + accessType
|
857 | );
|
858 | }
|
859 |
|
860 | const original = descriptor[accessType];
|
861 |
|
862 | if (!this.isMockFunction(original)) {
|
863 | if (typeof original !== 'function') {
|
864 | throw new Error(
|
865 | 'Cannot spy the ' +
|
866 | propertyName +
|
867 | ' property because it is not a function; ' +
|
868 | this._typeOf(original) +
|
869 | ' given instead'
|
870 | );
|
871 | }
|
872 |
|
873 | descriptor[accessType] = this._makeComponent(
|
874 | {
|
875 | type: 'function'
|
876 | },
|
877 | () => {
|
878 |
|
879 | descriptor[accessType] = original;
|
880 | Object.defineProperty(obj, propertyName, descriptor);
|
881 | }
|
882 | );
|
883 | descriptor[accessType].mockImplementation(function () {
|
884 |
|
885 | return original.apply(this, arguments);
|
886 | });
|
887 | }
|
888 |
|
889 | Object.defineProperty(obj, propertyName, descriptor);
|
890 | return descriptor[accessType];
|
891 | }
|
892 |
|
893 | clearAllMocks() {
|
894 | this._mockState = new WeakMap();
|
895 | }
|
896 |
|
897 | resetAllMocks() {
|
898 | this._mockConfigRegistry = new WeakMap();
|
899 | this._mockState = new WeakMap();
|
900 | }
|
901 |
|
902 | restoreAllMocks() {
|
903 | this._spyState.forEach(restore => restore());
|
904 |
|
905 | this._spyState = new Set();
|
906 | }
|
907 |
|
908 | _typeOf(value) {
|
909 | return value == null ? '' + value : typeof value;
|
910 | }
|
911 | }
|
912 |
|
913 |
|
914 | const JestMock = new ModuleMockerClass(global);
|
915 | module.exports = JestMock;
|