Skip to content

Commit

Permalink
fix: mocking of getters/setters on automatically mocked classes (#13145)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom Mrazauskas <tom@mrazauskas.de>
  • Loading branch information
staplespeter and mrazauskas committed Sep 28, 2022
1 parent 4adf6ab commit 82e503f
Show file tree
Hide file tree
Showing 10 changed files with 680 additions and 114 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -15,6 +15,7 @@
- `[jest-circus, jest-jasmine2]` Fix error messages for Node's `assert.throes` ([#13322](https://github.com/facebook/jest/pull/13322))
- `[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))
- `[jest-snapshot]` Prioritize parser used in the project ([#13323](https://github.com/facebook/jest/pull/13323))
- `[jest-transform]` Attempt to work around issues with atomic writes on Windows ([#11423](https://github.com/facebook/jest/pull/11423))
Expand Down
3 changes: 3 additions & 0 deletions jest.config.mjs
Expand Up @@ -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',
Expand Down
36 changes: 36 additions & 0 deletions packages/jest-mock/src/__tests__/SuperTestClass.ts
@@ -0,0 +1,36 @@
/**
* 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';

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';
}
}
11 changes: 11 additions & 0 deletions packages/jest-mock/src/__tests__/TestClass.ts
@@ -0,0 +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 {}
130 changes: 130 additions & 0 deletions packages/jest-mock/src/__tests__/class-mocks-dual-import.test.ts
@@ -0,0 +1,130 @@
/**
* 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');
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);
});
});
128 changes: 128 additions & 0 deletions packages/jest-mock/src/__tests__/class-mocks-single-import.test.ts
@@ -0,0 +1,128 @@
/**
* 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');

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);
});
});
38 changes: 38 additions & 0 deletions packages/jest-mock/src/__tests__/class-mocks-types.ts
@@ -0,0 +1,38 @@
/**
* 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';

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 {}

0 comments on commit 82e503f

Please sign in to comment.