Skip to content

fix: Support React 19 and remove Jest reliance in test utils #7686

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

Merged
merged 16 commits into from
Apr 8, 2025

Conversation

LFDanLu
Copy link
Member

@LFDanLu LFDanLu commented Jan 30, 2025

Closes #7632

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

Comment on lines 244 to 254
// else {
// // TODO: this is a bit unfortunate, but from a submenu point of view, we can't perform a check that waits for
// // focus to return to the original trigger since we don't have that information in the submenu trigger tester. Even if we did
// // it is a bit unpredicatable where focus might end up landing and waiting for the option/menu to disappear isn't sufficient if there are
// // more transitions in play. For now advance times by a certain amount of time and rely on the user to advance them even more if need be
// if (this._advanceTimer == null) {
// throw new Error('No advanceTimers provided for long press.');
// } else {
// await act(async () => await this._advanceTimer(1000));
// }
// }
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 some poking around trying to get rid of the last jest.runAllTimers() here but no luck. The above is ok, but can extend test duration by quite a bit, also seemed to have some problems with hanging that I didn't quite figure out

@LFDanLu
Copy link
Member Author

LFDanLu commented Jan 30, 2025

ugh lint blew up, not sure why

@@ -29,7 +29,7 @@ export interface UserOpts {
* A function used by the test utils to advance timers during interactions. Required for certain aria patterns (e.g. table). This can be overridden
* at the aria pattern tester level if needed.
*/
advanceTimer?: (time?: number) => void | Promise<unknown>
advanceTimer?: (time?: number) => void | Promise<unknown> | any
Copy link
Member Author

Choose a reason for hiding this comment

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

the typing will need to be looked at again for advanceTimers, providing jest.runAllTimers as is threw some TS issues depending on the configuration.

@@ -423,7 +423,7 @@ import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// ...
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/ListBox.html#testing
Copy link
Member Author

Choose a reason for hiding this comment

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

Hopefully makes it a little more clear that additional setup might be needed for RSP components in general

Comment on lines 28 to 29
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^16.0.0",
Copy link
Member Author

Choose a reason for hiding this comment

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

Doesn't seem to have any breaking changes with this bump and the tests ran clean but will need to confirm on a React 19 project that the test utils work now

@LFDanLu
Copy link
Member Author

LFDanLu commented Mar 18, 2025

closing for now, will reopen when I get some time to work some more on this

@LFDanLu LFDanLu closed this Mar 18, 2025
@LFDanLu LFDanLu reopened this Mar 31, 2025
@rspbot
Copy link

rspbot commented Apr 1, 2025

Comment on lines +232 to +237
// This chain of waitFors is needed in place of running all timers since we don't know how long transitions may take, or what action
// the menu option select may trigger.
if (
!(menuSelectionMode === 'single' && !closesOnSelect) &&
!(menuSelectionMode === 'multiple' && (keyboardActivation === 'Space' || interactionType === 'mouse'))
) {
Copy link
Member Author

Choose a reason for hiding this comment

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

The chain of waitFors below is a bit gross, but allows us to get rid of any assumptions of how long it will take the menu to close/transition out. Open to any alternatives

Copy link
Member

Choose a reason for hiding this comment

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

I think it might be better to pass in a function which could advance the timers by whatever amount.
I'm not sure how waitFor works in a mocked timer situation since technically it does polling which is based on timers.... at least, in the non-mocked timers case. You may want to have a look at the source for waitFor.
The alternative is to do something like test-library does with their userSetup({delay: null/50/100/whatever})

Copy link
Member

@snowystinger snowystinger Apr 3, 2025

Choose a reason for hiding this comment

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

selectOption({option, timerForClose: () => act(() => jest.runAllTimers())})

happy to workshop the name

Copy link
Member Author

Choose a reason for hiding this comment

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

waitFor advances fake timers if it detects them via: https://github.com/testing-library/dom-testing-library/blob/a86c54ccda5242ad8dfc1c70d31980bdbf96af7f/src/wait-for.js#L75-L82 and does polling. The only thing I'm a bit wary about with regards to making the user pass the timerForClose is twofold:

  • they may not really know how long they would need to wait (they may be using a third party library/have other conditions that may introduce variable timings to said menu closure). They could of course finagle that timing but I do like how using waitFor under the hood reduces the burden on the user to get the timing right.
  • API consistency: introducing timerForClose may open the need/possibility of adding the same kind of api to many of the other interaction calls in the utils. Perhaps it would be best for the user to perform their own polling after calling selectOption instead? Perhaps we could expect that they should await focus to return to a specific element outside of the util instead

Copy link
Member

Choose a reason for hiding this comment

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

Ah, didn't know it would advance fakeTimers, that's great, then I think this is fine

Comment on lines -624 to -625
// TODO: not ideal, this runAllTimers is only needed for RSPv3, not RAC or S2
act(() => {jest.runAllTimers();});
Copy link
Member Author

@LFDanLu LFDanLu Apr 2, 2025

Choose a reason for hiding this comment

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

no longer needed after a selectOption call due to the chain of waitFors, seems to work fine for various levels of open menus but will extensive testing to see if it is too brittle or not

@LFDanLu LFDanLu marked this pull request as ready for review April 2, 2025 22:31
@LFDanLu LFDanLu changed the title fix: (WIP) Support React 19 and remove Jest reliance in test utils fix: Support React 19 and remove Jest reliance in test utils Apr 2, 2025
@rspbot
Copy link

rspbot commented Apr 2, 2025

@rspbot
Copy link

rspbot commented Apr 2, 2025

@LFDanLu LFDanLu added the release label Apr 3, 2025
@@ -31,7 +31,7 @@ let columns = [
describe('Table ', function () {
let onSelectionChange = jest.fn();
let onSortChange = jest.fn();
let testUtilRealTimer = new User();
let testUtilRealTimer = new User({advanceTimer: async (waitTime) => await new Promise((resolve) => setTimeout(resolve, waitTime))});
Copy link
Member

@snowystinger snowystinger Apr 3, 2025

Choose a reason for hiding this comment

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

why async? does it not need an 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.

yeah it doesn't need the async await here, copy pasta from Analytic's real timer wait util just to mimic their setup as closely as possible to make sure the test-utils would work with their setup. The act happens by whatever calls advanceTimer aka

await act(async () => await advanceTimer(DEFAULT_LONG_PRESS_TIME));

snowystinger
snowystinger previously approved these changes Apr 4, 2025
@rspbot
Copy link

rspbot commented Apr 8, 2025

@rspbot
Copy link

rspbot commented Apr 8, 2025

## API Changes

@react-aria/test-utils

/@react-aria/test-utils:triggerLongPress

 triggerLongPress {
   opts: {
     element: HTMLElement
-  advanceTimer: (number) => void | Promise<unknown>
+  advanceTimer: (number) => unknown | Promise<unknown>
   pointerOpts?: Record<string, any>
 }
   returnVal: undefined
 }

/@react-aria/test-utils:UserOpts

 UserOpts {
-  advanceTimer?: (number) => void | Promise<unknown>
+  advanceTimer?: (number) => unknown | Promise<unknown>
   interactionType?: 'mouse' | 'touch' | 'keyboard' = mouse
 }

@react-spectrum/test-utils

/@react-spectrum/test-utils:triggerLongPress

 triggerLongPress {
   opts: {
     element: HTMLElement
-  advanceTimer: (number) => void | Promise<unknown>
+  advanceTimer: (number) => unknown | Promise<unknown>
   pointerOpts?: Record<string, any>
 }
   returnVal: undefined
 }

/@react-spectrum/test-utils:UserOpts

 UserOpts {
-  advanceTimer?: (number) => void | Promise<unknown>
+  advanceTimer?: (number) => unknown | Promise<unknown>
   interactionType?: 'mouse' | 'touch' | 'keyboard' = mouse
 }

@LFDanLu LFDanLu added this pull request to the merge queue Apr 8, 2025
Merged via the queue into main with commit a654a33 Apr 8, 2025
30 checks passed
@LFDanLu LFDanLu deleted the test_util_bug_fixes branch April 8, 2025 21:31
ritz078 added a commit to PSPDFKit-labs/react-spectrum that referenced this pull request Apr 10, 2025
* chore: Fix generated code sample for S2 TooltipTrigger docs (adobe#8000)

* Fix generated code sample for S2 TooltipTrigger docs

* review

* inlining

* fix: export SortDescriptor type from S2 (adobe#8030)

* chore: Deprecate UNSTABLE_portalContainer in favor for PortalProvider (adobe#7976)

* Initial refactor to tear out UNSTABLE_portalContainer in favor of the PortalContainer

* yarn.lock update

* switch to deprecating UNSTABLE_portalContainer

* prefer deprecated prop over context to make this a non-breaking change

* add rough docs

* updating copy to include explaination of UNSTABLE

* rename to UNSAFE_PortalProvider

* update copy and split out example

* use styles from RAC examples

---------

Co-authored-by: Robert Snow <[email protected]>

* feat: Add escapeKeyBehavior to GridList/ListBox/Menu/Table/Tree (adobe#7974)

* Add disallowClearAll to Menu/ListBox so Autocomplete in Popover can close without clearing selection

* add support for diallowClearAll to grid/tree/table

* make sure RSP components also surface disallowClearAll

* update api naming to escapeKeyBehavior

* skip 17 tests for build, investigate later

* review comments

* fix: useMove broken by NODE_ENV check (adobe#8046)

* fix: ColorWheel track click (adobe#8049)

* fix: minor typo in CalendarDate docs (adobe#8043)

* fix: minor typo in CalendarDate docs

* fix second example as well

---------

Co-authored-by: Robert Snow <[email protected]>

* fix: Updating collection when items change parents (adobe#8052)

* export Autocomplete from S2 (adobe#8050)

* chore: Optimize table test performance (adobe#8051)

* chore: Update typescript to 5.8 (adobe#7888)

* chore: update typescript to 5.8

* fix all the types for the upgrade

* fix numberfield styles

* fix: Apply touch-action by default in usePress (adobe#8047)

* fix: Apply touch-action by default in usePress

* fix test

---------

Co-authored-by: Daniel Lu <[email protected]>

* fix: set some better flex behaviour (adobe#8048)

* fix: Support React 19 and remove Jest reliance in test utils (adobe#7686)

* attempt to get rid of jest calls in menu util

* update RSP testing docs to directly mention mocks that maybe needed

* bump versions of RTL to 16

* use alternative to calling jest run timers in menu option selection

* fixing types and properly testing long press

* fix lint

* revert to pre testing library bump for clean slate

* fix build and another submenu edge case

now we shouldnt need to call runAllTimers after selectOption

* fix react 16 bug

* update return type of advanceTimer and docs copy

* move some general fixes from selectionMode="replace" branch here

* get rid of unneeded async

* getting rid of extraneous dep

* fix lint

* chore: revert ts update (adobe#8060)

* fix: add static color to s2 notification badge (adobe#8055)

* fix: add static color to s2 notification badge

* make opaque

* updates

* use locale

* fix lint

---------

Co-authored-by: Robert Snow <[email protected]>

* chore: Latest translations (adobe#8036)

* Latest translations

* Translation correction

* Couple of translation corrections

* Remove å from Norwegian string

---------

Co-authored-by: Yihui Liao <[email protected]>

* fix: Relax Parcel version range in public plugins (adobe#8067)

* Disclosure button label size update to match new sizes from Specturm (adobe#8006)

Co-authored-by: Danni <[email protected]>

* chore: audit 3.41 (adobe#8064)

* chore: audit 3.41

* remove deprecation

* chore: audit 3.41 (adobe#8064)

* chore: audit 3.41

* remove deprecation

* chore: Update package dependencies for @react-aria/overlays and @react-aria-components

* Added @react-aria/ssr and updated @react-aria/overlays in @react-aria/overlays package.json
* Added @react-aria/overlays, @react-aria/ssr, and @react-aria/utils in @react-aria-components package.json

* chore: Update import paths and dependencies for @react-aria-nutrient

* Refactored import statements in various components and tests to use @react-aria-nutrient/overlays instead of @react-aria/overlays.
* Removed references to @react-aria/overlays from package.json and yarn.lock.
* Updated documentation links to reflect the new package structure.

* chore: Update import paths in TableTests to use @react-aria-nutrient

* Refactored import statements in TableTests.js to replace @react-aria with @react-aria-nutrient for live-announcer, utils, and focus modules.
* Ensured consistency with recent package structure changes.

* fix: Add missing newline at end of test files

* Ensured proper formatting by adding a newline at the end of Table.test.js and TestTableUtils.test.tsx files to comply with best practices.

---------

Co-authored-by: Daniel Lu <[email protected]>
Co-authored-by: Trevor Howell <[email protected]>
Co-authored-by: Robert Snow <[email protected]>
Co-authored-by: Devon Govett <[email protected]>
Co-authored-by: DarkstarXDD <[email protected]>
Co-authored-by: Robert Snow <[email protected]>
Co-authored-by: Reid Barber <[email protected]>
Co-authored-by: Yihui Liao <[email protected]>
Co-authored-by: Richard Geraghty <[email protected]>
Co-authored-by: Kyle Taborski <[email protected]>
Co-authored-by: Danni <[email protected]>
ritz078 added a commit to PSPDFKit-labs/react-spectrum that referenced this pull request Apr 10, 2025
* chore: Fix generated code sample for S2 TooltipTrigger docs (adobe#8000)

* Fix generated code sample for S2 TooltipTrigger docs

* review

* inlining

* fix: export SortDescriptor type from S2 (adobe#8030)

* chore: Deprecate UNSTABLE_portalContainer in favor for PortalProvider (adobe#7976)

* Initial refactor to tear out UNSTABLE_portalContainer in favor of the PortalContainer

* yarn.lock update

* switch to deprecating UNSTABLE_portalContainer

* prefer deprecated prop over context to make this a non-breaking change

* add rough docs

* updating copy to include explaination of UNSTABLE

* rename to UNSAFE_PortalProvider

* update copy and split out example

* use styles from RAC examples

---------

Co-authored-by: Robert Snow <[email protected]>

* feat: Add escapeKeyBehavior to GridList/ListBox/Menu/Table/Tree (adobe#7974)

* Add disallowClearAll to Menu/ListBox so Autocomplete in Popover can close without clearing selection

* add support for diallowClearAll to grid/tree/table

* make sure RSP components also surface disallowClearAll

* update api naming to escapeKeyBehavior

* skip 17 tests for build, investigate later

* review comments

* fix: useMove broken by NODE_ENV check (adobe#8046)

* fix: ColorWheel track click (adobe#8049)

* fix: minor typo in CalendarDate docs (adobe#8043)

* fix: minor typo in CalendarDate docs

* fix second example as well

---------

Co-authored-by: Robert Snow <[email protected]>

* fix: Updating collection when items change parents (adobe#8052)

* export Autocomplete from S2 (adobe#8050)

* chore: Optimize table test performance (adobe#8051)

* chore: Update typescript to 5.8 (adobe#7888)

* chore: update typescript to 5.8

* fix all the types for the upgrade

* fix numberfield styles

* fix: Apply touch-action by default in usePress (adobe#8047)

* fix: Apply touch-action by default in usePress

* fix test

---------

Co-authored-by: Daniel Lu <[email protected]>

* fix: set some better flex behaviour (adobe#8048)

* fix: Support React 19 and remove Jest reliance in test utils (adobe#7686)

* attempt to get rid of jest calls in menu util

* update RSP testing docs to directly mention mocks that maybe needed

* bump versions of RTL to 16

* use alternative to calling jest run timers in menu option selection

* fixing types and properly testing long press

* fix lint

* revert to pre testing library bump for clean slate

* fix build and another submenu edge case

now we shouldnt need to call runAllTimers after selectOption

* fix react 16 bug

* update return type of advanceTimer and docs copy

* move some general fixes from selectionMode="replace" branch here

* get rid of unneeded async

* getting rid of extraneous dep

* fix lint

* chore: revert ts update (adobe#8060)

* fix: add static color to s2 notification badge (adobe#8055)

* fix: add static color to s2 notification badge

* make opaque

* updates

* use locale

* fix lint

---------

Co-authored-by: Robert Snow <[email protected]>

* chore: Latest translations (adobe#8036)

* Latest translations

* Translation correction

* Couple of translation corrections

* Remove å from Norwegian string

---------

Co-authored-by: Yihui Liao <[email protected]>

* fix: Relax Parcel version range in public plugins (adobe#8067)

* Disclosure button label size update to match new sizes from Specturm (adobe#8006)

Co-authored-by: Danni <[email protected]>

* chore: audit 3.41 (adobe#8064)

* chore: audit 3.41

* remove deprecation

* chore: audit 3.41 (adobe#8064)

* chore: audit 3.41

* remove deprecation

* chore: Update package dependencies for @react-aria/overlays and @react-aria-components

* Added @react-aria/ssr and updated @react-aria/overlays in @react-aria/overlays package.json
* Added @react-aria/overlays, @react-aria/ssr, and @react-aria/utils in @react-aria-components package.json

* chore: Update import paths and dependencies for @react-aria-nutrient

* Refactored import statements in various components and tests to use @react-aria-nutrient/overlays instead of @react-aria/overlays.
* Removed references to @react-aria/overlays from package.json and yarn.lock.
* Updated documentation links to reflect the new package structure.

* chore: Update import paths in TableTests to use @react-aria-nutrient

* Refactored import statements in TableTests.js to replace @react-aria with @react-aria-nutrient for live-announcer, utils, and focus modules.
* Ensured consistency with recent package structure changes.

* fix: Add missing newline at end of test files

* Ensured proper formatting by adding a newline at the end of Table.test.js and TestTableUtils.test.tsx files to comply with best practices.

---------

Co-authored-by: Daniel Lu <[email protected]>
Co-authored-by: Trevor Howell <[email protected]>
Co-authored-by: Robert Snow <[email protected]>
Co-authored-by: Devon Govett <[email protected]>
Co-authored-by: DarkstarXDD <[email protected]>
Co-authored-by: Robert Snow <[email protected]>
Co-authored-by: Reid Barber <[email protected]>
Co-authored-by: Yihui Liao <[email protected]>
Co-authored-by: Richard Geraghty <[email protected]>
Co-authored-by: Kyle Taborski <[email protected]>
Co-authored-by: Danni <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

test-utils for menu interactions cannot work without Jest
4 participants