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

jest.clearAllMocks(); does not remove mock implementation within afterEach #7136

Open
cphoover opened this issue Oct 10, 2018 · 105 comments
Open

Comments

@cphoover
Copy link

cphoover commented Oct 10, 2018

🐛 Bug Report

jest.clearAllMocks(); does not remove mock implementation within afterEach

To Reproduce

I have a file called src/layouts/index.js

// ./src/layouts/index.js
const importAll = (r) =>
    r.keys().reduce(
        (acc, key) => ({
            ...acc,
            [key.replace(/^\.\/(.*).json$/, '$1')]: r(key)
        }),
        {}
    );

module.exports = importAll(require.context('./', true, /\.json$/));

It utilizes webpack require.context so I am trying to mock with jest.mock.

I have another file... say file util.js

//./src/util.js
import layouts from '../layouts';
export const getLayout(name) {
  return layouts[name];
}

in my test I'm trying to clear the mocks after each test

//./src/util.test.js
describe('my test suite', () => {
  afterEach(() => {
     jest.clearAllMocks();
  })
  test('test number one', () => {
      jest.mock('./layouts', () => ({
          layout1 : { a : 1 },
          layout2 : { b: 2 },
     }));
     assert.equals(getLayout('layout1').a, 1);
     assert.equals(getLayout('layout2').b, 2);
  });
  test('test number two', () => {
     assert.equals(getLayout('layout1').a, 1);
     assert.equals(getLayout('layout2').b, 2);
  });
});

Expected behavior

I would expect for the first test to pass and the second test to fail... because the mock should have been cleared.

Link to repl or repo (highly encouraged)

https://repl.it/@CharlieHoover/SorrowfulBackSandboxes

@cphoover
Copy link
Author

As I understand the parallel execution model of jest the tests inside each suite are run sequentially so you should be able to mock per individual test.

@cphoover
Copy link
Author

cphoover commented Oct 10, 2018

FYI The mocking documentation and API is extremely unclear, and overly complicated IMHO.

@rickhanlonii
Copy link
Member

jest.clearAllMocks does not remove mock implementations by design - try jest.resetAllMocks

Here are the relevant docs:


@cphoover
Copy link
Author

Still does not work with resetAllMocks:

Example included:

https://repl.it/@CharlieHoover/SorrowfulBackSandboxes-2

Aside from that that is extremely ambiguous. Why would a function called clearAllMocks not clear the mocks... Name the function resetMockState or something more descriptive. clearAllMocks implies the mocks are being cleared.

@cphoover
Copy link
Author

cphoover commented Oct 11, 2018

@rickhanlonii my issue is not yet answered. I want to remove the mocks.

@rickhanlonii
Copy link
Member

Ah, yeah, looks like resetAllMocks does not reset mock module factories just the implementations set by mockImplementation. If you want to post what you want to do to stackoverflow I can help you do what you want there but it doesn't look like there's a bug here

Why would a function called clearAllMocks not clear the mocks

I think the confusion is that the "mock" in "clearAllMocks" does not refer to the mock implementations, it refers to the Jest mock objects. So this function means "clear out all jest mock objects" which is to say call .mockClear on all mock objects (i.e. clear the calls)

@ccemeraldeyes
Copy link

@rickhanlonii

omg so #1 it seems like "clear" and "reset" are being used opposite to what their logical meaning is.

Also, it's very clear what he's trying to do; remove the mock implementation, and you're saying there's no way to do that orrr.....?????

@ccemeraldeyes
Copy link

This should be reopened

@MikeSpitz
Copy link

+1

2 similar comments
@montezume
Copy link

+1

@AlvinLaiPro
Copy link

+1

@AlvinLaiPro
Copy link

I have a similar issue, when I mock an implementation in previous it case, the next it case will be affected.

@alexwaibel
Copy link

+1

@Lagily
Copy link

Lagily commented Nov 15, 2019

also struggling with this!

@d4nc3r
Copy link

d4nc3r commented Nov 27, 2019

+1 please update the docs to explain how to REMOVE a mock/spy

@JimmayVV
Copy link

+1 please update the docs to explain how to REMOVE a mock/spy

Isn't this what mockRestore is for? https://jestjs.io/docs/en/mock-function-api#mockfnmockrestore

@damien-roche
Copy link

damien-roche commented Dec 16, 2019

I think the default config should include:

{
  restoreMocks: true,
  clearMocks: true,
  resetMocks: true
} 

It is shocking that the default behaviour is to vomit state between tests. Can you please just keep my tests isolated by default? Then the [hopeful minority] who want to spread state across multiple tests can do so by opt-in.

@ankur20us
Copy link

ankur20us commented Dec 17, 2019

`
describe('test', () => {
beforeEach(() => {
const WelcomeService = require('./../SOME_MODULE')
WelcomeServiceSpyOfMessage = jest.spyOn(
WelcomeService,
'message', // some function I mocked
)
const IsUserAuthentic = require('./../SOME_MODULE')
IsUserAuthenticSpyOnIsUserAuthentic = jest.spyOn(
IsUserAuthentic,
'isUserAuthentic' // some function I mocked
)
app = require('../src/server') // my Express server
})

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

it('1. Mock implementation', async () => {
  const mockedMessage = faker.lorem.sentence()
  WelcomeServiceSpyOfMessage.mockImplementation(() => mockedMessage)
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 1')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', mockedMessage)
})

it('2. After restored implementation', async () => {
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 2')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', 'hello world')
})

})
`
Output:
console.log test/routes.test.js:36
>>> MOCKED MW 1

console.log test/routes.test.js:36
>>> MOCKED MW 1

Same mocked version of function is called for both the tests. Although I have restored all mocks in afterEach call, still same mock is getting called. Please tell me where I missed.

Thanks

@JoaoFGuiomar
Copy link

+1 🥂

@TorranceYang
Copy link

+1

@vinyoliver
Copy link

+1
It seems to me that clearing the mocks after each test should be the default behavior.

@robbporto
Copy link

+1
It seems to me that clearing the mocks after each test should be the default behavior.

+1

@joshssarna
Copy link

functions mocked with .spyOn() can be restored: jest.spyOn(object, method).mockImplementation(mockFunction).

I agree that mocks should be cleared automatically between tests, though.

@karl-frascari
Copy link

+1

1 similar comment
@saitho
Copy link

saitho commented Jan 27, 2020

+1

@cedricsarigumba
Copy link

Is there a fix for this issue? +1

@el-lsan
Copy link

el-lsan commented Feb 13, 2020

Facing the same issue!

@fake364
Copy link

fake364 commented Apr 8, 2022

has anyone found a fix for this ?
I am passing jest.clearAllMocks resetAllMocks under beforeEach and it definitely is still not clearing the mockImplementation

@SidKhanna296 jest.restoreAllMocks() is the one you're looking for.

damn, I've just struggled too much trying to get why clear or reset mocks don't actually CLEAR and RESET mocks, thank you!!! you are my savior

@RafaelEufrazio
Copy link

Shouldn't the clearAllMocks and restoreAllMocks combo work for any use case?

clearAllMocks clears all mock calls
restoreAllMocks restores all mocked implementations to their default (non-mocked) state

The way I see it, the resetAllMocks still keeps mocked implementations as mocks, only without return values or defined implementation.

If I'm wrong here, anyone please correct me

@JRRS1982
Copy link

JRRS1982 commented Apr 21, 2022

Shouldn't the clearAllMocks and restoreAllMocks combo work for any use case?

clearAllMocks clears all mock calls restoreAllMocks restores all mocked implementations to their default (non-mocked) state

The way I see it, the resetAllMocks still keeps mocked implementations as mocks, only without return values or defined implementation.

If I'm wrong here, anyone please correct me

mockClear clears only data pertaining to mock calls

mockReset resets to mock to its initial implementation.

Have a read of this on SO basically if you change mocks between tests then your mock changes, but the mock is not reset as its not been used (at least my understanding)

resetModules and resetMocks is i think the right setup - keen to get a consensus though.

@RafaelEufrazio
Copy link

Shouldn't the clearAllMocks and restoreAllMocks combo work for any use case?
clearAllMocks clears all mock calls restoreAllMocks restores all mocked implementations to their default (non-mocked) state
The way I see it, the resetAllMocks still keeps mocked implementations as mocks, only without return values or defined implementation.
If I'm wrong here, anyone please correct me

mockClear clears only data pertaining to mock calls

mockReset resets to mock to its initial implementation.

Have a read of this on SO basically if you change mocks between tests then your mock changes, but the mock is not reset as its not been used (at least my understanding)

resetModules and resetMocks is i think the right setup - keen to get a consensus though.

As explained in the link you sent, I'm understanding that the mockReset just resets the method to a new jest.fn(), not the original implementation of the method, while the mockRestore restores the original implementation of each method.

I've been using the restoreAllMocks together with the clearAllMocks with that purpose so far, and it has been working great.
Don't know if using resetModules I'd have any advantage though.

@olsonpm
Copy link

olsonpm commented May 20, 2022

to get around the issue, here's a pattern that works for and makes sense to me

the issue for me was resetting my mocks to those which are declared in __mocks__ directories. The easiest solution I saw was to reset modules and re-require them before each test. This way resetAllMocks didn't wipe out all the mocks I wanted persisted. Essentially only the one-off mocks I created in the tests are reset.

* the example is in typescript in case anyone has trouble figuring out the syntax there. Using require instead of dynamic import gets around typing nonsense

let's assume I mock fs.stat to return a particular object

// /__mocks__/fs.ts

// here we declare mocks we want persisted
const mockFs = {
  stat = jest.fn(() => ({ size: 100, blocks: 2, ... })
}

export default mockFs

and depend on that mock to test ./do-something.ts

// /do-something.test.ts

// declare 'let' for each dependency
let fs: jest.MockedObject<typeof import('fs')>
let doSomething: typeof import('./do-something')

beforeEach(() => {
  jest.resetAllMocks()
  jest.resetModules()
  
  fs = require('fs').default
  doSomething = jest.requireActual('./do-something').default
})

describe('some block', () => {
  it('should return a 404', () => {
    fs.stat.mockImplementation(() => throw new Error('file not found'))

    doSomething() // will have the mock implementation above
  })
  
  it('should work', () => {
    doSomething() // will have the mock implementation from /__mocks__/fs.ts
  })
})

@RafaelEufrazio
Copy link

to get around the issue, here's a pattern that works for and makes sense to me

the issue for me was resetting my mocks to those which are declared in mocks directories. The easiest solution I saw was to reset modules and re-require them before each test. This way resetAllMocks didn't wipe out all the mocks I wanted persisted. Essentially only the one-off mocks I created in the tests are reset.

  • the example is in typescript in case anyone has trouble figuring out the syntax there. Using require instead of dynamic import gets around typing nonsense

let's assume I mock fs.stat to return a particular object

// /__mocks__/fs.ts

// here we declare mocks we want persisted
const mockFs = {
  stat = jest.fn(() => ({ size: 100, blocks: 2, ... })
}

export default mockFs

and depend on that mock to test ./do-something.ts

// /do-something.test.ts

// declare 'let' for each dependency
let fs: jest.MockedObject<typeof import('fs')>
let doSomething: typeof import('./do-something')

beforeEach(() => {
  jest.resetAllMocks()
  jest.resetModules()
  
  fs = require('fs').default
  doSomething = jest.requireActual('./do-something').default
})

describe('some block', () => {
  it('should return a 404', () => {
    fs.stat.mockImplementation(() => throw new Error('file not found'))

    doSomething() // will have the mock implementation above
  })
  
  it('should work', () => {
    doSomething() // will have the mock implementation from /__mocks__/fs.ts
  })
})

I think if you used clearAllMocks together with restoreAllMocks you wouldn't need to re-require the dependencies. I may be wrong though, should be tested.

@lucasgcbkhomp
Copy link

lucasgcbkhomp commented May 23, 2022

@SimenB Hi, could you add some labels to this issue? It's a pretty hot topic and is indexed on google, but it seems like it is outside of the radar of those who can assist with this since it is not tagged with anything.

@pke
Copy link

pke commented May 23, 2022

I really have to wonder why facebook does not seem to have those problems? How are they testing over there?!
I was always frustrated jest can't execute tests inside a file in random order, like a proper testing framework should be able to do. The reason for that could be this weird, unpredictable mess of mocks.

@JRRS1982
Copy link

to get around the issue, here's a pattern that works for and makes sense to me

the issue for me was resetting my mocks to those which are declared in mocks directories. The easiest solution I saw was to reset modules and re-require them before each test. This way resetAllMocks didn't wipe out all the mocks I wanted persisted. Essentially only the one-off mocks I created in the tests are reset.

  • the example is in typescript in case anyone has trouble figuring out the syntax there. Using require instead of dynamic import gets around typing nonsense

let's assume I mock fs.stat to return a particular object

// /__mocks__/fs.ts

// here we declare mocks we want persisted
const mockFs = {
  stat = jest.fn(() => ({ size: 100, blocks: 2, ... })
}

export default mockFs

and depend on that mock to test ./do-something.ts

// /do-something.test.ts

// declare 'let' for each dependency
let fs: jest.MockedObject<typeof import('fs')>
let doSomething: typeof import('./do-something')

beforeEach(() => {
  jest.resetAllMocks()
  jest.resetModules()
  
  fs = require('fs').default
  doSomething = jest.requireActual('./do-something').default
})

describe('some block', () => {
  it('should return a 404', () => {
    fs.stat.mockImplementation(() => throw new Error('file not found'))

    doSomething() // will have the mock implementation above
  })
  
  it('should work', () => {
    doSomething() // will have the mock implementation from /__mocks__/fs.ts
  })
})

This is a good imo

@russoedu
Copy link

russoedu commented Jun 6, 2022

Still can't find a solution.

I'm testing a class instance and I need to mock one of the class functions that is called by another other function in the same class.

I tried all the "clean" methods, even together, in the file (before, after) and in the configs.

Nothing worked.

If I change the order of the tests (so, I first test the function (A) and then I test the other function (B) that uses function A and it works.

Not sure what is wrong with it and how to fix it.

@anoop-jadhav-ui
Copy link

anoop-jadhav-ui commented Jun 16, 2022

beforeEach(() => {
  jest.useFakeTimers();
});
afterEach(() => {
  jest.resetAllMocks();
});

This worked for me !

@jimmygchen
Copy link

jimmygchen commented Jun 17, 2022

I think the default config should include:

{
  restoreMocks: true,
  clearMocks: true,
  resetMocks: true
} 

It is shocking that the default behaviour is to vomit state between tests. Can you please just keep my tests isolated by default? Then the [hopeful minority] who want to spread state across multiple tests can do so by opt-in.

^^ this should really be considered.
This problem gets worse when fake timers are used. May be worth adding a clearAllTimers option too.

@pke
Copy link

pke commented Jun 17, 2022

But even this default config does not work reliably :( How is facebook working with such a broken test framework?

@bhushan-patil-official
Copy link

` describe('test', () => { beforeEach(() => { const WelcomeService = require('./../SOME_MODULE') WelcomeServiceSpyOfMessage = jest.spyOn( WelcomeService, 'message', // some function I mocked ) const IsUserAuthentic = require('./../SOME_MODULE') IsUserAuthenticSpyOnIsUserAuthentic = jest.spyOn( IsUserAuthentic, 'isUserAuthentic' // some function I mocked ) app = require('../src/server') // my Express server })

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

it('1. Mock implementation', async () => {
  const mockedMessage = faker.lorem.sentence()
  WelcomeServiceSpyOfMessage.mockImplementation(() => mockedMessage)
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 1')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', mockedMessage)
})

it('2. After restored implementation', async () => {
  IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => {
    console.log('>>> MOCKED MW 2')
    return true
  })
  const result = await request(app)
    .get('/api')
  expect(result.statusCode).toBe(200)
  expect(result.body).toHaveProperty('message', 'hello world')
})

}) ` Output: console.log test/routes.test.js:36 >>> MOCKED MW 1

console.log test/routes.test.js:36 >>> MOCKED MW 1

Same mocked version of function is called for both the tests. Although I have restored all mocks in afterEach call, still same mock is getting called. Please tell me where I missed.

Thanks

I think after whichever test you want to reset/clear the mock, you should add there

afterAll(() => { jest.restoreAllMocks(); })

Because that did the job for me.
Wherever I was mocking modules or making spyOn. I added the afterAll in describe. It worked for me.

@lucasgcbkhomp
Copy link

@SimenB would you kindly triage this for us? It's a very old issue that could be either a serious problem or just a documentation task. It remains untagged with no consensus on what it really is.

But even this default config does not work reliably :( How is facebook working with such a broken test framework?

Until we get this issue tagged so it becomes reachable, it will remain a mystery whether or not it's actually bugged or there's a large misunderstanding from lack of documentation. People only end up here because of search engine results.

agilgur5 added a commit to agilgur5/rollup-plugin-typescript2 that referenced this issue Jul 7, 2022
- now that the integration tests exist, we can actually test this scenario

- refactor: give each test their own `onwarn` mock when necessary
  - while `restoreMocks` is set in the `jest.config.js`, Jest apparently has poor isolation of mocks: jestjs/jest#7136
    - if two tests ran in parallel, `onwarn` was getting results from both, screwing up the `toBeCalledTimes` number
  - couldn't get the syntax error to work with `toBeCalledTimes` either
    - if no mock is given, it _does_ print warnings, but if a mock is given, it doesn't print, yet isn't called?
      - I think the mock is getting screwed up by the error being thrown here; maybe improperly saved or something
ezolenko pushed a commit to ezolenko/rollup-plugin-typescript2 that referenced this issue Jul 12, 2022
…es) (#345)

* fix: type-check `include`d files missed by transform (type-only files)

- type-only files never get processed by Rollup as their imports are
  elided/removed by TS in the resulting compiled JS file
  - so, as a workaround, make sure that all files in the `tsconfig`
    `include` (i.e. in `parsedConfig.fileNames`) are also type-checked
    - note that this will not catch _all_ type-only imports, in
      particular if one is using `tsconfig` `files` (or in general _not_
      using glob patterns in `include`) -- this is just a workaround,
      that requires a separate fix
  - we do the same process for generating declarations for "missed"
    files right now in `_onwrite`, so basically do the same thing but
    for type-checking in `_ongenerate`

(_technically_ speaking, there could be full TS files
(i.e. _not_ type-only) that are in the `include` and weren't
transformed
- these would basically be independent TS files not part of the bundle
  that the user wanted type-checking and declarations for (as we
  _already_ generate declarations for those files))

* move misssed type-checking to `buildEnd` hook, remove declarations check

- `buildEnd` is a more correct place for it, since this does not generate any output files
  - (unlike the missed declarations)
  - and this means it's only called once per build, vs. once per output

- remove the check against the `declarations` dict as one can type-check without outputting declarations
  - i.e. if `declaration: false`; not the most common use-case for rpt2, but it is one

* add new checkedFiles Set to not duplicate type-checking

- since `parsedConfig.fileNames` could include files that were already checked during the `transform` hook
- and because `declarations` dict is empty when `declaration: false`, so can't check against that

* move checkedFiles.add to the beginning of typecheckFile

- because printing diagnostics can bail if the category was error
  - that can result in a file being type-checked but not added to checkedFiles

* wip: fuse _ongenerate functionality into buildEnd, _onwrite into generateBundle

- per ezolenko, the whole generateRound etc stuff was a workaround because the buildEnd hook actually _didn't exist_ before
  - so now that it does, we can use it to simplify some logic
  - no longer need `_ongenerate` as that should be in `buildEnd`, and no longer need `_onwrite` as it is the only thing called in `generateBundle`, so just combine them
  - importantly, `buildEnd` also occurs before output generation, so this ensures that type-checking still occurs even if `bundle.generate()` is not called

- also move the `walkTree` call to above the "missed" type-checking as it needs to come first
  - it does unconditional type-checking once per watch cycle, whereas "missed" only type-checks those that were, well, "missed"
  - so in order to not have duplication, make "missed" come after, when the `checkedFiles` Set has been filled by `walkTree` already

- and for simplification, just return early on error to match the current behavior
  - in the future, may want to print the error and continue type-checking other files
    - so that all type-check errors are reported, not just the first one

NOTE: this is WIP because the `cache.done()` call and the `!noErrors` message are incorrectly blocked behind the `pluginOptions.check` conditional right now
- `cache.done()` needs to be called regardless of check or error or not, i.e. in all scenarios
  - but ideally it should be called after all the type-checking here
- `!noErrors` should be logged regardless of check or not
  - and similarly, after the type-checking

* call `cache().done()` and `!noErrors` in check and non-check conditions

- instead of making a big `if` statement, decided to split out a `buildDone` function
  - to always call at the end of the input phase

- we can also move the `cache().done()` in `emitSkipped` into `buildEnd`, as `buildEnd` gets called when an error occurs as well
  - and this way we properly print for errors as well

- `buildDone` will have more usage in other PRs as well, so I figure it makes sense to split it out now as well

* use `RollupContext` for type-only files

- i.e. bail out when `abortOnError: true`, which `ConsoleContext` can't do
  - `ConsoleContext` is basically meant for everywhere `RollupContext` can't be used
    - which is effectively only in the `options` hook, per the Rollup docs: https://rollupjs.org/guide/en/#options

* add test for type-only file with type errors

- now that the integration tests exist, we can actually test this scenario

- refactor: give each test their own `onwarn` mock when necessary
  - while `restoreMocks` is set in the `jest.config.js`, Jest apparently has poor isolation of mocks: jestjs/jest#7136
    - if two tests ran in parallel, `onwarn` was getting results from both, screwing up the `toBeCalledTimes` number
  - couldn't get the syntax error to work with `toBeCalledTimes` either
    - if no mock is given, it _does_ print warnings, but if a mock is given, it doesn't print, yet isn't called?
      - I think the mock is getting screwed up by the error being thrown here; maybe improperly saved or something
@agilgur5
Copy link

But even this default config does not work reliably :(

Yea I have restoreMocks: true, which according to the mock docs, should call .mockRestore, which should call .mockReset, which should call .mockClear. So only that config should be needed, but it does not seem to perfectly isolate the mocks either; it just restores them prior to the next test.

I've tried calling jest.restoreAllMocks() at the beginning of a test as well as mockFn.mockRestore(), and neither of those worked either.

@SimenB would you kindly triage this for us? It's a very old issue that could be either a serious problem or just a documentation task. It remains untagged with no consensus on what it really is.

@SimenB I reproduced this pretty consistently in ezolenko/rollup-plugin-typescript2#345 (comment) / ezolenko/rollup-plugin-typescript2@01373c1 if that helps with narrowing this down.

At least in my case, basically, if two tests ran in parallel, the top-level mock would have state from both tests, instead of isolated state in each test. The workaround I used for this was to create mocks per-test (i.e. inside each individual test's scope, instead of using a top-level mock). That's in the commit linked above, without that workaround, the tests will fail due to the mock sharing state between parallel tests.

That sounds like possibly correct behavior (given concurrency constraints), but it also sounds like restoreMocks etc are supposed to handle isolating these properly as well; there would be no need for these configuration settings if per-test mocks were required. Or, it's only meant for serially executed tests, which should be explicitly mentioned in the docs, especially since Jest's execution model (when tests are executed in serial vs. parallel) can often be hard to grasp.

@paulmax-os
Copy link

@agilgur5 for me jest.restoreAllMocks() is working fine when it's called from within afterEach(). Furthermore I used mockReturnValueOnce() and mockResolvedValueOnce. Maybe this helps?

@agilgur5
Copy link

@agilgur5 for me jest.restoreAllMocks() is working fine when it's called from within afterEach().

@paulmax-os restoreMocks: true should theoretically have the same effect as that.
Though it's possible that afterEach has an effect on Jest's concurrency model 🤷

Furthermore I used mockReturnValueOnce() and mockResolvedValueOnce.

I'm not sure that these are related? I don't have a need or use-case for these

@paulmax-os
Copy link

@agilgur5 yeah, I just wanted to share a (another) working "solution" for anyone reaching this page. I am using the ...Once() methods in my code, but I think you're right: It should also work without ...Once().

@AyuDevs
Copy link

AyuDevs commented Nov 1, 2022

did you find a solution in the end? nothing seems to work

@paulmax-os
Copy link

paulmax-os commented Nov 1, 2022

For me it worked in the end by doing this:

let wrapper;

beforeEach(() => {
    wrapper = null;
    jest.clearAllMocks();
})

it('makes bar out of foo', async () => {
    const mockMethod = jest
      .spyOn(Class, 'methodName')
      .mockImplementation();

    wrapper = someActionYouWantToPerform('foo');
    await flushPromises(); // depends on your implementation

    expect(mockMethod).toHaveBeenCalledWith('foo');
});

@haribizohra
Copy link

haribizohra commented Apr 25, 2023

For me the problem was that I had a static property. And the problem happened since they aren't part of the instance and are remembered. I have changed it to a normal class property. and it worked (clearAllMocks), maybe someone else didn't pay attention to this and had the same issue 😊

@bj97301
Copy link

bj97301 commented Apr 29, 2023

my function is still being mocked after calling:

    jest.restoreAllMocks()
    jest.resetAllMocks()
    jest.clearAllMocks()

am i missing something?

@kernwig
Copy link

kernwig commented Aug 17, 2023

I too can call all three function and set the equivalents in config, and my call counts still retain their increments from one test to the next.

The only thing that works for me to to create new mocks in beforeEach:

import createMockInstance from "jest-create-mock-instance";

describe("MyUnitUnderTest", () => {
  let reservationRepo: jest.Mocked<ReservationRepository>;
  let eventPublisher: jest.Mocked<EventPublisherService>;
  let usecase: MyUnitUnderTest;

  beforeEach(() => {
    reservationRepo = createMockInstance(ReservationRepository);
    eventPublisher = createMockInstance(EventPublisherService);
    usecase = new MyUnitUnderTest(reservationRepo, eventPublisher);
  });

@mattcwebster
Copy link

For me the problem was that I had a static property. And the problem happened since they aren't part of the instance and are remembered. I have changed it to a normal class property. and it worked (clearAllMocks), maybe someone else didn't pay attention to this and had the same issue 😊

same here, is there a work around for static properties as we shouldn't have to change our implementation to pass a unit test. Atleast, I never do.

@bajiraonakamoto
Copy link

I solve my issue saving the original behavior from my function in another const and after it restore my behavior to original function.

const MyObject = {
  getValue() {
    return 'original value'
  }
}
describe('Test restore original implementation', function () {
  const originalObjectState = {...MyObject}

  test('Mock original function', async function () {
    MyObject.getValue = jest.fn(() => 'mocked value')
    const value = MyObject.getValue()
    expect(value).toBe('mocked value')
  });

  test('Restore original function', async function () {
    MyObject.getValue = originalObjectState.getValue
    const value = MyObject.getValue()
    expect(value).toBe('original value')
  });

});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests