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

Implement support for async act callbacks and nested calls to act #1854

Merged
merged 5 commits into from
Aug 11, 2019

Conversation

robertknight
Copy link
Member

This PR implements support for passing async callbacks to act and nesting calls to act, matching React 16.9.0. This is useful in cases where triggering an effect or state change involves async steps, such as waiting for a fetch call to resolve.

Following React's behavior, act returns a Promise which resolves immediately if the callback is synchronous or after the callback resolves if it is asynchronous. Awaiting the result of act before making assertions is optional if the callback is sync, but required if the callback is async, as effects/updates are not flushed until the callback's result has resolved in that case.

When calls to act are nested, effects and updates are only flushed when the outer act call returns. This also follows React's behavior.

One feature of React's act that is not implemented yet is warning if you pass an async callback to act but forget to await the result.

  • The first commit adds a Babel transform for await/async using the same low-footprint transform that is used in microbundle, for convenience writing the tests for the later commits (Slack discussion)
  • The second commit adds support for async callbacks to act
  • The third commit adds support for nested calls to act

Add a transform to convert async/await to Promises for use in tests.
This is the same low-footprint transform used by microbundle.

Slack discussion: https://preact.slack.com/archives/G9T60GUQ0/p1565514000140700
Implement initial support for `act` callbacks returning a Promise, in
which case the promise is awaited before state updates and effects are
flushed.

See https://reactjs.org/blog/2019/08/08/react-v16.9.0.html#async-act-for-testing
for more details on the motivation.
When calls to act are nested, effects and component updates are only
flushed when the outer `act` call returns, as per [1] and [2].

This is convenient for creating helper functions which may invoke `act`
themselves.

[1] facebook/react#15682
[2] facebook/react#15472
@coveralls
Copy link

coveralls commented Aug 11, 2019

Coverage Status

Coverage increased (+0.1%) to 99.879% when pulling 104b02d on async-act into 00a7289 on master.

*/
export function act(cb) {
++actDepth;
if (actDepth > 1) {
Copy link
Member

@marvinhagemeister marvinhagemeister Aug 11, 2019

Choose a reason for hiding this comment

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

Super super tiny nit: We can combine this line and the above one:

if (++actDepth > 1) { ... }

Copy link
Member

@marvinhagemeister marvinhagemeister left a comment

Choose a reason for hiding this comment

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

So good! I love your PRs 👍 The attention to details is amazing 😍💯


act(() => {
act(() => {
button.dispatchEvent(new Event('click'));
Copy link
Member

Choose a reason for hiding this comment

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

This will fail in IE11 because it doesn't support new Event(). I have a PR ready which introduces a helper method for that: https://github.com/preactjs/preact/pull/1856/files#diff-d429c5e5b8692f8b67a9d38592332a1eR8

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for catching this. I've updated the code to use the helper.

expect(counter).to.equal(0);

act(() => {
button.dispatchEvent(new Event('click'));
Copy link
Member

Choose a reason for hiding this comment

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

Same IE11 issue as below

Merge in `createEvent` test helper from master.
 - Use `createEvent` helper instead of `new Event` for IE 11 compatibility
 - Combine `actDepth` increment with test
@robertknight
Copy link
Member Author

Feedback / IE 11 issues addressed. Thanks for the super-swift review :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants