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

requestAnimationFrame does not invoke callback (v22, jsdom: latest version) #5147

Closed
oookli opened this issue Dec 20, 2017 · 17 comments
Closed

Comments

@oookli
Copy link

oookli commented Dec 20, 2017

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.

  1. Use requestAnimationFrame on your code
  2. try to test what is happened inside callback

What 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

@oookli oookli changed the title requestAnimationFrame do not invoke callback (v22, jsdom: latest version) requestAnimationFrame does not invoke callback (v22, jsdom: latest version) Dec 21, 2017
@lukomwro
Copy link

You can mock requestAnimationFrame with your own implementation.

Here is a workaround:

beforeEach(() => {
  jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb());
});

afterEach(() => {
  window.requestAnimationFrame.mockRestore();
});

@oookli
Copy link
Author

oookli commented Dec 21, 2017

@lukomwro Great solution, you're right, big thanks

@SimenB
Copy link
Member

SimenB commented Dec 21, 2017

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

@oookli
Copy link
Author

oookli commented Dec 21, 2017

@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

@SimenB
Copy link
Member

SimenB commented Dec 21, 2017

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 SimenB closed this as completed Dec 21, 2017
@oookli
Copy link
Author

oookli commented Dec 21, 2017

@SimenB thank you for help, have a nice day :-)

@SimenB
Copy link
Member

SimenB commented Dec 21, 2017

function myFunction() {
  requestAnimationFrame(() => {
    console.log('inner');
  });
}

myFunction();
console.log('outer');

Logs

outer
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.

@oookli
Copy link
Author

oookli commented Dec 21, 2017

@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.

afc163 added a commit to ant-design/ant-design that referenced this issue Mar 5, 2018
afc163 added a commit to ant-design/ant-design that referenced this issue Mar 6, 2018
* Fix test case for new jsdom

* use setTimeout as raf in jest jsdom

* Fix cancelAnimationFrame

* Add comment for jestjs/jest#5147

* longer timeout

* fix snap

* upgrade antd-tools
afc163 pushed a commit to ant-design/ant-design that referenced this issue Mar 10, 2018
* Add the defaultActiveTabKey property for the Card component (close #8789, #8942)

* `activeTabKey` should be added

* Improve

* Fix large tabs font size, close #9509

* docs: Add TreeSelect[dropdownClassName]

* Fix passing dropdownClassName to tree-select

* build: update remark-parse requirement to ^5.0.0 (#9545)

Updates the requirements on [remark-parse](https://github.com/remarkjs/remark) to permit the latest version.
- [Release notes](https://github.com/remarkjs/remark/releases)
- [Commits](https://github.com/remarkjs/remark/commits/remark@5.0.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* add Tooltip  contextMenu doc

* Improve Grid and Layout type definition

* fix: focus editor (#9548)

* Fix test case for new jsdom (#9527)

* Fix test case for new jsdom

* use setTimeout as raf in jest jsdom

* Fix cancelAnimationFrame

* Add comment for jestjs/jest#5147

* longer timeout

* fix snap

* upgrade antd-tools

* Update typescript requirement to ~2.7.2 (#9522)

Updates the requirements on [typescript](https://github.com/Microsoft/TypeScript) to permit the latest version.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/commits/v2.7.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Fix a ts error

* build: update react-slick requirement to ~0.20.0 (#9543)

Updates the requirements on [react-slick](https://github.com/akiran/react-slick) to permit the latest version.
- [Changelog](https://github.com/akiran/react-slick/blob/master/CHANGELOG.md)
- [Commits](https://github.com/akiran/react-slick/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* Fix test cases

* site: fix intersection-observer polyfill

* docs: update recommendation

* Fix typo WeexPickerProps -> WeekPickerProps (#9564)

* use lodash

* Fixed typo on Visualization rules (#9575)

Style of a navigation should conform to the its level.

should be

Style of a navigation should conform to its level.

* Improve Radio/Checkbox type definition

Close #9574

* Remove AbstractCheckboxChangeEvent, fix TS4029 error

See microsoft/TypeScript#9944

* Update index.en-US.md (#9579)

* add transitionName from message.config (#9580)

* add transitionName from message.config

* Update index.en-US.md (#9579)

* modify doc

* build: update react-virtualized requirement to ~9.18.5 (#9544)

Updates the requirements on [react-virtualized](https://github.com/bvaughn/react-virtualized) to permit the latest version.
- [Changelog](https://github.com/bvaughn/react-virtualized/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bvaughn/react-virtualized/commits/9.18.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>

* When treeNode is disabled, its switcher is highlight and clickabled (#9539)

* When treeNode is disabled, its switcher is highlight and clickabled

* rc-tree@1.7.11

* Fix moment require (#9528)

Fix #9502

* Update snapshot
@manatarms
Copy link

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.

@SimenB
Copy link
Member

SimenB commented May 4, 2018

You can mock it if you want

@manatarms
Copy link

manatarms commented May 6, 2018

@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.

@SimenB
Copy link
Member

SimenB commented May 6, 2018

@manatarms JSDOM implements raf, so raf shouldn't do anything... I just tested, and using jest.spyOn works. See https://repl.it/@SimenB/ExtralargeRoyalblueNetwork

@manatarms
Copy link

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.

@danielhusar
Copy link

danielhusar commented May 29, 2019

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)

@grocco
Copy link

grocco commented Jun 7, 2019

you can just await a Promise

it("raf", async () => {
  await new Promise((resolve) =>
    requestAnimationFrame(() => {
      expect(true).toBe(true);
      resolve();
    })
  )
})

@ndresx
Copy link
Contributor

ndresx commented Oct 17, 2020

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?

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants