From 780dc0504b84cf8a1c67aa3889fef8e80962c22c Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Sat, 15 Oct 2022 00:10:44 +0100 Subject: [PATCH] bug-13140-001 Re-added spyOn support for function exports exposed using getters --- packages/jest-mock/src/index.ts | 82 ++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 408690efaaab..f4c9b5776034 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -1193,72 +1193,78 @@ export class ModuleMocker { ${this._typeOf(descriptor?.[accessType])} given instead`, ); } - } else if (typeof descriptor.value !== 'function') { + } else if ( + (descriptor.value && typeof descriptor.value !== 'function') || + (descriptor.get && typeof descriptor.get !== 'function') + ) { throw new Error( `Cannot spy the ${String( methodKey, )} property because it is not a function; ${this._typeOf( - descriptor.value, + descriptor.value ? descriptor.value : descriptor.get, )} given instead`, ); } + const isMethodOwner = Object.prototype.hasOwnProperty.call( + object, + methodKey, + ); let mock: Mock; - if (accessType == 'get' && descriptor['get']) { - const originalAccessor = descriptor['get']; - mock = this._makeComponent( - { - type: 'function', - }, - () => { - descriptor![accessType] = originalAccessor; + if (accessType == 'get' && descriptor.get) { + const originalAccessor = descriptor.get; + mock = this._makeComponent({type: 'function'}, () => { + if (isMethodOwner) { + descriptor!.get = originalAccessor; Object.defineProperty(object, methodKey, descriptor!); - }, - ); + } else { + delete object[methodKey]; + } + }); - descriptor[accessType] = mock; + descriptor.get = mock; mock.mockImplementation(function (this: unknown) { return originalAccessor.call(this); }); Object.defineProperty(object, methodKey, descriptor); - } else if (accessType == 'set' && descriptor['set']) { - const originalAccessor = descriptor['set']; - mock = this._makeComponent( - { - type: 'function', - }, - () => { - descriptor![accessType] = originalAccessor; + } else if (accessType == 'set' && descriptor.set) { + const originalAccessor = descriptor.set; + mock = this._makeComponent({type: 'function'}, () => { + if (isMethodOwner) { + descriptor!.set = originalAccessor; Object.defineProperty(object, methodKey, descriptor!); - }, - ); + } else { + delete object[methodKey]; + } + }); - descriptor[accessType] = mock; + descriptor.set = mock; mock.mockImplementation(function (this: unknown) { return originalAccessor.call(this, arguments[0]); }); Object.defineProperty(object, methodKey, descriptor); + } else if (descriptor.get) { + const originalGet = descriptor.get; + mock = this._makeComponent({type: 'function'}, () => { + descriptor!.get = originalGet; + Object.defineProperty(object, methodKey, descriptor!); + }); + descriptor.get = () => mock; + Object.defineProperty(object, methodKey, descriptor); } else { const isMethodOwner = Object.prototype.hasOwnProperty.call( object, methodKey, ); const original = descriptor; - - mock = this._makeComponent( - { - type: 'function', - }, - () => { - if (isMethodOwner) { - object[methodKey] = original.value; - } else { - delete object[methodKey]; - } - }, - ); - + mock = this._makeComponent({type: 'function'}, () => { + if (isMethodOwner) { + object[methodKey] = original.value; + } else { + delete object[methodKey]; + } + }); // @ts-expect-error overriding original method with a Mock object[methodKey] = mock; mock.mockImplementation(function (this: unknown) {