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

mockClear vs mockReset vs mockRestore #5143

Closed
silvenon opened this issue Dec 20, 2017 · 12 comments
Closed

mockClear vs mockReset vs mockRestore #5143

silvenon opened this issue Dec 20, 2017 · 12 comments

Comments

@silvenon
Copy link
Contributor

Do you want to request a feature or report a bug?

I would like to ask a question about a feature and then submit a PR to the docs based on the answer.

What is the current behavior?

The docs for mockReset say this:

Resets all information stored in the mock, including any initial implementation and mock name given.

This is useful when you want to completely restore a mock back to its initial state.

What is the expected behavior?

I'm not sure what mockRestore does exactly in the context of restoring. Do I need it for restoring a mock's initial implementation? For example:

it('my test', () => {
  const prop = jest.spyOn(obj, 'prop').mockImplementation(() => { /* ... */ });
  // do something with obj.prop
  prop.mockRestore();
});

Is the above enough? Do I need to also call mockReset or maybe even mockClear beforehand? Why do the docs say that mockReset is useful for restoring mock to its initial state?

My main question: what is mockReset useful for?

@SimenB
Copy link
Member

SimenB commented Dec 21, 2017

In your snippet mockRestore restores obj.prop back to its initial state. Instead of

const origProp = obj.prop;
obj.prop = jest.fn().mockImplementation(() => { /* ... */ });
// do something with obj.prop
obj.prop = origProp;

You do not have to call reset or clear.

Did that help? PR very much welcome for clarification to the docs 🙂

@silvenon
Copy link
Contributor Author

Thanks, that did help. 👍 I'm just wondering when is mockReset useful, i.e. when you would reset a mock instead of simply creating a new one with jest.fn(). I'll try to think of some examples and submit a PR to the docs.

@SimenB
Copy link
Member

SimenB commented Dec 21, 2017

For instance:

const mockAProp = jest.fn();

jest.mock('some-dep', () => ({ foobar: mockAProp }));

afterEach(() => {
    mockAProp.mockReset();
});

test('test 1', () => {
    mockAProp.mockImplementation(() => true);
});

test('test 2', () => {
    mockAProp.mockImplementation(() => true);
});

@silvenon
Copy link
Contributor Author

Thanks!

@geoffreyyip
Copy link

geoffreyyip commented Apr 3, 2018

Hey all, think this issue is worth looking into again. The clear, reset, restore distinction isn't the most intuitive.

The site's pretty good on distinguishing the difference between mockReset() and mockClear(). mockReset() is a supersized version of mockClear(). mockClear() resets usage data but not implementation. mockRestore() resets everything, which includes usage data, implementation and mock name.

I also like that restoreMocks() config option points users to the jest.restoreAllMocks() method, which then points to the mockRestore() method. And so forth for their reset and clear counterparts.

Where I see the most confusing is the difference between mockRestore() and mockReset()

mockFn.mockReset()

Resets all information stored in the mock, including any initial implementation and mock name given.

This is useful when you want to completely restore a mock back to its initial state.

Beware that mockReset will replace mockFn.mock, not just mockFn.mock.calls and mockFn.mock.instances. You should therefore avoid assigning mockFn.mock to other variables, temporary or not, to make sure you don't access stale data.

mockFn.mockRestore()

Removes the mock and restores the initial implementation.

This is useful when you want to mock functions in certain test cases and restore the original implementation in others.

Beware that mockFn.mockRestore only works when mock was created with jest.spyOn. Thus you have to take care of restoration yourself when manually assigning jest.fn().

The restoreMocks configuration option is available to restore mocks automatically between tests.

There's two main points of confusion here for me. The first is that both mention resetting implementation. The second is that mockRestore() mentions only working on spies.

Questions that could be clarified:

  • Does mockReset() reset implementation for spies?
  • Does mockRestore() do anything for non-spy mocks?
  • What does it mean to "take care of restoration yourself when manually assigning jest.fn()"?

@rodoabad
Copy link

Any updates on this?

@SimenB
Copy link
Member

SimenB commented Dec 11, 2018

The updated docs doesn't help? #6227

@jensbodal
Copy link

Currently I'm just adding the following any time I use mocks since I believe this should cover all cases whether I use spies or mocks.

afterEach(() => {
    jest.resetAllMocks();
    jest.restoreAllMocks();
});

@sepehr
Copy link

sepehr commented Jan 8, 2020

FTR, here are the answers to the questions raised by @geoffreyyip.

"Does mockReset() reset implementation for spies?"

No. It resets the implementation to a new undefined-returning mock function.

"Does mockRestore() do anything for non-spy mocks?"

Yes. It resets the implementation to a new undefined-returning mock function. For spies, it "restores" the original implementation.

"What does it mean to "take care of restoration yourself when manually assigning jest.fn()"?"

Here's an example:

// contrary to jest.spyOn(), jest.fn() has "replaces" the original implementation
// without keeping a copy for later restoration. 
test('...', () => {
  const origFn = module.api
  module.api = jest.fn() 

  // act, assert, etc.

  // manual restoration
  module.api = origFn
})

Here's a passing test suite that clarifies how mockReset() and mockRestore() behavior differs:
https://repl.it/@sepehr/jest-mock-api-reset-restore#jest-mock-apis.test.js

Further explanation:
https://stackoverflow.com/a/59792748/65732

@tremby
Copy link

tremby commented Jan 25, 2021

@sepehr, your example is really helpful but I think you forgot to change the text of the final test; it's currently a copy of the first test's text and doesn't describe the actual expected results.

@sepehr
Copy link

sepehr commented Jan 25, 2021

@tremby, thanks for the feedback and the catch. I've already fixed this in the linked repl, but forgot that there's a hardcoded snippet as well 😅

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants