Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(jest-mock): do not restore mocks when jest.resetAllMocks() is called #13866

Merged
209 changes: 175 additions & 34 deletions packages/jest-mock/src/__tests__/index.test.ts
Expand Up @@ -1215,30 +1215,6 @@ describe('moduleMocker', () => {
expect(fn.getMockName()).toBe('jest.fn()');
});

test('after mock reset, the object should return to its original value', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both tests are moved below and extended

const myObject = {bar: () => 'bar'};

const barStub = moduleMocker.spyOn(myObject, 'bar');

barStub.mockReturnValue('POTATO!');
expect(myObject.bar()).toBe('POTATO!');
barStub.mockReset();

expect(myObject.bar()).toBe('bar');
});

test('after resetAllMocks, the object should return to its original value', () => {
const myObject = {bar: () => 'bar'};

const barStub = moduleMocker.spyOn(myObject, 'bar');

barStub.mockReturnValue('POTATO!');
expect(myObject.bar()).toBe('POTATO!');
moduleMocker.resetAllMocks();

expect(myObject.bar()).toBe('bar');
});

test('mockName gets reset by mockRestore', () => {
const fn = jest.fn();
expect(fn.getMockName()).toBe('jest.fn()');
Expand Down Expand Up @@ -1312,6 +1288,164 @@ describe('moduleMocker', () => {
);
});

it('supports clearing a spy', () => {
let methodOneCalls = 0;
const obj = {
methodOne() {
methodOneCalls++;
},
};

const spy1 = moduleMocker.spyOn(obj, 'methodOne');

obj.methodOne();

// The spy and the original function are called.
expect(methodOneCalls).toBe(1);
expect(spy1.mock.calls).toHaveLength(1);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);

spy1.mockClear();

// After clearing the spy, the method is still mock function.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);

// After clearing the spy, call count is reset.
expect(spy1.mock.calls).toHaveLength(0);
});

it('supports clearing all spies', () => {
let methodOneCalls = 0;
let methodTwoCalls = 0;
const obj = {
methodOne() {
methodOneCalls++;
},
methodTwo() {
methodTwoCalls++;
},
};

const spy1 = moduleMocker.spyOn(obj, 'methodOne');
const spy2 = moduleMocker.spyOn(obj, 'methodTwo');

obj.methodOne();
obj.methodTwo();

// Both spies and both original functions are called.
expect(methodOneCalls).toBe(1);
expect(methodTwoCalls).toBe(1);
expect(spy1.mock.calls).toHaveLength(1);
expect(spy2.mock.calls).toHaveLength(1);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(true);

moduleMocker.clearAllMocks();

// After clearing all mocks, the methods are still mock functions.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(true);

// After clearing all mocks, call counts are reset.
expect(spy1.mock.calls).toHaveLength(0);
expect(spy2.mock.calls).toHaveLength(0);
});

it('supports resetting a spy', () => {
const methodOneReturn = 0;
const obj = {
methodOne() {
return methodOneReturn;
},
};

const spy1 = moduleMocker.spyOn(obj, 'methodOne').mockReturnValue(10);

// Return value is mocked.
expect(methodOneReturn).toBe(0);
expect(obj.methodOne()).toBe(10);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);

spy1.mockReset();

// After resetting the spy, the method is still mock functions.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);

// After resetting the spy, the method returns the original return value.
expect(methodOneReturn).toBe(0);
expect(obj.methodOne()).toBe(0);
});

it('supports resetting all spies', () => {
const methodOneReturn = 0;
const methodTwoReturn = 0;
const obj = {
methodOne() {
return methodOneReturn;
},
methodTwo() {
return methodTwoReturn;
},
};

moduleMocker.spyOn(obj, 'methodOne').mockReturnValue(10);
moduleMocker.spyOn(obj, 'methodTwo').mockReturnValue(20);

// Return values are mocked.
expect(methodOneReturn).toBe(0);
expect(methodTwoReturn).toBe(0);
expect(obj.methodOne()).toBe(10);
expect(obj.methodTwo()).toBe(20);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(true);

moduleMocker.resetAllMocks();

// After resetting all mocks, the methods are still mock functions.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(true);

// After resetting all mocks, the methods return the original return value.
expect(methodOneReturn).toBe(0);
expect(methodTwoReturn).toBe(0);
expect(obj.methodOne()).toBe(0);
expect(obj.methodTwo()).toBe(0);
});

it('supports restoring a spy', () => {
let methodOneCalls = 0;
const obj = {
methodOne() {
methodOneCalls++;
},
};

const spy1 = moduleMocker.spyOn(obj, 'methodOne');

obj.methodOne();

// The spy and the original function are called.
expect(methodOneCalls).toBe(1);
expect(spy1.mock.calls).toHaveLength(1);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);

spy1.mockRestore();

// After restoring the spy, the method is not mock function.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(false);

obj.methodOne();

// After restoring the spy only the real method bumps its call count, not the spy.
expect(methodOneCalls).toBe(2);
expect(spy1.mock.calls).toHaveLength(0);
});

it('supports restoring all spies', () => {
let methodOneCalls = 0;
let methodTwoCalls = 0;
Expand All @@ -1327,25 +1461,32 @@ describe('moduleMocker', () => {
const spy1 = moduleMocker.spyOn(obj, 'methodOne');
const spy2 = moduleMocker.spyOn(obj, 'methodTwo');

// First, we call with the spies: both spies and both original functions
// should be called.
obj.methodOne();
obj.methodTwo();

// Both spies and both original functions are called.
expect(methodOneCalls).toBe(1);
expect(methodTwoCalls).toBe(1);
expect(spy1.mock.calls).toHaveLength(1);
expect(spy2.mock.calls).toHaveLength(1);

expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(true);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(true);

moduleMocker.restoreAllMocks();

// Then, after resetting all mocks, we call methods again. Only the real
// methods should bump their count, not the spies.
// After restoring all mocks, the methods are not mock functions.
expect(moduleMocker.isMockFunction(obj.methodOne)).toBe(false);
expect(moduleMocker.isMockFunction(obj.methodTwo)).toBe(false);

obj.methodOne();
obj.methodTwo();

// After restoring all mocks only the real methods bump their count, not the spies.
expect(methodOneCalls).toBe(2);
expect(methodTwoCalls).toBe(2);
expect(spy1.mock.calls).toHaveLength(1);
expect(spy2.mock.calls).toHaveLength(1);
expect(spy1.mock.calls).toHaveLength(0);
expect(spy2.mock.calls).toHaveLength(0);
});

it('should work with getters', () => {
Expand Down Expand Up @@ -1518,8 +1659,8 @@ describe('moduleMocker', () => {
obj.methodTwo();
expect(methodOneCalls).toBe(2);
expect(methodTwoCalls).toBe(2);
expect(spy1.mock.calls).toHaveLength(1);
expect(spy2.mock.calls).toHaveLength(1);
expect(spy1.mock.calls).toHaveLength(0);
expect(spy2.mock.calls).toHaveLength(0);
});

it('should work with getters on the prototype chain', () => {
Expand Down Expand Up @@ -1624,8 +1765,8 @@ describe('moduleMocker', () => {
obj.methodTwo();
expect(methodOneCalls).toBe(2);
expect(methodTwoCalls).toBe(2);
expect(spy1.mock.calls).toHaveLength(1);
expect(spy2.mock.calls).toHaveLength(1);
expect(spy1.mock.calls).toHaveLength(0);
expect(spy2.mock.calls).toHaveLength(0);
});
});

Expand Down