Jest: Different behaviour between mockResolvedValue and mockImplementation

Created on 26 Jun 2018  路  13Comments  路  Source: facebook/jest

馃悰 Bug Report

In the documentation mockFn.mockResolvedValue(value) is described as a simple sugar function for jest.fn().mockImplementation(() => Promise.resolve(value)), but I noticed a different behaviour when using ES2018 Promise finally().

The tests pass with mockImplementation() but fail with mockResolvedValue() and return this error: finally is not a function.

To Reproduce

Use ES2018 Promise finally() in your application (importing babel-polyfill for example) and try to test it with mockResolvedValue() and mockImplementation().

Expected behavior

The result should be the same with both implementations.

Link to repo

Here is a simple example.

Config

Node: 8.11.1
Jest: 23.2.0 (empty config)
Babel: 6.23.0 (babel-preset-env)
Babel-polyfill: 6.26.0

Most helpful comment

Curiously, the code in jest actually does simply call mockImplementation(() => Promise.resolve(value)):
https://github.com/facebook/jest/blob/f8efff95431dd079abf8ae02b8e541e3019d211b/packages/jest-mock/src/index.js#L512

It looks like the issue might be in the way how ES polyfills patch finally in. I guess that somehow jest runtime captures the 'native' instance of Promise function, while unit test scripts capture a patched version with another prototype. I mean, I did see 2 different prototypes for Promise while debugging - one with finally and one without.

All 13 comments

Is there a workaround for tests with code using finally() until this is resolved?

In my tests I imported babel-polyfill in the setupTestFrameworkScriptFile file and when I need to mock a function that returns a promise, I use the jest.fn().mockImplementation(() => Promise.resolve(value)) syntax instead of jest.fn().mockResolvedValue(value) .
I'm not sure it's the right way to do but it works.

Thanks @VictorCazanave that worked for me

A slightly shorter workaround is jest.fn().mockReturnValue(Promise.resolve(value)) - also works.

Curiously, the code in jest actually does simply call mockImplementation(() => Promise.resolve(value)):
https://github.com/facebook/jest/blob/f8efff95431dd079abf8ae02b8e541e3019d211b/packages/jest-mock/src/index.js#L512

It looks like the issue might be in the way how ES polyfills patch finally in. I guess that somehow jest runtime captures the 'native' instance of Promise function, while unit test scripts capture a patched version with another prototype. I mean, I did see 2 different prototypes for Promise while debugging - one with finally and one without.

Curiously, the code in jest actually does simply call mockImplementation(() => Promise.resolve(value)):
jest/packages/jest-mock/src/index.js

Line 512 in f8efff9

f.mockImplementation(() => Promise.resolve(value));
It looks like the issue might be in the way how ES polyfills patch finally in. I guess that somehow jest runtime captures the 'native' instance of Promise function, while unit test scripts capture a patched version with another prototype. I mean, I did see 2 different prototypes for Promise while debugging - one with finally and one without.

I have the same issue. But it is so weird. I passed all my unit test at local computer. And then I push it to Github then it was failed some test cases on Drone CI tool. Which as I understand is the same root cause with you.
I have followed the guide to change mockResolvedValue to mockImplementation. However, it didn't work to me. I have digged deep to the library to see what really happening and it is the same like you talk about.

code from jest mock

Now I am trying to find what I have to do next.

I found a solution for this and I think that this is root cause(my project use Vuejs).
In my webpack.base.conf I saw this line of code.

entry: {
    app: ["babel-polyfill", "./src/main.js"]
  },

It mean we add babel-polyfill before we run our bundle file in order to allow it pack polyfill in.

So In my setup.js. I added import "babel-polyfill" and it work perfectly.

Bumped into this issue while adding jest to an Angular-CLI project.

Tried importing babel-polyfill in setup.js to no avail.

Been having this issue as well. I can add in a .finally polyfill, but mockResolvedValue seems to avoid it somehow.

I also have a similar issue (not obviously related to .finally though). I'm testing a React component that has several synchronous calls and mocking the return values of those calls.

When I use

mockedFunction.mockResolvedValue({ success: true })

the test fails (due to not actually waiting for the mocked promise to resolve), but when I use

mockedFunction.mockImplementation(() => Promise.resolve({ success: true }))

it works as expected.

Was a fix found for this?

@lgc13 I did this to get around it:

mockImplementationOnce(() => Promise.resolve("response"))

The solution for me was to start using Node 10+ which supports finally.

Was this page helpful?
0 / 5 - 0 ratings