Flow: Mocking functions and Flow types

Created on 6 Mar 2017  Â·  5Comments  Â·  Source: facebook/flow

So I'm using create-react-app, updated to the latest version of Jest.

I've added Flow annotations to my unit tests, and everything works in terms of type-checking except for when I try to mock module functions.

For example:

describe('dropdown actions', () => {
  test('create close dropdown successfully', () => {
    Date.now = jest.fn().mockReturnValueOnce(1000) // this has a Flow error
    expect(closeDropdown()).toEqual({
      type: 'CLOSE_DROPDOWN',
      closedAt: 1000,
    });
  });
});

Gives me:

 15:     Date.now = jest.fn().mockReturnValueOnce(1000)
              ^^^ property `now`. Covariant property `now` incompatible with contravariant use in
 15:     Date.now = jest.fn().mockReturnValueOnce(1000)
         ^^^^^^^^ assignment of property `now`

I understand why Flow throws this error: Date.now is read only, so now is covariant (it's a static method). That's why Flow is throwing the error - I'm trying to write to the object property.

But Facebook's own documentation for mocking something like Date.now does the same thing I do:

Date.now = jest.fn(() => 1482363367071);

So I guess this something I need to fix by using Jest in a more clever way? Is there a way in Flow to fix this, or make it okay to do this sort of mocking?

Most helpful comment

Date.now is supposed to be read-only.

The only way around it that I can think of is to force it for testing.

(Date: any).now = ...

All 5 comments

Date.now is supposed to be read-only.

The only way around it that I can think of is to force it for testing.

(Date: any).now = ...

I see - thanks! I'll go with that for now.

Hey, I'm having the same issue.

Casting as suggested by @nmn works but I was wondering if there was a way to make Flow aware of the jest mock? Ideally that's what one would be able to do...

@artisologic You could define your own module just for testing. Then you could import them in Flow comments so Flow uses those types.

So for example, you could define a file like this for your own Date type:

declare module.exports: {
  now: Function,
  ...
}

Then in your test you could:

/*::
const Date = require('path-to-fake-date');
*/

Now, Flow would use the types from the module you defined even though it won't actually affect your code.

tangentially, how are you guys not getting all the warning about jest globals?

src/api/__tests__/timers.test.js:5
  5: jest.mock('api/request');
     ^^^^ identifier `jest`. Could not resolve name

src/api/__tests__/timers.test.js:7
  7: describe('fetchTimers', () => {
     ^^^^^^^^ identifier `describe`. Could not resolve name

src/api/__tests__/timers.test.js:8
  8:   it('returns a few timers (promise)', () => fetchTimers().then((timers) => {
       ^^ identifier `it`. Could not resolve name

I tried:

$ flow-typed install jest
• Found [email protected] installed. Installing libdefs compatible with this version of Flow...
ERROR: Please specify an npm package name of the format '[email protected]'

So I tried:

$ flow-typed install jest@19
• Found [email protected] installed. Installing libdefs compatible with this version of Flow...
• rebasing flow-typed cache...done.
• Installing 1 libdefs...
  • jest_v19.x.x.js
    â””> ./flow-typed/npm/jest_v19.x.x.js

thinking that create-react-app uses v19.
But I'm getting the same errors...
Thanks

Was this page helpful?
0 / 5 - 0 ratings