`requestAnimationFrame` polyfill error in Jest tests
Asked Answered
B

10

25

Got this error after upgrading to React when I ran my Jest unit tests:

React depends on requestAnimationFrame. Make sure that you load a polyfill in older browsers.

How do I fix it?

I'm using Jest 18.1.0.

Bullfrog answered 25/4, 2017 at 7:17 Comment(0)
P
36

Found a workaround!

Steps:

  1. Create the file __mocks__/react.js (see about __mocks__ folder here)
  2. Add the following into __mocks__/react.js

const react = require('react');
// Resolution for requestAnimationFrame not supported in jest error :
// https://github.com/facebook/react/issues/9102#issuecomment-283873039
global.window = global;
window.addEventListener = () => {};
window.requestAnimationFrame = () => {
  throw new Error('requestAnimationFrame is not supported in Node');
};

module.exports = react;
  1. Run jest !

As marked on comments on the code

This is the solution from https://github.com/facebook/react/issues/9102#issuecomment-283873039

Pigskin answered 13/5, 2017 at 6:52 Comment(1)
I use redux-observable and RxJs, I needed to add: window.cancelAnimationFrame = window.clearTimeout and window.requestAnimationFrame = (cb) => window.setTimeout(cb, 1000 / 60) (I inspired from the code in RxJS)Ostracon
D
35

this worked for me:

  1. Install raf

npm install --saveDev raf or yarn add -D raf

  1. Add the polyfill to your setupFiles in your jest config in package.json like this:

'setupFiles': ['raf/polyfill']

Note: if you have other setup files in this array, you may want to put raf/polyfill first.

Diazole answered 9/10, 2017 at 23:54 Comment(3)
What and where are my setupFiles config?Mycostatin
@kirsteng it is one of the jest config property. Btw this solution works for me, cheers!Daffy
This is the solution found in other packages. github.com/gaearon/react-hot-loader/blob/master/…raf is also a dependency of airbnb/enzyme.Demodulation
H
10

If you just need to polyfill it for tests, then you don't actually need the throttling.

Create a new file with this code:

global.requestAnimationFrame = function (cb) {
    return setTimeout(cb, 0);
};

Add that file to the jest/setupFiles array in your package.json.

Humility answered 15/8, 2017 at 8:20 Comment(3)
nice ... i dropped the setTimeout and went with just cb() - works for all of my existing tests.Tolu
i have added this to my setup file but still getting the warning.Numeral
@Numeral in order to make work this the entry on package.json must be: "jest": { "setupFiles": ["./someFolder/jestHelpers.js"] }Whooper
F
8

If you are using create-react-app, some of these solutions will not work well (or at all, in the case of setupFiles). What does work well is creating a file at src/setupTests.js and adding your mock in there:

global.requestAnimationFrame = (cb) => { cb(); };

You can also add other global mocks in there (e.g. localStorage and navigator.serviceWorker).

Fifine answered 24/10, 2017 at 21:29 Comment(0)
D
1

Another working solution!

The idea is to load a simple shim before each spec, by using the setupFiles property in the jest config.

Create a file shim.js file (preferably in your root dir) and have this code in it:

global.requestAnimationFrame = (callback) => {
    setTimeout(callback, 0);
};

Next, you may be having redundant code that keep reappearing in all/most of your files - and you want to put them in a single file and have them run before each spec also, to do that:

Create a setup.js file in the root dir too. A good piece of redundant code to D.R.Y is the react enzyme adapter configuration code. Paste it here

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

Now create the jest.config.js file, to specify the paths of the two files

{
    module.exports = {
        "setupFiles": ["<rootDir>shim.js", "<rootDir>setup.js"]
    }
}

N.B: The jest config file take json, so make sure json's in. Also, if your shim.js and setup.js files are not in the same dir as your jest.config.js, adjust the path accordingly.

Hope this helps!

Credit: https://github.com/facebook/jest/issues/4545

Disapproval answered 3/11, 2017 at 13:14 Comment(0)
K
1

Here's a realistic way to mock requestAnimationFrame:

let time;
const maxTimeElapsed = 2000;

beforeEach(() => {
  time = 0;
  jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => {
    time += 100;
    if (time < maxTimeElapsed) {
      return cb(time) as any;
    }
  });
});

in your test, it repeatedly calls the RAF callback until it reaches the max elapsed time that you set. It happens instantly, so you don't need to stall it.

Keever answered 19/2, 2019 at 19:45 Comment(0)
G
0

Just upgrade your react-scripts to 1.0.15 or above. It has been officially fixed after that version. See more details in https://github.com/facebook/create-react-app/issues/3199

Search the comment of gaearon commented on 31 Oct 2017

Godard answered 7/2, 2018 at 3:38 Comment(0)
T
0

If you use TypeScript, the best solution is;

window.requestAnimationFrame = (): number => {
   window.clearTimeout();
   return 0;
};

Before all your describe and test suits.

Teutonism answered 13/8, 2021 at 20:39 Comment(0)
B
0

According raf package docs at this moment need to run polyfill() function and specify object that need to be polyfilled. In my case works:

require('raf').polyfill(global.window)
Bannockburn answered 14/6, 2022 at 11:53 Comment(0)
B
-1

Turns out it was because I upgraded enzyme without upgrading react and react-dom.

React 15.5 brings about some deprecations that caused many dependent libraries to have to update too. Make sure you are updating react, react-dom and check the README of those dependent packages for new libraries you have to install. For instance, Enzyme 2.8.2 now requires react-addons-test-utils as a dependency.

Bullfrog answered 25/4, 2017 at 10:16 Comment(1)
I have upgraded react and react-dom but it seems not work.Thalassography

© 2022 - 2024 — McMap. All rights reserved.