Do you want to request a _feature_ or report a _bug_?
A bug
What is the current behavior?
The requestAnimationFrame doesn't invoke callback. Maybe it happened because the jsdom is using setTimeout under the hood, but useFakeTimers
and runAllTimers
not helping.
If the current behavior is a bug, please provide the steps to reproduce and
either a repl.it demo through https://repl.it/languages/jest or a minimal
repository on GitHub that we can yarn install
and yarn test
.
requestAnimationFrame
on your codeWhat is the expected behavior?
requestAnimationFrame should invoke its callback
Please provide your exact Jest configuration and mention your Jest, node,
yarn/npm version and operating system.
OS: High Sierra
node: 8.9.1
jest: 22.0.3
You can mock requestAnimationFrame
with your own implementation.
Here is a workaround:
beforeEach(() => {
jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb());
});
afterEach(() => {
window.requestAnimationFrame.mockRestore();
});
@lukomwro Great solution, you're right, big thanks
I cannot reproduce this, raf
works for me. Can you provide a reproduction repo?
test('raf', done => {
requestAnimationFrame(() => {
expect(true).toBe(true);
done();
});
});
passes, and switching true
to false
gives the failure as expected
fakeTimers
doesn't work with raf (it's not implemented with the setTimeout
we have access to), but that's a separate bug. Didn't think about that one
@SimenB yes, this example will work as expected, but if you will use raf
inside some code, async done
will not be available, so this code will not work:
test('raf',() => {
requestAnimationFrame(() => {
expect(true).toBe(true);
});
});
so maybe fakeTimers
issue fix will help
That's just async javascript for you.
You can open up a separate feature request for fakeTimers
to work with raf
(PR welcome as well!), but closing this as raf
does work as it should in Jest 22
@SimenB thank you for help, have a nice day :-)
function myFunction() {
requestAnimationFrame(() => {
console.log('inner');
});
}
myFunction();
console.log('outer');
Logs
inner
There is no way for Jest to know that you have scheduled some async work inside your test and wait for it unless you signal it (either done
callback or returning a Promise
).
You can also use e.g. this:
test('something', () => {
expect.hasAssertions();
requestAnimationFrame(() => {
expect(true).toBe(true);
});
});
Then your test will fail.
@SimenB yes, you're right, but if you will use jest < 22, you definitely will use requestAnimationFrame
polyfill, and useFakeTimers
with runAllTimers
will help you to execute code inside callback, so if somebody will update jest to latest version, that code will not work.
Hey, any updates on this? I'm also facing the same issue. I upgraded Jest to v22 and my test using requestAnimationFrame started failing. Is there any way to get around this? Thanks.
You can mock it if you want
@SimenB for some reason I can't seem to be able to mock out requestAnimationFrame used inside the raf package.
I'm currently on Jest 22.1.3.
Here are the things that I've tried
jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb());
window.requestAnimationFrame = cb => cb()
Object.defineProperty(window, 'requestAnimationFrame', {
writable: true,
value: cb => {
cb();
}
});
Any ideas on what's happening here? I know it's not returning my mock because console.log(window.requestAnimationFrame.toString())
is different that my mock. I also tried to switch out window for global and it still doesn't seem to work.
Update: I realized I could just mock the raf module instead. DOH!
jest.mock('raf', () => {
return jest.fn().mockImplementation(cb => cb());
});
This works for me.
@manatarms JSDOM implements raf, so raf
shouldn't do anything... I just tested, and using jest.spyOn
works. See https://repl.it/@SimenB/ExtralargeRoyalblueNetwork
Thanks for the repl @SimenB. For some reason when I put a console.log(raf.toString())
inside /node_modules/raf/index.js for the return value, I get the original implementation instead of my mock. I could be doing something wrong here, but I got it working by mocking out raf instead of requestAnimationFrame.
I can replace requestAnimationFrame
with my own implementation like this
(bit naive, but fine if I just want to advance timers)
global.requestAnimationFrame = fn => setTimeout(fn, 16);
But it must go inside setup-jest
file, as if its inside my test file, it doesn't work.
(probably global is different between the two, I'm running JSDOM 15 and jest 24.8.0)
(I have used this approach to test react-spring
components and it works pretty well)
you can just await a Promise
it("raf", async () => {
await new Promise((resolve) =>
requestAnimationFrame(() => {
expect(true).toBe(true);
resolve();
})
)
})
Sorry for commenting on this closed issue, but I don't fully understand why requestAnimationFrame
needs to be mocked in one of the setup files first when the testEnvironment
is jsdom
? As soon as it's mocked in there, it can be mocked again within the tests, but without the mock in the setup file, the mock in the test file gets more or less ignored. Is there any reason for this behavior?
Most helpful comment
You can mock
requestAnimationFrame
with your own implementation.Here is a workaround: