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

feat: Use concurrent React when available #937

Merged
merged 22 commits into from
Sep 13, 2021

Conversation

eps1lon
Copy link
Member

@eps1lon eps1lon commented Jun 23, 2021

BREAKING CHANGE: If you have React 18 installed, we'll use the new createRoot API by default which comes with a set of changes while also enabling support for concurrent features.
To can opt-out of this change by using render(ui, { legacyRoot: true } ). But be aware that the legacy root API is deprecated in React 18 and its usage will trigger console warnings.

If you want to try out this build follow the "local install instructions" in https://ci.codesandbox.io/status/testing-library/react-testing-library/pr/937/

Continuation of #925 that GitHub is unable to re-open.

Integration tests:

What:

Closes #509

Why:

Concurrent features will be available in React 18.

Opt-out (breaking change) vs opt-in (feature release):
createRoot is considered to be the default in React 18 so we should follow.

How:

Add a concurrent option to render. Note that there are still some unsolved problems with testing concurrent features like reactwg/react-18#21 (comment) and reactwg/react-18#23 (comment). So testing concurrent features will change. We will only support the latest pre-release of React 18. So any release of @testing-library/react may break your testing setup if don't have the latest alpha/beta/release candidate installed.

Checklist:

  • Documentation added to the
    docs site
  • Tests
  • Typescript definitions updated
  • Ready to be merged

@eps1lon eps1lon added the BREAKING CHANGE This change will require a major version bump label Jun 23, 2021
@codesandbox-ci
Copy link

codesandbox-ci bot commented Jun 23, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f9c851e:

Sandbox Source
React Configuration
react-testing-library-examples Configuration

@eps1lon eps1lon changed the title React 18 compat feat: Use createRoot when available Jun 23, 2021
@eps1lon eps1lon changed the title feat: Use createRoot when available feat: Use concurrent React when available Jun 23, 2021
@codecov
Copy link

codecov bot commented Jun 23, 2021

Codecov Report

Merging #937 (f9c851e) into alpha (84851dc) will not change coverage.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##             alpha      #937   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            4         4           
  Lines          140       179   +39     
  Branches        28        38   +10     
=========================================
+ Hits           140       179   +39     
Flag Coverage Δ
experimental 92.73% <85.93%> (?)
latest 91.62% <76.56%> (?)
next 92.73% <85.93%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/act-compat.js 100.00% <100.00%> (ø)
src/pure.js 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 84851dc...f9c851e. Read the comment docs.

@eps1lon eps1lon force-pushed the feat/concurrent-render branch from c42e134 to 60395b4 Compare September 11, 2021 09:56
@eps1lon eps1lon changed the base branch from main to alpha September 11, 2021 09:56
Copy link
Member

@kentcdodds kentcdodds left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks solid! Just one question.

unstable_advanceTimersWrapper: cb => {
return act(cb)
},
asyncWrapper: cb => cb(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary to configure?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR: I misunderstood the question. I think we don't need to configure that because it's the default. I still leave my original long winded explainer for future reference and because it made me realize I still don't fully understand why act() behaves the way it does.

So let's say we have

waitFor(() => expect(getByRole('button')).toBeInTheDocument())

and the button would only appear after two intervals. This would previously translate to

act(() => {
   jest.advanceTimersByTime();
   checkCallback();
   jest.advanceTimersByTime();
   checkCallback();
});

The problem is that React only flushes effects when exiting the act call. So checkCallback could not assert on any effect scheduled due to timers being advanced.
If we just configure unstable_advanceTimersWrapper to use act we would now have

act(() => {
   jest.advanceTimersByTime();
   act(() => {
     checkCallback();
   })
   jest.advanceTimersByTime();
   act(() => {
     checkCallback();
   });
});

The problem now is that React only flushes scheduled effects in the outermost act so we need to remove that.

I think I good question is why only the outermost act is considered.

Copy link
Member Author

@eps1lon eps1lon Sep 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to double check something though. React 17 will no longer have act as the asyncWrapper but somehow our React 17 tests are still passing. So either our tests are incomplete or this was dead code.

Copy link
Member

@MatanBobi MatanBobi Sep 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to double check something though. React 17 will no longer have act as the asyncWrapper but somehow our React 17 tests are still passing. So either our tests are incomplete or this was dead code.

Did you mean React 18? If so, following this comment I'm not sure it won't work, it's just not needed anymore, isn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean React 18? If so, following this comment I'm not sure it won't work, it's just not needed anymore, isn't it?

No, 17. I was reffering to our usage though. I changed the behavior for React 17 as well but no tests started failing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to double check something though. React 17 will no longer have act as the asyncWrapper but somehow our React 17 tests are still passing. So either our tests are incomplete or this was dead code.

Tests are incomplete due to usage of class components. Backported the new tests with a function component in #962 that should ensure asyncWrapper is still present in React 17.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prevented mild disaster since the new tests also uncovered silly lines such as typeof React.startTransition !== undefined. It's either React.startTransition !== undefined or typeof React.startTransition !== 'undefined'.

Also uncovered that the "configure wrapper" approach is not compatible with supporting different timers across multiple versions of react.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to leave this a bit until the next WG meeting. Unclear what the timeline is for work on act. Feels like the core team already moved on but there are still glaring holes in the behavior of act().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I'm personally fine with shipping this as an alpha to test integration. We haven't solved all problems yet for the alpha but neither has React itself. I'm fine with shipping this in an incomplete state since I can just blame React about all the missing parts 😎

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds fine to me 👍

@eps1lon eps1lon force-pushed the feat/concurrent-render branch from 5c5c433 to f9c851e Compare September 12, 2021 10:10
@eps1lon eps1lon merged commit c888cb6 into testing-library:alpha Sep 13, 2021
@eps1lon eps1lon deleted the feat/concurrent-render branch September 13, 2021 08:49
@github-actions
Copy link

🎉 This PR is included in version 13.0.0-alpha.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@nstepien
Copy link

Testing this 13.0.0-alpha.1 release in adazzle/react-data-grid#2459 and now React is printing a ton of act warnings, is that expected?
https://github.com/adazzle/react-data-grid/runs/3585365674

@diegohaz
Copy link

Testing this 13.0.0-alpha.1 release in adazzle/react-data-grid#2459 and now React is printing a ton of act warnings, is that expected?
https://github.com/adazzle/react-data-grid/runs/3585365674

@nstepien I'm also experiencing this on tests using waitFor. But, if I understood correctly, this hasn't been fully implemented in this alpha release because of #937 (comment)

@eps1lon
Copy link
Member Author

eps1lon commented Sep 13, 2021

@nstepien @diegohaz Please read #509 (comment)

eps1lon added a commit to eps1lon/react-testing-library that referenced this pull request Nov 22, 2021
BREAKING CHANGE: If you have React 18 installed, we'll use the new [`createRoot` API](reactwg/react-18#5) by default which comes with a set of [changes while also enabling support for concurrent features](reactwg/react-18#4).
To can opt-out of this change by using `render(ui, { legacyRoot: true } )`. But be aware that the legacy root API is deprecated in React 18 and its usage will trigger console warnings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKING CHANGE This change will require a major version bump released on @alpha
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for React 18
6 participants