From bf4d2d6013eebf0b02b9ec3cac57c3641bb02071 Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Tue, 16 Aug 2022 17:41:29 +0100 Subject: [PATCH 01/10] bug-13140 Added tests for class mocks --- .../jest-mock/src/__tests__/SuperTestClass.ts | 28 +++ packages/jest-mock/src/__tests__/TestClass.ts | 3 + .../__tests__/class-mocks-dual-import.test.ts | 122 +++++++++++++ .../class-mocks-single-import.test.ts | 120 +++++++++++++ .../src/__tests__/class-mocks-types.ts | 30 ++++ .../src/__tests__/class-mocks.test.ts | 163 ++++++++++++++++++ 6 files changed, 466 insertions(+) create mode 100644 packages/jest-mock/src/__tests__/SuperTestClass.ts create mode 100644 packages/jest-mock/src/__tests__/TestClass.ts create mode 100644 packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts create mode 100644 packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts create mode 100644 packages/jest-mock/src/__tests__/class-mocks-types.ts create mode 100644 packages/jest-mock/src/__tests__/class-mocks.test.ts diff --git a/packages/jest-mock/src/__tests__/SuperTestClass.ts b/packages/jest-mock/src/__tests__/SuperTestClass.ts new file mode 100644 index 000000000000..2ea722af2f3a --- /dev/null +++ b/packages/jest-mock/src/__tests__/SuperTestClass.ts @@ -0,0 +1,28 @@ +export class SuperTestClass { + static staticTestProperty = 'staticTestProperty'; + + static get staticTestAccessor(): string { + return 'staticTestAccessor'; + } + + static set staticTestAccessor(_x: string) { + return; + } + + static staticTestMethod(): string { + return 'staticTestMethod'; + } + + testProperty = 'testProperty'; + + get testAccessor(): string { + return 'testAccessor'; + } + set testAccessor(_x: string) { + return; + } + + testMethod(): string { + return 'testMethod'; + } +} diff --git a/packages/jest-mock/src/__tests__/TestClass.ts b/packages/jest-mock/src/__tests__/TestClass.ts new file mode 100644 index 000000000000..59b17d7810f6 --- /dev/null +++ b/packages/jest-mock/src/__tests__/TestClass.ts @@ -0,0 +1,3 @@ +import {SuperTestClass} from './SuperTestClass'; + +export default class TestClass extends SuperTestClass {} diff --git a/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts b/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts new file mode 100644 index 000000000000..f017806fce07 --- /dev/null +++ b/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts @@ -0,0 +1,122 @@ +import {SuperTestClass} from './SuperTestClass'; +import TestClass from './TestClass'; +jest.mock('./SuperTestClass'); +jest.mock('./TestClass'); + +describe('Testing the mocking of a class hierarchy defined in multiple imports', () => { + it('can call an instance method - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testMethod') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new SuperTestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can call a superclass instance method - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testMethod') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can read a value from an instance getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testAccessor', 'get') + .mockImplementation(() => { + return 'mockTestAccessor'; + }); + const testClassInstance = new SuperTestClass(); + expect(testClassInstance.testAccessor).toEqual('mockTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can read a value from a superclass instance getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testAccessor', 'get') + .mockImplementation(() => { + return 'mockTestAccessor'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testAccessor).toEqual('mockTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to an instance setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new SuperTestClass(); + testClassInstance.testAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can write a value to a superclass instance setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new TestClass(); + testClassInstance.testAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can read a value from a static getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass, 'staticTestAccessor', 'get') + .mockImplementation(() => { + return 'mockStaticTestAccessor'; + }); + expect(SuperTestClass.staticTestAccessor).toEqual('mockStaticTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can read a value from a superclass static getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass, 'staticTestAccessor', 'get') + .mockImplementation(() => { + return 'mockStaticTestAccessor'; + }); + expect(TestClass.staticTestAccessor).toEqual('mockStaticTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to a static setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass, 'staticTestAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + SuperTestClass.staticTestAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can write a value to a superclass static setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass, 'staticTestAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + TestClass.staticTestAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts b/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts new file mode 100644 index 000000000000..b99054d8734b --- /dev/null +++ b/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts @@ -0,0 +1,120 @@ +import SuperTestClass, {TestClass} from './class-mocks-types'; +jest.mock('./class-mocks-types'); + +describe('Testing the mocking of a class hierarchy defined in a single import', () => { + it('can call an instance method - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testMethod') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new SuperTestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can call a superclass instance method - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testMethod') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can read a value from an instance getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testAccessor', 'get') + .mockImplementation(() => { + return 'mockTestAccessor'; + }); + const testClassInstance = new SuperTestClass(); + expect(testClassInstance.testAccessor).toEqual('mockTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can read a value from a superclass instance getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testAccessor', 'get') + .mockImplementation(() => { + return 'mockTestAccessor'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testAccessor).toEqual('mockTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to an instance setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass.prototype, 'testAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new SuperTestClass(); + testClassInstance.testAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can write a value to a superclass instance setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass.prototype, 'testAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new TestClass(); + testClassInstance.testAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can read a value from a static getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass, 'staticTestAccessor', 'get') + .mockImplementation(() => { + return 'mockStaticTestAccessor'; + }); + expect(SuperTestClass.staticTestAccessor).toEqual('mockStaticTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can read a value from a superclass static getter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass, 'staticTestAccessor', 'get') + .mockImplementation(() => { + return 'mockStaticTestAccessor'; + }); + expect(TestClass.staticTestAccessor).toEqual('mockStaticTestAccessor'); + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to a static setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(SuperTestClass, 'staticTestAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + SuperTestClass.staticTestAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + + mockTestMethod.mockClear(); + }); + + it('can write a value to a superclass static setter - Auto-mocked class', () => { + const mockTestMethod = jest + .spyOn(TestClass, 'staticTestAccessor', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + TestClass.staticTestAccessor = ''; + expect(mockTestMethod).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/jest-mock/src/__tests__/class-mocks-types.ts b/packages/jest-mock/src/__tests__/class-mocks-types.ts new file mode 100644 index 000000000000..e39e582e9ad1 --- /dev/null +++ b/packages/jest-mock/src/__tests__/class-mocks-types.ts @@ -0,0 +1,30 @@ +export default class SuperTestClass { + static staticTestProperty = 'staticTestProperty'; + + static get staticTestAccessor(): string { + return 'staticTestAccessor'; + } + + static set staticTestAccessor(_x: string) { + return; + } + + static staticTestMethod(): string { + return 'staticTestMethod'; + } + + testProperty = 'testProperty'; + + get testAccessor(): string { + return 'testAccessor'; + } + set testAccessor(_x: string) { + return; + } + + testMethod(): string { + return 'testMethod'; + } +} + +export class TestClass extends SuperTestClass {} diff --git a/packages/jest-mock/src/__tests__/class-mocks.test.ts b/packages/jest-mock/src/__tests__/class-mocks.test.ts new file mode 100644 index 000000000000..e8ddd312aaf9 --- /dev/null +++ b/packages/jest-mock/src/__tests__/class-mocks.test.ts @@ -0,0 +1,163 @@ +describe('Testing the mocking of a class', () => { + it('can call an instance method', () => { + class TestClass { + testMethod(): string { + return 'testMethod'; + } + } + + jest.spyOn(TestClass.prototype, 'testMethod').mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + }); + + it('can call a superclass instance method', () => { + class SuperTestClass { + testMethod(): string { + return 'testMethod'; + } + } + + class TestClass extends SuperTestClass {} + + jest.spyOn(TestClass.prototype, 'testMethod').mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod()).toEqual('mockTestMethod'); + }); + + it('can read a value from an instance getter', () => { + class TestClass { + get testMethod(): string { + return 'testMethod'; + } + } + + jest + .spyOn(TestClass.prototype, 'testMethod', 'get') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod).toEqual('mockTestMethod'); + }); + + it('can read a value from an superclass instance getter', () => { + class SuperTestClass { + get testMethod(): string { + return 'testMethod'; + } + } + + class TestClass extends SuperTestClass {} + + jest + .spyOn(TestClass.prototype, 'testMethod', 'get') + .mockImplementation(() => { + return 'mockTestMethod'; + }); + const testClassInstance = new TestClass(); + expect(testClassInstance.testMethod).toEqual('mockTestMethod'); + }); + + it('can write a value to an instance setter', () => { + class TestClass { + set testMethod(_x: string) { + return; + } + } + + const mocktestMethod = jest + .spyOn(TestClass.prototype, 'testMethod', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new TestClass(); + testClassInstance.testMethod = ''; + expect(mocktestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to a superclass instance setter', () => { + class SuperTestClass { + set testMethod(_x: string) { + return; + } + } + + class TestClass extends SuperTestClass {} + + const mocktestMethod = jest + .spyOn(TestClass.prototype, 'testMethod', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + const testClassInstance = new TestClass(); + testClassInstance.testMethod = ''; + expect(mocktestMethod).toHaveBeenCalledTimes(1); + }); + + it('can read a value from a static getter', () => { + class TestClass { + static get testMethod(): string { + return 'testMethod'; + } + } + + jest.spyOn(TestClass, 'testMethod', 'get').mockImplementation(() => { + return 'mockTestMethod'; + }); + expect(TestClass.testMethod).toEqual('mockTestMethod'); + }); + + it('can read a value from a superclass static getter', () => { + class SuperTestClass { + static get testMethod(): string { + return 'testMethod'; + } + } + + class TestClass extends SuperTestClass {} + + jest.spyOn(TestClass, 'testMethod', 'get').mockImplementation(() => { + return 'mockTestMethod'; + }); + expect(TestClass.testMethod).toEqual('mockTestMethod'); + }); + + it('can write a value to a static setter', () => { + class TestClass { + static set testMethod(_x: string) { + return; + } + } + + const mocktestMethod = jest + .spyOn(TestClass, 'testMethod', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + TestClass.testMethod = ''; + expect(mocktestMethod).toHaveBeenCalledTimes(1); + }); + + it('can write a value to a superclass static setter', () => { + class SuperTestClass { + static set testMethod(_x: string) { + return; + } + } + + class TestClass extends SuperTestClass {} + + const mocktestMethod = jest + .spyOn(TestClass, 'testMethod', 'set') + .mockImplementation((_x: string) => { + return () => {}; + }); + TestClass.testMethod = ''; + expect(mocktestMethod).toHaveBeenCalledTimes(1); + }); +}); From ee81c2598b690849d3c6f2a4c840234f54079e2d Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Tue, 16 Aug 2022 18:02:57 +0100 Subject: [PATCH 02/10] bug-13140 Implemented mocking of getter/setter methods --- packages/jest-mock/src/index.ts | 246 +++++++++++++++++--------------- 1 file changed, 131 insertions(+), 115 deletions(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 305699b0a50c..fb155c349451 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -506,7 +506,7 @@ export class ModuleMocker { if (!isReadonlyProp(object, prop)) { const propDesc = Object.getOwnPropertyDescriptor(object, prop); - if ((propDesc !== undefined && !propDesc.get) || object.__esModule) { + if (propDesc !== undefined || object.__esModule) { slots.add(prop); } } @@ -884,7 +884,9 @@ export class ModuleMocker { } this._getSlots(metadata.members).forEach(slot => { + let slotMock: Mock; const slotMetadata = (metadata.members && metadata.members[slot]) || {}; + if (slotMetadata.ref != null) { callbacks.push( (function (ref) { @@ -892,7 +894,24 @@ export class ModuleMocker { })(slotMetadata.ref), ); } else { - mock[slot] = this._generateMock(slotMetadata, callbacks, refs); + slotMock = this._generateMock(slotMetadata, callbacks, refs); + + //missing getter and setter refs will be resolved as their callbacks have been + //stacked before the setting of the accessor definition is stacked. + if ( + slotMetadata.members?.get?.ref !== undefined || + slotMetadata.members?.set?.ref !== undefined + ) { + callbacks.push( + (function (ref) { + return () => Object.defineProperty(mock, slot, ref); + })(slotMock), + ); + } else if (slotMetadata.members?.get || slotMetadata.members?.set) { + Object.defineProperty(mock, slot, slotMock); + } else { + mock[slot] = slotMock; + } } }); @@ -980,8 +999,23 @@ export class ModuleMocker { ) { return; } - // @ts-expect-error no index signature - const slotMetadata = this.getMetadata(component[slot], refs); + + let descriptor = Object.getOwnPropertyDescriptor(component, slot); + let proto = Object.getPrototypeOf(component); + while (!descriptor && proto !== null) { + descriptor = Object.getOwnPropertyDescriptor(proto, slot); + proto = Object.getPrototypeOf(proto); + } + + let slotMetadata: MockFunctionMetadata | null = null; + if (descriptor?.get || descriptor?.set) { + // @ts-expect-error ignore type mismatch + slotMetadata = this.getMetadata(descriptor, refs); + } else { + // @ts-expect-error no index signature + slotMetadata = this.getMetadata(component[slot], refs); + } + if (slotMetadata) { if (!members) { members = {}; @@ -1054,148 +1088,130 @@ export class ModuleMocker { methodName: M, accessType?: 'get' | 'set', ) { - if (accessType) { - return this._spyOnProperty(object, methodName, accessType); - } - - if (typeof object !== 'object' && typeof object !== 'function') { + if (!object) { throw new Error( - `Cannot spyOn on a primitive value; ${this._typeOf(object)} given`, + `spyOn could not find an object to spy upon for ${String(methodName)}`, ); } - const original = object[methodName]; - - if (!this.isMockFunction(original)) { - if (typeof original !== 'function') { - throw new Error( - `Cannot spy the ${String( - methodName, - )} property because it is not a function; ${this._typeOf( - original, - )} given instead`, - ); - } - - const isMethodOwner = Object.prototype.hasOwnProperty.call( - object, - methodName, - ); - - let descriptor = Object.getOwnPropertyDescriptor(object, methodName); - let proto = Object.getPrototypeOf(object); - - while (!descriptor && proto !== null) { - descriptor = Object.getOwnPropertyDescriptor(proto, methodName); - proto = Object.getPrototypeOf(proto); - } - - let mock: Mock; - - if (descriptor && descriptor.get) { - const originalGet = descriptor.get; - mock = this._makeComponent({type: 'function'}, () => { - descriptor!.get = originalGet; - Object.defineProperty(object, methodName, descriptor!); - }); - descriptor.get = () => mock; - Object.defineProperty(object, methodName, descriptor); - } else { - mock = this._makeComponent({type: 'function'}, () => { - if (isMethodOwner) { - object[methodName] = original; - } else { - delete object[methodName]; - } - }); - // @ts-expect-error overriding original method with a Mock - object[methodName] = mock; - } - - mock.mockImplementation(function (this: unknown) { - return original.apply(this, arguments); - }); + if (!methodName) { + throw new Error('No property name supplied'); } - return object[methodName]; - } - - private _spyOnProperty>( - obj: T, - propertyName: M, - accessType: 'get' | 'set' = 'get', - ): Mock<() => T> { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new Error( - `Cannot spyOn on a primitive value; ${this._typeOf(obj)} given`, - ); + if (accessType && accessType != 'get' && accessType != 'set') { + throw new Error('Invalid accessType supplied'); } - if (!obj) { + if (typeof object !== 'object' && typeof object !== 'function') { throw new Error( - `spyOn could not find an object to spy upon for ${String( - propertyName, - )}`, + `Cannot spyOn on a primitive value; ${this._typeOf(object)} given`, ); } - if (!propertyName) { - throw new Error('No property name supplied'); - } - - let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName); - let proto = Object.getPrototypeOf(obj); - + let descriptor = Object.getOwnPropertyDescriptor(object, methodName); + let proto = Object.getPrototypeOf(object); while (!descriptor && proto !== null) { - descriptor = Object.getOwnPropertyDescriptor(proto, propertyName); + descriptor = Object.getOwnPropertyDescriptor(proto, methodName); proto = Object.getPrototypeOf(proto); } - if (!descriptor) { - throw new Error(`${String(propertyName)} property does not exist`); + throw new Error(`${String(methodName)} property does not exist`); } - if (!descriptor.configurable) { - throw new Error(`${String(propertyName)} is not declared configurable`); + throw new Error(`${String(methodName)} is not declared configurable`); } - if (!descriptor[accessType]) { - throw new Error( - `Property ${String( - propertyName, - )} does not have access type ${accessType}`, - ); + if (this.isMockFunction(descriptor.value)) { + return object[methodName]; + } else if (accessType == 'get' && this.isMockFunction(descriptor.get)) { + return descriptor.get; + } else if (accessType == 'set' && this.isMockFunction(descriptor.set)) { + return descriptor.set; } - const original = descriptor[accessType]; - - if (!this.isMockFunction(original)) { - if (typeof original !== 'function') { + if (accessType) { + if (typeof descriptor[accessType] !== 'function') { throw new Error( - `Cannot spy the ${String( - propertyName, - )} property because it is not a function; ${this._typeOf( - original, - )} given instead`, + `Cannot spy the ${String(accessType)} ${String( + methodName, + )} property because it is not a function; + ${this._typeOf(descriptor?.[accessType])} given instead`, ); } + } else if (typeof descriptor.value !== 'function') { + throw new Error( + `Cannot spy the ${String( + methodName, + )} property because it is not a function; ${this._typeOf( + descriptor.value, + )} given instead`, + ); + } + + let mock: Mock; + + if (accessType == 'get' && descriptor['get']) { + const originalAccessor = descriptor['get']; + mock = this._makeComponent( + { + type: 'function', + }, + () => { + descriptor![accessType] = originalAccessor; + Object.defineProperty(object, methodName, descriptor!); + }, + ); - descriptor[accessType] = this._makeComponent({type: 'function'}, () => { - // @ts-expect-error: mock is assignable - descriptor![accessType] = original; - Object.defineProperty(obj, propertyName, descriptor!); + descriptor[accessType] = mock; + mock.mockImplementation(function (this: unknown) { + return originalAccessor.apply(this, []); }); + Object.defineProperty(object, methodName, descriptor); + } else if (accessType == 'set' && descriptor['set']) { + const originalAccessor = descriptor['set']; + mock = this._makeComponent( + { + type: 'function', + }, + () => { + descriptor![accessType] = originalAccessor; + Object.defineProperty(object, methodName, descriptor!); + }, + ); - (descriptor[accessType] as Mock<() => T>).mockImplementation(function ( - this: unknown, - ) { - // @ts-expect-error - wrong context - return original.apply(this, arguments); + descriptor[accessType] = mock; + mock.mockImplementation(function (this: unknown) { + return originalAccessor.apply(this, arguments[0]); + }); + Object.defineProperty(object, methodName, descriptor); + } else { + const isMethodOwner = Object.prototype.hasOwnProperty.call( + object, + methodName, + ); + const original = descriptor; + + mock = this._makeComponent( + { + type: 'function', + }, + () => { + if (isMethodOwner) { + object[methodName] = original.value; + } else { + delete object[methodName]; + } + }, + ); + + // @ts-expect-error overriding original method with a Mock + object[methodName] = mock; + mock.mockImplementation(function (this: unknown) { + return original.value.apply(this, arguments); }); } - Object.defineProperty(obj, propertyName, descriptor); - return descriptor[accessType] as Mock<() => T>; + return mock; } clearAllMocks(): void { From 52bfb65de3db540062d49dd8eb09cdc4ed7e1bb1 Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Wed, 17 Aug 2022 17:26:05 +0100 Subject: [PATCH 03/10] bug-13140 Made existing tests pass --- jest.config.mjs | 3 ++ .../src/__tests__/class-mocks.test.ts | 4 ++ .../jest-mock/src/__tests__/index.test.ts | 7 ++- packages/jest-mock/src/index.ts | 54 ++++++++++++++++--- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/jest.config.mjs b/jest.config.mjs index 192ccd07dcfa..5459b96db2b2 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -58,6 +58,9 @@ export default { '/packages/jest-haste-map/src/__tests__/haste_impl.js', '/packages/jest-haste-map/src/__tests__/dependencyExtractor.js', '/packages/jest-haste-map/src/__tests__/test_dotfiles_root/', + '/packages/jest-mock/src/__tests__/class-mocks-types.ts', + '/packages/jest-mock/src/__tests__/TestClass.ts', + '/packages/jest-mock/src/__tests__/SuperTestClass.ts', '/packages/jest-repl/src/__tests__/test_root', '/packages/jest-resolve-dependencies/src/__tests__/__fixtures__/', '/packages/jest-runtime/src/__tests__/defaultResolver.js', diff --git a/packages/jest-mock/src/__tests__/class-mocks.test.ts b/packages/jest-mock/src/__tests__/class-mocks.test.ts index e8ddd312aaf9..874e2940ec7a 100644 --- a/packages/jest-mock/src/__tests__/class-mocks.test.ts +++ b/packages/jest-mock/src/__tests__/class-mocks.test.ts @@ -65,6 +65,7 @@ describe('Testing the mocking of a class', () => { it('can write a value to an instance setter', () => { class TestClass { + // eslint-disable-next-line accessor-pairs set testMethod(_x: string) { return; } @@ -82,6 +83,7 @@ describe('Testing the mocking of a class', () => { it('can write a value to a superclass instance setter', () => { class SuperTestClass { + // eslint-disable-next-line accessor-pairs set testMethod(_x: string) { return; } @@ -129,6 +131,7 @@ describe('Testing the mocking of a class', () => { it('can write a value to a static setter', () => { class TestClass { + // eslint-disable-next-line accessor-pairs static set testMethod(_x: string) { return; } @@ -145,6 +148,7 @@ describe('Testing the mocking of a class', () => { it('can write a value to a superclass static setter', () => { class SuperTestClass { + // eslint-disable-next-line accessor-pairs static set testMethod(_x: string) { return; } diff --git a/packages/jest-mock/src/__tests__/index.test.ts b/packages/jest-mock/src/__tests__/index.test.ts index 6b9f716d7ef0..595e0a1a5ca3 100644 --- a/packages/jest-mock/src/__tests__/index.test.ts +++ b/packages/jest-mock/src/__tests__/index.test.ts @@ -192,6 +192,11 @@ describe('moduleMocker', () => { expect(mock.nonEnumGetter).toBeUndefined(); }); + //This test was never valid. ModuleMocker mocked the read value of the getter + //i.e. the returned class on an ES module getter. + //So this test only verified that SOMETHING (10) was assigned to the enumGetter property. + //Exclusion case has been added to the ModuleMocker to ensure that ES modules + //are still mocked, whilst accessor properties are too. it('mocks getters of ES modules', () => { const foo = Object.defineProperties( {}, @@ -1263,7 +1268,7 @@ describe('moduleMocker', () => { }, }; - const spy = moduleMocker.spyOn(obj, 'method'); + const spy = moduleMocker.spyOn(obj, 'method', 'get'); const thisArg = {this: true}; const firstArg = {first: true}; diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index fb155c349451..8ef19a51af0f 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -506,7 +506,26 @@ export class ModuleMocker { if (!isReadonlyProp(object, prop)) { const propDesc = Object.getOwnPropertyDescriptor(object, prop); - if (propDesc !== undefined || object.__esModule) { + //In test packages/jest-runtime/src/__tests__/runtime_require_mock.test.js -> it('multiple node core modules returns correct module') + //when the component.name == 'propertyIsEnumerable' (object.name at start of _getSlots()) + //when retrieving metadata, the match for object !== ObjectProto fails. + //This causes an error where an ancestor prototype getter method, + //and introduction of mocking getters, results in a getter object + //being assigned to the prototype property __proto__, + //which then breaks when later building the mock. Ignore getters for __proto__. + //Please note that the metadata structure for the objects in this test seems heavily polluted + //with unnecessary objects, as if the exclusion conditions for object types in _getSlots() + //is failing in multiple cases. + + //it seems the OR condition "object.__esModule" was added to allow + //getters returning imported class definitions to be included whilst + //other accessor properties with getters were ignored. + //Can the "object.__esModule" condition now be removed? + if ( + (propDesc !== undefined && + !(propDesc.get && prop == '__proto__')) || + object.__esModule + ) { slots.add(prop); } } @@ -896,7 +915,10 @@ export class ModuleMocker { } else { slotMock = this._generateMock(slotMetadata, callbacks, refs); - //missing getter and setter refs will be resolved as their callbacks have been + //For superclass accessor properties the subclass metadata contains the definitions + //for the getter and setter methods, and the superclass refs to them. + //The mock implementations are not available until the callbacks have been executed. + //Missing getter and setter refs will be resolved as their callbacks have been //stacked before the setting of the accessor definition is stacked. if ( slotMetadata.members?.get?.ref !== undefined || @@ -907,7 +929,16 @@ export class ModuleMocker { return () => Object.defineProperty(mock, slot, ref); })(slotMock), ); - } else if (slotMetadata.members?.get || slotMetadata.members?.set) { + //} else if (slotMetadata.members?.get || slotMetadata.members?.set) { + } else if ( + (slotMetadata.members?.get || slotMetadata.members?.set) && + slotMetadata.members?.configurable && + slotMetadata.members?.enumerable + ) { + //In the test examples/jquery/__tests__/fetch_current_user.test.js-> it('calls into $.ajax with the correct params') + //the Ajax metadata has a 'get' property, causing it to enter here and except. + //while trying to redefine the 'prototype' property. + //The accessor property metadata contains 'configurable' and 'enumberable' properties also Object.defineProperty(mock, slot, slotMock); } else { mock[slot] = slotMock; @@ -1009,8 +1040,19 @@ export class ModuleMocker { let slotMetadata: MockFunctionMetadata | null = null; if (descriptor?.get || descriptor?.set) { + //Specific case required for mocking class definitions imported via types. + //In this case the class definitions are stored in accessor properties. + //All getters were previously ignored except where the containing object had __esModule == true + //Now getters are mocked the class definitions must still be read. + //Example is packages/jest-core/src/__tests__/TestScheduler.test.js -> test('works with default value') // @ts-expect-error ignore type mismatch - slotMetadata = this.getMetadata(descriptor, refs); + if (component.__esModule) { + // @ts-expect-error no index signature + slotMetadata = this.getMetadata(component[slot], refs); + } else { + // @ts-expect-error ignore type mismatch + slotMetadata = this.getMetadata(descriptor, refs); + } } else { // @ts-expect-error no index signature slotMetadata = this.getMetadata(component[slot], refs); @@ -1164,7 +1206,7 @@ export class ModuleMocker { descriptor[accessType] = mock; mock.mockImplementation(function (this: unknown) { - return originalAccessor.apply(this, []); + return originalAccessor.call(this); }); Object.defineProperty(object, methodName, descriptor); } else if (accessType == 'set' && descriptor['set']) { @@ -1181,7 +1223,7 @@ export class ModuleMocker { descriptor[accessType] = mock; mock.mockImplementation(function (this: unknown) { - return originalAccessor.apply(this, arguments[0]); + return originalAccessor.call(this, arguments[0]); }); Object.defineProperty(object, methodName, descriptor); } else { From 9e7fe2012616b616e091d66f70b5a6e6c968c7ed Mon Sep 17 00:00:00 2001 From: staplespeter Date: Sat, 17 Sep 2022 00:26:35 +0100 Subject: [PATCH 04/10] Update packages/jest-mock/src/index.ts Co-authored-by: Tom Mrazauskas --- packages/jest-mock/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index a42b0f95c804..e60de0806763 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -1023,7 +1023,7 @@ export class ModuleMocker { proto = Object.getPrototypeOf(proto); } - let slotMetadata: MockFunctionMetadata | null = null; + let slotMetadata: MockMetadata | null = null; if (descriptor?.get || descriptor?.set) { //Specific case required for mocking class definitions imported via types. //In this case the class definitions are stored in accessor properties. From 38e6918cb78a0e5b9d4ce5869bf58f8ceb19733a Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Sat, 17 Sep 2022 00:41:45 +0100 Subject: [PATCH 05/10] Bug-13140 Changing types for Updating types for automocked class getters/setters --- packages/jest-mock/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index e60de0806763..982020644a80 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -893,7 +893,7 @@ export class ModuleMocker { } this._getSlots(metadata.members).forEach(slot => { - let slotMock: Mock; + let slotMock: Mocked; const slotMetadata = (metadata.members && metadata.members[slot]) || {}; if (slotMetadata.ref != null) { @@ -917,7 +917,7 @@ export class ModuleMocker { callbacks.push( (function (ref) { return () => Object.defineProperty(mock, slot, ref); - })(slotMock), + })(slotMock as PropertyDescriptor), ); } else if ( (slotMetadata.members?.get || slotMetadata.members?.set) && @@ -928,7 +928,7 @@ export class ModuleMocker { //the Ajax metadata has a 'get' property, causing it to enter here and except //while trying to redefine the 'prototype' property. //The accessor property metadata contains 'configurable' and 'enumberable' properties also - Object.defineProperty(mock, slot, slotMock); + Object.defineProperty(mock, slot, slotMock as PropertyDescriptor); } else { mock[slot] = slotMock; } From a5613b9df85e6f32ae1ab27e869ba6d4a76487d6 Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Tue, 20 Sep 2022 13:03:02 +0100 Subject: [PATCH 06/10] Bug-13140: Removing unnecessary comments. Removed unnecessary condition. --- .../jest-mock/src/__tests__/index.test.ts | 5 ---- packages/jest-mock/src/index.ts | 30 +++++-------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/packages/jest-mock/src/__tests__/index.test.ts b/packages/jest-mock/src/__tests__/index.test.ts index 595e0a1a5ca3..d18b9b27f8dd 100644 --- a/packages/jest-mock/src/__tests__/index.test.ts +++ b/packages/jest-mock/src/__tests__/index.test.ts @@ -192,11 +192,6 @@ describe('moduleMocker', () => { expect(mock.nonEnumGetter).toBeUndefined(); }); - //This test was never valid. ModuleMocker mocked the read value of the getter - //i.e. the returned class on an ES module getter. - //So this test only verified that SOMETHING (10) was assigned to the enumGetter property. - //Exclusion case has been added to the ModuleMocker to ensure that ES modules - //are still mocked, whilst accessor properties are too. it('mocks getters of ES modules', () => { const foo = Object.defineProperties( {}, diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 982020644a80..4b1d26fadbe0 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -512,25 +512,9 @@ export class ModuleMocker { if (!isReadonlyProp(object, prop)) { const propDesc = Object.getOwnPropertyDescriptor(object, prop); - //In test packages/jest-runtime/src/__tests__/runtime_require_mock.test.js -> it('multiple node core modules returns correct module') - //when the component.name == 'propertyIsEnumerable' (object.name at start of _getSlots()) - //when retrieving metadata, the match for object !== ObjectProto fails. - //This causes an error where an ancestor prototype getter method, - //and introduction of mocking getters, results in a getter object - //being assigned to the prototype property __proto__, - //which then breaks when later building the mock. Ignore getters for __proto__. - //Please note that the metadata structure for the objects in this test seems heavily polluted - //with unnecessary objects, as if the exclusion conditions for object types in _getSlots() - //is failing in multiple cases. - - //it seems the OR condition "object.__esModule" was added to allow - //getters returning imported class definitions to be included whilst - //other accessor properties with getters were ignored. - //Can the "object.__esModule" condition now be removed? if ( - (propDesc !== undefined && - !(propDesc.get && prop == '__proto__')) || - object.__esModule + propDesc !== undefined && + !(propDesc.get && prop == '__proto__') ) { slots.add(prop); } @@ -924,10 +908,12 @@ export class ModuleMocker { slotMetadata.members?.configurable && slotMetadata.members?.enumerable ) { - //In the test examples/jquery/__tests__/fetch_current_user.test.js-> it('calls into $.ajax with the correct params') - //the Ajax metadata has a 'get' property, causing it to enter here and except - //while trying to redefine the 'prototype' property. - //The accessor property metadata contains 'configurable' and 'enumberable' properties also + //In some cases, e.g. third-party APIs, a 'prototype' ancestor to be + //mocked has a function property called 'get'. In this circumstance + //the 'prototype' property cannot be redefined and doing so causes an + //exception. Checks have been added for the 'configurable' and + //'enumberable' properties present on true accessor property + //descriptors to prevent the attempt to replace the API. Object.defineProperty(mock, slot, slotMock as PropertyDescriptor); } else { mock[slot] = slotMock; From 7b7cc5b39bf7b6a2478900827bcf38f8776b2216 Mon Sep 17 00:00:00 2001 From: Peter Staples Date: Tue, 20 Sep 2022 13:10:49 +0100 Subject: [PATCH 07/10] Bug-13140 Updating comment --- packages/jest-mock/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 4b1d26fadbe0..1a9cebbed1e2 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -1011,11 +1011,10 @@ export class ModuleMocker { let slotMetadata: MockMetadata | null = null; if (descriptor?.get || descriptor?.set) { - //Specific case required for mocking class definitions imported via types. + //Specific case required for mocking class definitions imported via modules. //In this case the class definitions are stored in accessor properties. //All getters were previously ignored except where the containing object had __esModule == true //Now getters are mocked the class definitions must still be read. - //Example is packages/jest-core/src/__tests__/TestScheduler.test.js -> test('works with default value') // @ts-expect-error ignore type mismatch if (component.__esModule) { // @ts-expect-error no index signature From d02a2ddd553c34bac7538c1e1ac31e6f116c9034 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 28 Sep 2022 09:09:05 +0200 Subject: [PATCH 08/10] Apply suggestions from code review --- packages/jest-mock/src/index.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/jest-mock/src/index.ts b/packages/jest-mock/src/index.ts index 1a9cebbed1e2..4fbf3b0dd0a2 100644 --- a/packages/jest-mock/src/index.ts +++ b/packages/jest-mock/src/index.ts @@ -889,11 +889,11 @@ export class ModuleMocker { } else { slotMock = this._generateMock(slotMetadata, callbacks, refs); - //For superclass accessor properties the subclass metadata contains the definitions - //for the getter and setter methods, and the superclass refs to them. - //The mock implementations are not available until the callbacks have been executed. - //Missing getter and setter refs will be resolved as their callbacks have been - //stacked before the setting of the accessor definition is stacked. + // For superclass accessor properties the subclass metadata contains the definitions + // for the getter and setter methods, and the superclass refs to them. + // The mock implementations are not available until the callbacks have been executed. + // Missing getter and setter refs will be resolved as their callbacks have been + // stacked before the setting of the accessor definition is stacked. if ( slotMetadata.members?.get?.ref !== undefined || slotMetadata.members?.set?.ref !== undefined @@ -908,12 +908,12 @@ export class ModuleMocker { slotMetadata.members?.configurable && slotMetadata.members?.enumerable ) { - //In some cases, e.g. third-party APIs, a 'prototype' ancestor to be - //mocked has a function property called 'get'. In this circumstance - //the 'prototype' property cannot be redefined and doing so causes an - //exception. Checks have been added for the 'configurable' and - //'enumberable' properties present on true accessor property - //descriptors to prevent the attempt to replace the API. + // In some cases, e.g. third-party APIs, a 'prototype' ancestor to be + // mocked has a function property called 'get'. In this circumstance + // the 'prototype' property cannot be redefined and doing so causes an + // exception. Checks have been added for the 'configurable' and + // 'enumberable' properties present on true accessor property + // descriptors to prevent the attempt to replace the API. Object.defineProperty(mock, slot, slotMock as PropertyDescriptor); } else { mock[slot] = slotMock; @@ -1011,10 +1011,10 @@ export class ModuleMocker { let slotMetadata: MockMetadata | null = null; if (descriptor?.get || descriptor?.set) { - //Specific case required for mocking class definitions imported via modules. - //In this case the class definitions are stored in accessor properties. - //All getters were previously ignored except where the containing object had __esModule == true - //Now getters are mocked the class definitions must still be read. + // Specific case required for mocking class definitions imported via modules. + // In this case the class definitions are stored in accessor properties. + // All getters were previously ignored except where the containing object had __esModule == true + // Now getters are mocked the class definitions must still be read. // @ts-expect-error ignore type mismatch if (component.__esModule) { // @ts-expect-error no index signature From c45be304c35ae11d450c28d66df9b09555e27c3f Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 28 Sep 2022 09:10:11 +0200 Subject: [PATCH 09/10] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88cfba26a809..68199551cc54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - `[jest-haste-map]` Remove `__proto__` usage ([#13256](https://github.com/facebook/jest/pull/13256)) - `[jest-mock]` Improve `spyOn` typings to handle optional properties ([#13247](https://github.com/facebook/jest/pull/13247)) +- `[jest-mock]` Fix mocking of getters and setters on classes ([#13145](https://github.com/facebook/jest/pull/13145)) - `[jest-snapshot]` Throw useful error when an array is passed as property matchers ([#13263](https://github.com/facebook/jest/pull/13263)) ### Chore & Maintenance From f86074a3f6e38c6c6f3ba476070ad07437fa328d Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 28 Sep 2022 09:17:09 +0200 Subject: [PATCH 10/10] copyright headers --- packages/jest-mock/src/__tests__/SuperTestClass.ts | 8 ++++++++ packages/jest-mock/src/__tests__/TestClass.ts | 8 ++++++++ .../src/__tests__/class-mocks-dual-import.test.ts | 8 ++++++++ .../src/__tests__/class-mocks-single-import.test.ts | 8 ++++++++ packages/jest-mock/src/__tests__/class-mocks-types.ts | 8 ++++++++ packages/jest-mock/src/__tests__/class-mocks.test.ts | 8 ++++++++ 6 files changed, 48 insertions(+) diff --git a/packages/jest-mock/src/__tests__/SuperTestClass.ts b/packages/jest-mock/src/__tests__/SuperTestClass.ts index 2ea722af2f3a..ae1c262e34f6 100644 --- a/packages/jest-mock/src/__tests__/SuperTestClass.ts +++ b/packages/jest-mock/src/__tests__/SuperTestClass.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + export class SuperTestClass { static staticTestProperty = 'staticTestProperty'; diff --git a/packages/jest-mock/src/__tests__/TestClass.ts b/packages/jest-mock/src/__tests__/TestClass.ts index 59b17d7810f6..e4197db98abe 100644 --- a/packages/jest-mock/src/__tests__/TestClass.ts +++ b/packages/jest-mock/src/__tests__/TestClass.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + import {SuperTestClass} from './SuperTestClass'; export default class TestClass extends SuperTestClass {} diff --git a/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts b/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts index f017806fce07..510484d06700 100644 --- a/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts +++ b/packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + import {SuperTestClass} from './SuperTestClass'; import TestClass from './TestClass'; jest.mock('./SuperTestClass'); diff --git a/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts b/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts index b99054d8734b..2b326b971ea5 100644 --- a/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts +++ b/packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + import SuperTestClass, {TestClass} from './class-mocks-types'; jest.mock('./class-mocks-types'); diff --git a/packages/jest-mock/src/__tests__/class-mocks-types.ts b/packages/jest-mock/src/__tests__/class-mocks-types.ts index e39e582e9ad1..4e277903940f 100644 --- a/packages/jest-mock/src/__tests__/class-mocks-types.ts +++ b/packages/jest-mock/src/__tests__/class-mocks-types.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + export default class SuperTestClass { static staticTestProperty = 'staticTestProperty'; diff --git a/packages/jest-mock/src/__tests__/class-mocks.test.ts b/packages/jest-mock/src/__tests__/class-mocks.test.ts index 874e2940ec7a..a0120958b54b 100644 --- a/packages/jest-mock/src/__tests__/class-mocks.test.ts +++ b/packages/jest-mock/src/__tests__/class-mocks.test.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + describe('Testing the mocking of a class', () => { it('can call an instance method', () => { class TestClass {