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
BorderControl test: await floating-ui state changes when rendering/opening popover #45241
Conversation
Size Change: 0 B Total Size: 1.28 MB ℹ️ View Unchanged
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @jsnajdr for working on this!
Maybe we should add some inline comments in the tests explaining why those unusual act
calls are necessary?
I'm also improving the test suite by removing the global props object which is i) mutable and ii) shared by all tests. And replacing it with a createProps() function that creates a props instance for each test separately.
Those are good changes as well. Cc'ing @tyxla who has recently opened a PR refactoring BorderBoxControl
tests (https://github.com/WordPress/gutenberg/pull/45208/files).
In general I'm not a fan of having the props/createProps
and renderBorderControl / rerenderBorderControl
utilities, as they make the tests more abstract and harder to read, but it's definitely not something related to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing this one @jsnajdr 👍
✅ After checking out #45235 I could replicate the original error
✅ Applying the changes from this PR resolves that issue
Maybe we should add some inline comments in the tests explaining why those unusual act calls are necessary?
This sounds like a good idea. Maybe include the link to the floating-ui docs in those comments as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this @jsnajdr 🙌
I generally agree with what @ciampo already offered as feedback and don't have much more to add. The helpers are pre-existing, so I don't feel it's blocking to inline them, it would just be a nice improvement. Also, inline comments would definitely help, because act()
around element.focus()
seems pretty redundant.
|
||
const toggleLabelRegex = /Border color( and style)* picker/; | ||
|
||
const renderBorderControl = ( customProps ) => { | ||
return render( <BorderControl { ...{ ...props, ...customProps } } /> ); | ||
const renderBorderControl = async ( props ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I added explanatory comment so that any reader will understand the connection between the mysterious await act
and floating-ui
's useFloating
hook.
I don't want to spend time on inlining the renderBorderControl
calls now. Some wrappers around the plain render
and rerender
calls still make sense, because there is the additional act()
call. We could refactor them to:
renderAndWait( <BorderControl { ...props } /> );
making the wrapper a bit shorter, but let's do that in another PR. We could probably avoid all the rerender
calls, too, by putting the value
prop into local useState
of a wrapper component that is actually tested. But let's do that independently, as it's not necessary for the React 18 upgrade.
inline comments would definitely help, because
act()
aroundelement.focus()
seems pretty redundant.
element.focus()
is an issue unrelated to floating-ui
and I'd say the need to wrap it in act()
is not a mystery at all: we're directly calling a method of the DOM element object, which will internaly fire a focus
event, completely circumventing any Testing Library wrappers like fireEvent
or userEvent
. I did a similar fix for another component in #45243.
e94ef94
to
bc2fbe8
Compare
The failing PHPUnit tests are fixed now. See #45265. |
bc2fbe8
to
6c4349a
Compare
Thank you! I rebased the branch and will merge once the tests come back green. |
This PR fixes an issue where the
BorderControl
unit test fails with React 18 (see #45235) with anerror. It happens right after the
BorderControl
is rendered or rerendered, or after anopenPopover
call. Why would that happen given thatrender
andfireEvent
calls are automatically wrapped withact()
? Because the component uses the@floating-ui/react-dom
library, and that library doessetState
in a promise handler, like:Because the
act()
wrappers used byrender
andfireEvent
are "synchronous", i.e, they areact( () => {} )
calls that don't wait for promises to resolve, thesetData
call escapes outside theact()
.We need to add an "asynchronous"
act()
:to get the
setData
flushed before the promise returned byact()
resolves.This PR fixes the issue by making the
renderBorderControl
andopenPopover
functions asynchronous and by adding anawait act
call inside them.The same fix is recommended by the Floating UI docs: https://floating-ui.com/docs/react-dom#testing
I'm also improving the test suite by removing the global
props
object which is i) mutable and ii) shared by all tests. And replacing it with acreateProps()
function that creates aprops
instance for each test separately.This issue was already somewhat discussed back in April in https://github.com/WordPress/gutenberg/pull/32765/files#r845193273.