jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
43.86k stars 6.39k forks source link

jest.resetAllMocks also resets manual mocks #10419

Open nilsm opened 3 years ago

nilsm commented 3 years ago

🐛 Bug Report

Calling jest.resetAllMocks() resets manual mocks created via a mocks folder. I'm calling this a bug because it means there is no way to return to the original, manually mocked implementation. The manual mock is wiped out by resetAllMocks(); It also means that you can't easily mix and match manual mocks and the mockResolvedValue, mockValue, mockImplementation, etc. methods.

To Reproduce

Use a manual mock, and call jest.resetAllMocks()

Expected behavior

I expect the manual mock to be restored to its manually mocked state, and not to a blank mock.

Link to repl or repo (highly encouraged)

I couldn't create a mocks folder in repl.it, can upload a repo later if required.

envinfo

System:
    OS: macOS 10.15.5
    CPU: (4) x64 Intel(R) Core(TM) i5-5287U CPU @ 2.90GHz
  Binaries:
    Node: 12.18.1 - ~/.nvm/versions/node/v12.18.1/bin/node
    npm: 6.14.7 - ~/.nvm/versions/node/v12.18.1/bin/npm
  npmPackages:
    jest: ^26.2.2 => 26.3.0 
tkrotoff commented 3 years ago

Your sentence "there is no way to return to the original, manually mocked implementation" sums it all. I've spent hours playing with clearAllMocks, resetAllMocks, restoreAllMocks, resetModules trying to find a clean solution. There are none.

In my opinion this is what you would expect from restoreAllMocks instead of "only works when the mock was created with jest.spyOn".

What's the point of having __mocks__ if restoreAllMocks does not use it?

// __mocks__/npm-package.js

export const foo = jest.fn(() => 'original');
// mytest.test.js

import { foo } from 'npm-package';

//beforeEach(jest.restoreAllMocks);

test('original', () => {
  expect(foo()).toEqual('original');
});

test('override', () => {
  foo.mockReturnValue('override');
  expect(foo()).toEqual('override');
});

test('original', () => {
  jest.restoreAllMocks();
  // FAIL
  // restoreAllMocks/resetAllMocks assigns jest.fn() to foo instead of using __mocks__/npm-package.js
  expect(foo()).toEqual('original');
});

Related:

ccmattr commented 3 years ago

I agree with this sentiment. I could definitely use a way to reset back to the original mock. In my case I'm trying to mock the knex module. Currently I'm doing the following:

// __mocks__/knex.js
export default {
    select: jest.fn().mockReturnThis(),
    from: jest.fn().mockReturnThis(),
    where: jest.fn().mockReturnThis(),
    whereNotNull: jest.fn().mockReturnThis(),
    del: jest.fn().mockReturnThis(),
    insert: jest.fn().mockReturnThis(),
    into: jest.fn().mockReturnThis(),
    orderBy: jest.fn().mockReturnThis(),
    limit: jest.fn().mockReturnThis(),
    first: jest.fn().mockReturnThis(),
    then: jest.fn(function (done) {
        done(null)
    })
}

When i override one of the properties to provide a specific value for my test I then cant reset it back to the original mock as iv lost the context of this.

julienw commented 1 year ago

see also https://github.com/facebook/jest/issues/7573 that's similar. Still no answer to this issue, I bumped into it again today :/

adambiggs commented 1 year ago

I just wasted hours trying to figure out why my __mocks__ weren't working... Turns out it was resetMocks: true in my jest.config.js...

Why would you ever want to reset manual mocks to essentially be an empty jest.fn()? I would expect resetting a manual mock would set it back to the state defined in the __mocks__ module.

Also, this only seems to apply to manual mocks of user modules. Manual mocks of node modules seem to work fine with resetMocks: true in my Jest config... 🙃

MilanJimi commented 1 year ago

Just ran into this today. I can't find any function that would reset jest.spyOn, but restore the original manual __mocks__. It always just returns to default jest.fn().

I can work around by ordering the tests differently (yuck). This is just nasty.

github-actions[bot] commented 4 months ago

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

tkrotoff commented 4 months ago

Please don't close 🙏 (I hate those bots)