Skip to content

chore: upgrade dev dependencies to React 18.2#3410

Open
talkor wants to merge 5 commits into
masterfrom
chore/react-18-dev-upgrade
Open

chore: upgrade dev dependencies to React 18.2#3410
talkor wants to merge 5 commits into
masterfrom
chore/react-18-dev-upgrade

Conversation

@talkor

@talkor talkor commented Jun 28, 2026

Copy link
Copy Markdown
Member

Summary

  • Upgrade devDependencies across all 16 packages to React 18.2 while keeping peerDependencies at >=16.9.0 — consumers on React 16/17/18 continue to work
  • Upgrade @testing-library/react from v12 to v14, remove deprecated @testing-library/react-hooks
  • Remove dead @hot-loader/react-dom dependency
  • Fix act() wrapping in tests for React 18's stricter automatic batching
  • Update snapshots for React 18 output differences
  • Zero source code changes — library code remains agnostic, no React 18+ APIs used

Motivation

Modernize dev tooling (Storybook, test runner) to React 18 for better DX while preserving backward compatibility for consumers still on React 16/17.

Test plan

  • All 1594 tests pass across 14 packages
  • Storybook starts and renders correctly
  • CI passes
  • Spot-check component stories in Storybook

🤖 Generated with Claude Code

Upgrade devDependencies across all packages to React 18.2 while keeping
peerDependencies at >=16.9.0 for consumer compatibility. No source code
changes — library remains compatible with React 16/17/18.

- Bump react/react-dom devDeps from ^16.x to ^18.2.0 (16 packages)
- Upgrade @testing-library/react from ^12 to ^14
- Remove deprecated @testing-library/react-hooks (merged into @testing-library/react)
- Remove @hot-loader/react-dom (unused with Vite tooling)
- Bump react-is to ^18.2.0
- Fix act() wrapping in tests for React 18 automatic batching
- Update snapshots for React 18 output
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Analysis

Changed Components

Component Base PR Diff
@vibe/dialog 52.19KB 55.82KB +3.63KB 🔺
@vibe/icon-button 66.25KB 69.72KB +3.47KB 🔺
@vibe/tooltip 61.34KB 64.89KB +3.56KB 🔺
@vibe/typography 63.45KB 67.05KB +3.6KB 🔺
AccordionItem 66.53KB 69.97KB +3.44KB 🔺
AlertBanner 70.9KB 74.48KB +3.58KB 🔺
AlertBannerText 63.97KB 67.54KB +3.57KB 🔺
AttentionBox 74.36KB 77.87KB +3.51KB 🔺
Avatar 66.78KB 70.2KB +3.42KB 🔺
AvatarGroup 93.28KB 97.04KB +3.76KB 🔺
Badge 43.15KB 46.79KB +3.63KB 🔺
BreadcrumbItem 64.7KB 68.29KB +3.59KB 🔺
BreadcrumbMenu 68.63KB 72.28KB +3.65KB 🔺
BreadcrumbMenuItem 77.18KB 80.71KB +3.53KB 🔺
ButtonGroup 68.35KB 72.02KB +3.67KB 🔺
Checkbox 66.91KB 70.38KB +3.47KB 🔺
Chips 75.03KB 78.73KB +3.7KB 🔺
ColorPicker 74.55KB 78.11KB +3.56KB 🔺
ColorPickerContent 73.73KB 77.36KB +3.62KB 🔺
Combobox 84.06KB 87.61KB +3.55KB 🔺
Counter 42.23KB 45.82KB +3.59KB 🔺
DatePicker 112.47KB 116.01KB +3.54KB 🔺
Dropdown 95.25KB 98.89KB +3.64KB 🔺
EditableHeading 66.69KB 70.15KB +3.46KB 🔺
EditableText 66.51KB 70.03KB +3.52KB 🔺
EmptyState 70.43KB 74.13KB +3.7KB 🔺
ExpandCollapse 66.27KB 69.92KB +3.65KB 🔺
Info 72.15KB 75.7KB +3.55KB 🔺
Label 68.64KB 72.18KB +3.54KB 🔺
List 72.99KB 76.48KB +3.5KB 🔺
ListItem 65.58KB 69.13KB +3.56KB 🔺
ListItemAvatar 66.93KB 70.43KB +3.5KB 🔺
ListTitle 65.04KB 68.68KB +3.64KB 🔺
MenuItem 76.97KB 80.51KB +3.54KB 🔺
MenuItemButton 69.99KB 73.65KB +3.66KB 🔺
MenuTitle 65.35KB 68.9KB +3.56KB 🔺
MenuButton 66.07KB 69.75KB +3.68KB 🔺
Modal 79.17KB 82.77KB +3.6KB 🔺
ModalHeader 65.83KB 69.36KB +3.53KB 🔺
ModalFooter 67.8KB 71.3KB +3.49KB 🔺
ModalFooterWizard 68.7KB 72.16KB +3.46KB 🔺
MultiStepIndicator 52.91KB 56.52KB +3.61KB 🔺
NumberField 72.83KB 76.55KB +3.72KB 🔺
RadioButton 65.92KB 69.44KB +3.52KB 🔺
Search 70.64KB 74.1KB +3.46KB 🔺
Slider 73.93KB 77.45KB +3.52KB 🔺
SplitButton 66.57KB 70.15KB +3.57KB 🔺
Steps 71.43KB 74.96KB +3.53KB 🔺
TableBody 66.8KB 70.35KB +3.55KB 🔺
TableCell 65.22KB 68.81KB +3.59KB 🔺
TableHeaderCell 72.28KB 75.72KB +3.44KB 🔺
TableRowMenu 68.81KB 72.56KB +3.75KB 🔺
TableVirtualizedBody 71.44KB 75KB +3.57KB 🔺
Tab 64.04KB 67.6KB +3.56KB 🔺
TextArea 66.4KB 69.9KB +3.5KB 🔺
TextField 69.44KB 72.94KB +3.5KB 🔺
TextWithHighlight 64.35KB 67.99KB +3.64KB 🔺
Tipseen 71.18KB 74.8KB +3.62KB 🔺
TipseenContent 71.62KB 75.25KB +3.63KB 🔺
TipseenMedia 71.37KB 74.93KB +3.56KB 🔺
TipseenWizard 73.96KB 77.38KB +3.42KB 🔺
Toast 74.05KB 77.56KB +3.51KB 🔺
Toggle 66.63KB 70.23KB +3.6KB 🔺
ListItem (Next) 69.95KB 73.46KB +3.51KB 🔺
ListTitle (Next) 65.3KB 68.89KB +3.59KB 🔺
Unchanged Components
Component Base PR Diff
@vibe/button 17.31KB 16.95KB -378B 🟢
@vibe/clickable 5.97KB 5.58KB -394B 🟢
@vibe/icon 12.93KB 12.57KB -369B 🟢
@vibe/layer 2.97KB 2.59KB -385B 🟢
@vibe/layout 9.86KB 9.53KB -334B 🟢
@vibe/loader 5.67KB 5.31KB -377B 🟢
Accordion 6.31KB 5.96KB -353B 🟢
AlertBannerButton 18.77KB 18.46KB -317B 🟢
AlertBannerLink 15.3KB 14.92KB -382B 🟢
BreadcrumbsBar 5.7KB 5.37KB -332B 🟢
Divider 5.43KB 5.11KB -334B 🟢
FormattedNumber 5.84KB 5.47KB -378B 🟢
GridKeyboardNavigationContext 4.66KB 4.3KB -366B 🟢
HiddenText 5.42KB 5.05KB -375B 🟢
Link 14.87KB 14.52KB -357B 🟢
ListItemIcon 14.02KB 13.64KB -385B 🟢
Menu 8.64KB 8.29KB -363B 🟢
MenuDivider 5.54KB 5.22KB -329B 🟢
MenuGridItem 7.21KB 6.82KB -399B 🟢
ModalContent 4.73KB 4.35KB -383B 🟢
ModalMedia 7.51KB 7.19KB -319B 🟢
ModalBasicLayout 8.92KB 8.6KB -324B 🟢
ModalMediaLayout 8.08KB 7.74KB -347B 🟢
ModalSideBySideLayout 6.33KB 6KB -340B 🟢
ProgressBar 7.33KB 6.99KB -350B 🟢
Skeleton 6KB 5.69KB -317B 🟢
SplitButtonMenu 8.8KB 8.45KB -358B 🟢
Table 7.26KB 6.92KB -351B 🟢
TableContainer 5.31KB 4.96KB -365B 🟢
TableHeader 5.66KB 5.3KB -362B 🟢
TableRow 5.55KB 5.21KB -350B 🟢
TabList 8.88KB 8.53KB -359B 🟢
TabPanel 5.3KB 4.96KB -343B 🟢
TabPanels 5.89KB 5.52KB -376B 🟢
TabsContext 5.47KB 5.12KB -367B 🟢
ThemeProvider 4.37KB 4.06KB -320B 🟢
ToastButton 18.64KB 18.27KB -377B 🟢
ToastLink 15.14KB 14.8KB -352B 🟢
TransitionView 5.46KB 5.09KB -370B 🟢
VirtualizedGrid 12.55KB 12.21KB -348B 🟢
VirtualizedList 12.26KB 11.95KB -319B 🟢
List (Next) 8.19KB 7.84KB -362B 🟢

📊 Summary:

  • Total Base Size: 4.76MB
  • Total PR Size: 4.97MB
  • Total Difference: +217.3KB

⚠️ Significant size change detected! Please review the changes carefully.

talkor added 2 commits June 28, 2026 15:31
- react-is is a runtime dependency bundled into output — keep at v16
  to avoid +3.5KB per component (symbols are stable across React versions)
- Wrap interaction test DOM assertions in waitFor() for React 18 batching
Import expect and waitFor from @storybook/test (unified module) instead
of separate @storybook/jest import.
@talkor talkor marked this pull request as ready for review June 28, 2026 14:05
@talkor talkor requested a review from a team as a code owner June 28, 2026 14:05
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Invalid renderHook ReturnType typing 📘 Rule violation ≡ Correctness ⭐ New
Description
useDebounceEvent.test.ts declares hookResult as `ReturnType<typeof
renderHook<UseDebounceResult>>, but applying generic type arguments inside a typeof` type query is
invalid TypeScript and can fail the test build/typecheck. This risks breaking CI and undermines the
reliability of the migrated React 18 test suite.
Code

packages/core/src/hooks/tests/useDebounceEvent.test.ts[10]

+  let hookResult: ReturnType<typeof renderHook<UseDebounceResult>>;
Evidence
The change introduces the annotation ReturnType<typeof renderHook<UseDebounceResult>>, which is
not valid because TypeScript does not allow supplying type arguments (<UseDebounceResult>) within
a typeof renderHook type query, so it can produce a compile-time type error and prevent the tests
from compiling/running (violating the requirement that tests remain reliable). The variable is
subsequently used as the object returned by renderHook (e.g., via hookResult.result.current),
indicating it should be typed as a renderHook result/RenderHookResult-shaped value rather than
using an invalid ReturnType expression.

CLAUDE.md: Tests must verify real behavior and accessibility attributes and follow established test ID patterns
packages/core/src/hooks/tests/useDebounceEvent.test.ts[10-10]
packages/core/src/hooks/tests/useDebounceEvent.test.ts[1-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`packages/core/src/hooks/__tests__/useDebounceEvent.test.ts` types `hookResult` as `ReturnType<typeof renderHook<UseDebounceResult>>`, but generic parameters cannot be applied inside a `typeof` type query, making this invalid TypeScript syntax. This can break TypeScript compilation of the test suite and block CI.

## Issue Context
This PR migrates hook tests from `@testing-library/react-hooks` to `@testing-library/react`, and the intent is to correctly type the value returned by `renderHook(...)` while keeping the tests reliable under the React 18 tooling upgrade.

## Fix Focus Areas
- packages/core/src/hooks/__tests__/useDebounceEvent.test.ts[10-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Slider thumbs queried too early 🐞 Bug ☼ Reliability
Description
sliderTestUtils replaced findBy* with immediate getBy* for slider thumbs even though
SliderBase only renders thumbs after railRef.current becomes available and a mount effect
triggers a rerender. This can make slider tests intermittently fail when the post-mount rerender is
delayed or timing differs across environments.
Code

packages/core/src/components/Slider/tests/sliderTestUtils.tsx[R7-17]

+export function renderSliderInNonRangeMode(props = {}) {
 const renderResult = render(<Slider aria-label={SLIDER_LABEL} defaultValue={20} {...props} />);
-  // noinspection JSCheckFunctionSignatures
-  const elThumb = await screen.findByLabelText(SLIDER_LABEL);
+  const elThumb = screen.getByLabelText(SLIDER_LABEL);
 return { ...renderResult, elThumb };
}

-export async function renderSliderInRangeMode(props = {}) {
+export function renderSliderInRangeMode(props = {}) {
 const renderResult = render(<Slider ranged={true} defaultValue={[25, 65]} {...props} />);
-  // noinspection JSCheckFunctionSignatures
-  const elThumbStart = await screen.findByTestId("monday-slider__thumb-0");
-  // noinspection JSCheckFunctionSignatures
-  const elThumbEnd = await screen.findByTestId("monday-slider__thumb-1");
+  const elThumbStart = screen.getByTestId("monday-slider__thumb-0");
+  const elThumbEnd = screen.getByTestId("monday-slider__thumb-1");
 return { ...renderResult, elThumbStart, elThumbEnd };
Evidence
The test utils now require the thumb nodes synchronously, but SliderBase conditionally renders
thumbs only when railRef.current is truthy, and useSliderRail only triggers a rerender after a
mount effect calls setRailCoords(). This establishes that thumb presence depends on post-mount
timing, not just the initial render.

packages/core/src/components/Slider/tests/sliderTestUtils.tsx[7-23]
packages/core/src/components/Slider/SliderBase/SliderBase.tsx[87-105]
packages/core/src/components/Slider/SliderHooks.ts[183-207]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`renderSliderInNonRangeMode`, `renderSliderInRangeMode`, and `renderSliderForSnapshots` now use synchronous `screen.getBy*` queries for elements that may not exist until after mount effects/state updates run. This creates timing sensitivity and potential CI flakes.
### Issue Context
In `SliderBase`, thumbs are rendered only when `railRef.current` is set, and `useSliderRail()` uses a `useEffect` + `setRailCoords()` update to trigger a rerender after mount.
### Fix
Make the helper functions async again (or add an awaited `waitFor`) and use `await screen.findByLabelText/findByTestId(...)` to wait until the thumbs are present.
### Fix Focus Areas
- packages/core/src/components/Slider/__tests__/sliderTestUtils.tsx[7-23]
- packages/core/src/components/Slider/SliderBase/SliderBase.tsx[87-105]
- packages/core/src/components/Slider/SliderHooks.ts[183-207]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. User events no longer awaited 🐞 Bug ☼ Reliability
Description
Several tests were converted from async (findBy*/waitFor + await userEvent.*) to synchronous
getBy* assertions while still relying on event-driven/timer-driven UI updates. This can cause
assertions to run before React commits the resulting updates, creating flaky tests under React 18’s
batching/scheduling.
Code

packages/components/dialog/src/Dialog/tests/Dialog.test.tsx[R104-110]

     const button = within(container).getByText("Click Me");
-      await userEvent.click(button);
-      vi.runAllTimers();
+      userEvent.click(button);
+      act(() => {
+        vi.runAllTimers();
+      });

-      await waitFor(() => expect(screen.getByText("Dialog Content")).toBeInTheDocument());
+      expect(screen.getByText("Dialog Content")).toBeInTheDocument();
Evidence
The updated tests perform userEvent interactions (click/hover) and then immediately perform
synchronous getBy* assertions after manually advancing timers, which assumes all
interaction-driven React updates are committed by that point. The code shows multiple such patterns
introduced by the PR’s refactor.

packages/components/dialog/src/Dialog/tests/Dialog.test.tsx[95-129]
packages/core/src/components/SplitButton/tests/SplitButton.test.tsx[46-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Tests now trigger interactions with `userEvent` but do not await the interaction completion and removed `waitFor/findBy*` usage. When combined with timers/state updates, this can race with React committing updates, leading to flaky assertions.
### Issue Context
Example: dialog show/hide trigger tests call `userEvent.click/hover` and then immediately assert after `runAllTimers`, without awaiting the event sequence itself.
### Fix
- Use `const user = userEvent.setup(...)` and `await user.click(...)` / `await user.hover(...)`.
- Keep tests `async` where needed.
- If fake timers are used, configure `userEvent.setup({ advanceTimers: vi.advanceTimersByTime })` (or the project’s equivalent) and await the user actions.
- Prefer `findBy*`/`waitFor` when asserting on DOM changes caused by async state updates.
### Fix Focus Areas
- packages/components/dialog/src/Dialog/__tests__/Dialog.test.tsx[95-129]
- packages/core/src/components/SplitButton/__tests__/SplitButton.test.tsx[46-72]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit c9caf40

Results up to commit 7b8d156


🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)


Remediation recommended
1. Slider thumbs queried too early 🐞 Bug ☼ Reliability
Description
sliderTestUtils replaced findBy* with immediate getBy* for slider thumbs even though
SliderBase only renders thumbs after railRef.current becomes available and a mount effect
triggers a rerender. This can make slider tests intermittently fail when the post-mount rerender is
delayed or timing differs across environments.
Code

packages/core/src/components/Slider/tests/sliderTestUtils.tsx[R7-17]

+export function renderSliderInNonRangeMode(props = {}) {
  const renderResult = render(<Slider aria-label={SLIDER_LABEL} defaultValue={20} {...props} />);
-  // noinspection JSCheckFunctionSignatures
-  const elThumb = await screen.findByLabelText(SLIDER_LABEL);
+  const elThumb = screen.getByLabelText(SLIDER_LABEL);
  return { ...renderResult, elThumb };
}

-export async function renderSliderInRangeMode(props = {}) {
+export function renderSliderInRangeMode(props = {}) {
  const renderResult = render(<Slider ranged={true} defaultValue={[25, 65]} {...props} />);
-  // noinspection JSCheckFunctionSignatures
-  const elThumbStart = await screen.findByTestId("monday-slider__thumb-0");
-  // noinspection JSCheckFunctionSignatures
-  const elThumbEnd = await screen.findByTestId("monday-slider__thumb-1");
+  const elThumbStart = screen.getByTestId("monday-slider__thumb-0");
+  const elThumbEnd = screen.getByTestId("monday-slider__thumb-1");
  return { ...renderResult, elThumbStart, elThumbEnd };
Evidence
The test utils now require the thumb nodes synchronously, but SliderBase conditionally renders
thumbs only when railRef.current is truthy, and useSliderRail only triggers a rerender after a
mount effect calls setRailCoords(). This establishes that thumb presence depends on post-mount
timing, not just the initial render.

packages/core/src/components/Slider/tests/sliderTestUtils.tsx[7-23]
packages/core/src/components/Slider/SliderBase/SliderBase.tsx[87-105]
packages/core/src/components/Slider/SliderHooks.ts[183-207]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`renderSliderInNonRangeMode`, `renderSliderInRangeMode`, and `renderSliderForSnapshots` now use synchronous `screen.getBy*` queries for elements that may not exist until after mount effects/state updates run. This creates timing sensitivity and potential CI flakes.

### Issue Context
In `SliderBase`, thumbs are rendered only when `railRef.current` is set, and `useSliderRail()` uses a `useEffect` + `setRailCoords()` update to trigger a rerender after mount.

### Fix
Make the helper functions async again (or add an awaited `waitFor`) and use `await screen.findByLabelText/findByTestId(...)` to wait until the thumbs are present.

### Fix Focus Areas
- packages/core/src/components/Slider/__tests__/sliderTestUtils.tsx[7-23]
- packages/core/src/components/Slider/SliderBase/SliderBase.tsx[87-105]
- packages/core/src/components/Slider/SliderHooks.ts[183-207]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. User events no longer awaited 🐞 Bug ☼ Reliability
Description
Several tests were converted from async (findBy*/waitFor + await userEvent.*) to synchronous
getBy* assertions while still relying on event-driven/timer-driven UI updates. This can cause
assertions to run before React commits the resulting updates, creating flaky tests under React 18’s
batching/scheduling.
Code

packages/components/dialog/src/Dialog/tests/Dialog.test.tsx[R104-110]

      const button = within(container).getByText("Click Me");
-      await userEvent.click(button);
-      vi.runAllTimers();
+      userEvent.click(button);
+      act(() => {
+        vi.runAllTimers();
+      });

-      await waitFor(() => expect(screen.getByText("Dialog Content")).toBeInTheDocument());
+      expect(screen.getByText("Dialog Content")).toBeInTheDocument();
Evidence
The updated tests perform userEvent interactions (click/hover) and then immediately perform
synchronous getBy* assertions after manually advancing timers, which assumes all
interaction-driven React updates are committed by that point. The code shows multiple such patterns
introduced by the PR’s refactor.

packages/components/dialog/src/Dialog/tests/Dialog.test.tsx[95-129]
packages/core/src/components/SplitButton/tests/SplitButton.test.tsx[46-72]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Tests now trigger interactions with `userEvent` but do not await the interaction completion and removed `waitFor/findBy*` usage. When combined with timers/state updates, this can race with React committing updates, leading to flaky assertions.

### Issue Context
Example: dialog show/hide trigger tests call `userEvent.click/hover` and then immediately assert after `runAllTimers`, without awaiting the event sequence itself.

### Fix
- Use `const user = userEvent.setup(...)` and `await user.click(...)` / `await user.hover(...)`.
- Keep tests `async` where needed.
- If fake timers are used, configure `userEvent.setup({ advanceTimers: vi.advanceTimersByTime })` (or the project’s equivalent) and await the user actions.
- Prefer `findBy*`/`waitFor` when asserting on DOM changes caused by async state updates.

### Fix Focus Areas
- packages/components/dialog/src/Dialog/__tests__/Dialog.test.tsx[95-129]
- packages/core/src/components/SplitButton/__tests__/SplitButton.test.tsx[46-72]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

…test

The hook checks document.activeElement against focusedElementRef.current
(the inner input). The test was focusing the Search wrapper div found by
test-id, which doesn't match — causing the hook to early-return without
updating visual focus.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

chore: upgrade dev React to 18.2 + Testing Library v14; fix React 18 test timing
⚙️ Configuration changes 🧪 Tests 🕐 40+ Minutes

Grey Divider

Description

• Upgrade package-level devDependencies to React/ReactDOM 18.2 and @testing-library/react v14.
• Remove deprecated @testing-library/react-hooks and unused @hot-loader/react-dom.
• Stabilize tests for React 18 batching by tightening act()/timer usage and updating snapshots.
Diagram

graph TD
  A["Monorepo packages"] --> B["package.json devDeps"] --> C["React 18.2 (dev)"] --> D["Vitest + RTL"] --> G["Updated tests & snapshots"]
  B --> E["@testing-library/react v14"] --> D
  E --> F["@storybook/test (waitFor)"] --> D
  B --> H["Removed deprecated deps"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize React devDeps at the workspace root
  • ➕ Avoids repeating React/react-dom/react-test-renderer across many package.json files
  • ➕ Reduces risk of version skew between packages during local testing
  • ➖ May break package-local test setups that rely on direct devDeps
  • ➖ Some tooling/publishing workflows expect per-package devDependencies
2. Keep @testing-library/react v12 and pin React 16/17 for tests
  • ➕ Minimizes test churn and snapshot changes
  • ➕ Lower short-term risk of timing regressions
  • ➖ Blocks modernization of Storybook/testing ecosystem
  • ➖ Leaves deprecated packages in place (@testing-library/react-hooks)
3. Raise peerDependencies to include React 18 explicitly
  • ➕ Communicates React 18 support more clearly to consumers
  • ➕ May reduce consumer-side mismatch warnings
  • ➖ Contradicts the stated goal of keeping compatibility for React 16/17 consumers
  • ➖ Could force dependency resolution changes for downstream apps

Recommendation: The chosen approach (upgrade devDependencies while keeping peerDependencies broad) is the best fit for improving DX without imposing React 18 on consumers. Centralizing devDeps could be a follow-up if the repo wants to reduce duplication, but it’s riskier to do concurrently with the React/RTL upgrade.

Files changed (57) +488 / -496

Tests (41) +426 / -428
Dialog.test.tsxStabilize Dialog tests for React 18 batching with act()+timers +171/-106

Stabilize Dialog tests for React 18 batching with act()+timers

• Reworks many tests to avoid async findBy/waitFor where timers drive state. Wraps timer advancement in @testing-library/react's act() to satisfy React 18 update flushing and reduces flaky scheduling assumptions.

packages/components/dialog/src/Dialog/tests/Dialog.test.tsx

useDisableScroll.test.tsMigrate renderHook import to @testing-library/react +1/-1

Migrate renderHook import to @testing-library/react

• Replaces @testing-library/react-hooks usage with renderHook from @testing-library/react. Keeps the test behavior while removing the deprecated package dependency.

packages/components/dialog/src/Dialog/tests/useDisableScroll.test.ts

Refable.test.tsxConsolidate cleanup import under @testing-library/react +1/-2

Consolidate cleanup import under @testing-library/react

• Stops importing cleanup from @testing-library/react-hooks and uses cleanup from @testing-library/react instead. Maintains existing render/fireEvent usage.

packages/components/dialog/src/Dialog/components/Refable/tests/Refable.test.tsx

useDisableScroll.test.tsMigrate hook test to RTL renderHook +1/-1

Migrate hook test to RTL renderHook

• Updates hook test imports to renderHook from @testing-library/react. Removes reliance on the deprecated @testing-library/react-hooks package.

packages/components/dialog/src/Dialog/hooks/tests/useDisableScroll.test.ts

IconButton.test.tsxAdjust tooltip timing assertions to run inside act() +9/-9

Adjust tooltip timing assertions to run inside act()

• Moves vi.advanceTimersByTime calls into act() blocks to align with React 18 update flushing. Also removes unnecessary async test wrappers where no awaits are required.

packages/components/icon-button/src/IconButton/tests/IconButton.test.tsx

Avatar.test.tsxMove cleanup to @testing-library/react +1/-2

Move cleanup to @testing-library/react

• Removes cleanup import from @testing-library/react-hooks and uses cleanup from @testing-library/react. Keeps existing component test behavior unchanged.

packages/core/src/components/Avatar/tests/Avatar.test.tsx

BreadcrumbMenu.test.tsxRemove waitFor usage in menu open test after timer flush +4/-6

Remove waitFor usage in menu open test after timer flush

• Drops waitFor and async wrapper, relying on act() + vi.runAllTimers to flush updates under React 18. Keeps expectations deterministic after timer execution.

packages/core/src/components/BreadcrumbsBar/BreadcrumbMenu/tests/BreadcrumbMenu.test.tsx

ColorPicker.test.tsxEnsure tooltip timer advancements occur inside act() +3/-3

Ensure tooltip timer advancements occur inside act()

• Moves vi.advanceTimersByTime calls into existing act() blocks for React 18 compliance. Prevents warnings and improves test stability around delayed tooltips.

packages/core/src/components/ColorPicker/tests/ColorPicker.test.tsx

Combobox.test.tsxReplace waitFor with act()+timer flushing for debounced updates +17/-13

Replace waitFor with act()+timer flushing for debounced updates

• Imports act from @testing-library/react and wraps vi.runAllTimers in act() to flush state updates under React 18. Simplifies tests by removing async/waitFor where timers are the driving mechanism.

packages/core/src/components/Combobox/tests/Combobox.test.tsx

GridKeyboardNavigationContext.test.tsxMigrate renderHook/act imports to @testing-library/react +1/-1

Migrate renderHook/act imports to @testing-library/react

• Switches hook testing utilities from @testing-library/react-hooks to @testing-library/react. Retains existing semantics for act(), cleanup, and renderHook.

packages/core/src/components/GridKeyboardNavigationContext/tests/GridKeyboardNavigationContext.test.tsx

Menu.test.tsxConsolidate act import under @testing-library/react +1/-2

Consolidate act import under @testing-library/react

• Removes @testing-library/react-hooks act import and uses act from @testing-library/react instead. Keeps renderer and DOM tests intact while removing deprecated dependency usage.

packages/core/src/components/Menu/Menu/tests/Menu.test.tsx

useAdjacentSelectableMenuIndex.test.tsxSwitch renderHook to @testing-library/react +1/-1

Switch renderHook to @testing-library/react

• Replaces renderHook import from @testing-library/react-hooks with @testing-library/react. Keeps hook behavior assertions unchanged.

packages/core/src/components/Menu/Menu/hooks/tests/useAdjacentSelectableMenuIndex.test.tsx

useFocusOnMount.test.tsxSwitch renderHook to @testing-library/react +1/-1

Switch renderHook to @testing-library/react

• Moves hook test to renderHook from @testing-library/react. Removes usage of deprecated @testing-library/react-hooks.

packages/core/src/components/Menu/Menu/hooks/tests/useFocusOnMount.test.tsx

useLastNavigationDirection.test.tsxMigrate hook test utilities to RTL v14 +1/-1

Migrate hook test utilities to RTL v14

• Imports renderHook and act from @testing-library/react instead of @testing-library/react-hooks. Aligns hook tests with updated testing-library packages.

packages/core/src/components/Menu/Menu/hooks/tests/useLastNavigationDirection.test.tsx

useFocusGridItemByActiveStatus.test.tsMigrate renderHook/cleanup to @testing-library/react +1/-1

Migrate renderHook/cleanup to @testing-library/react

• Switches cleanup and renderHook imports to @testing-library/react. Maintains existing test logic while removing deprecated dependencies.

packages/core/src/components/Menu/MenuGridItem/tests/useFocusGridItemByActiveStatus.test.ts

useMenuGridItemNavContext.test.tsMigrate renderHook/cleanup to @testing-library/react +1/-1

Migrate renderHook/cleanup to @testing-library/react

• Updates hook test imports to come from @testing-library/react. Keeps assertions and context setup unchanged.

packages/core/src/components/Menu/MenuGridItem/tests/useMenuGridItemNavContext.test.ts

useFocusEscapeTargets.test.tsMove hook testing imports to RTL +1/-1

Move hook testing imports to RTL

• Uses renderHook and cleanup from @testing-library/react instead of @testing-library/react-hooks. Keeps the focus escape target behaviors tested as before.

packages/core/src/components/Modal/hooks/useFocusEscapeTargets/tests/useFocusEscapeTargets.test.ts

MultiStepIndicator.test.tsxUse act from @testing-library/react +1/-2

Use act from @testing-library/react

• Replaces @testing-library/react-hooks act import with act from @testing-library/react. Maintains test interactions and assertions.

packages/core/src/components/MultiStepIndicator/tests/MultiStepIndicator.test.tsx

useNumberFieldState.test.tsMigrate renderHook/act to RTL +1/-1

Migrate renderHook/act to RTL

• Switches hook test utilities to @testing-library/react. Removes dependency on @testing-library/react-hooks while preserving behavior.

packages/core/src/components/NumberField/hooks/tests/useNumberFieldState.test.ts

useSpinButtonHandlers.test.tsMigrate renderHook/act to RTL +1/-1

Migrate renderHook/act to RTL

• Uses renderHook and act from @testing-library/react instead of @testing-library/react-hooks. Keeps the spin button handler tests functionally the same.

packages/core/src/components/NumberField/hooks/tests/useSpinButtonHandlers.test.ts

Slider-non-ranged.test.tsxRemove async flows; wrap timer-driven updates in act() +58/-84

Remove async flows; wrap timer-driven updates in act()

• Eliminates async/await usage and relies on synchronous renders plus explicit act() around timer advances for tooltip/keyboard flows. Snapshot expectations are updated to reflect React 18 timing behavior.

packages/core/src/components/Slider/tests/Slider-non-ranged.test.tsx

Slider-ranged.test.tsxRefactor ranged slider tests to be synchronous under React 18 +71/-99

Refactor ranged slider tests to be synchronous under React 18

• Removes async render patterns and uses act() to flush timer-driven tooltip/focus changes. Keeps snapshots and keyboard interaction validations stable with React 18 scheduling.

packages/core/src/components/Slider/tests/Slider-ranged.test.tsx

sliderTestUtils.tsxMake slider test render helpers synchronous (getBy* vs findBy*) +7/-11

Make slider test render helpers synchronous (getBy* vs findBy*)

• Converts render helpers from async findBy* queries to synchronous getBy* queries. Reduces unnecessary async behavior and aligns with explicit act()+timer control in calling tests.

packages/core/src/components/Slider/tests/sliderTestUtils.tsx

SplitButton.test.tsxUse act()+timers instead of waitFor/findByText for dialog/menu +17/-16

Use act()+timers instead of waitFor/findByText for dialog/menu

• Wraps click/keyboard + timer flushing inside act() and replaces findBy*/waitFor with synchronous getBy* queries once timers are run. Improves determinism under React 18 automatic batching.

packages/core/src/components/SplitButton/tests/SplitButton.test.tsx

Steps.test.tsxSwitch act import to @testing-library/react +1/-2

Switch act import to @testing-library/react

• Removes @testing-library/react-hooks act usage and imports act from @testing-library/react. Keeps the rest of the Steps tests unchanged.

packages/core/src/components/Steps/tests/Steps.test.tsx

Tab.test.tsxConsolidate act and timer handling under RTL +3/-4

Consolidate act and timer handling under RTL

• Uses act from @testing-library/react and ensures timer advancement for tooltips happens within act() blocks. Reduces React 18 act warnings and timing flakiness.

packages/core/src/components/Tabs/Tab/tests/Tab.test.tsx

TextField-tests.test.tsxFlush debounced timer updates via act() instead of waitFor +13/-16

Flush debounced timer updates via act() instead of waitFor

• Imports act from @testing-library/react and replaces waitFor-based debounce assertions with act()+advanceTimersByTime. Keeps the same onChange expectations with less scheduling sensitivity under React 18.

packages/core/src/components/TextField/tests/TextField-tests.test.tsx

Tipseen.test.tsxFlush showDelay timers inside act() for snapshot stability +4/-5

Flush showDelay timers inside act() for snapshot stability

• Removes an async waitFor wrapper and explicitly runs timers within act() before snapshotting. Aligns delayed rendering behavior with React 18 update flushing.

packages/core/src/components/Tipseen/tests/Tipseen.test.tsx

Toast.test.tsxUse act from @testing-library/react +1/-2

Use act from @testing-library/react

• Switches act import from @testing-library/react-hooks to @testing-library/react. Maintains the existing toast interaction and assertion logic.

packages/core/src/components/Toast/tests/Toast.test.tsx

useDebounceEvent.test.tsMigrate hook tests to @testing-library/react and simplify types +2/-2

Migrate hook tests to @testing-library/react and simplify types

• Uses renderHook/cleanup/act from @testing-library/react and updates type annotations to match RTL's renderHook return types. Continues validating debounce behavior without the deprecated hooks package.

packages/core/src/hooks/tests/useDebounceEvent.test.ts

useEventListener.test.tsConsolidate fireEvent and renderHook imports under RTL +1/-2

Consolidate fireEvent and renderHook imports under RTL

• Moves renderHook/cleanup/act imports to @testing-library/react and imports fireEvent from the same module. Removes @testing-library/react-hooks usage while preserving behavior.

packages/core/src/hooks/tests/useEventListener.test.ts

useKeyEvent.test.tsConsolidate fireEvent and renderHook imports under RTL +1/-2

Consolidate fireEvent and renderHook imports under RTL

• Updates hook test utilities and fireEvent imports to come from @testing-library/react. Removes dependency on @testing-library/react-hooks.

packages/core/src/hooks/tests/useKeyEvent.test.ts

useActiveDescendantListFocus.test.tsMigrate renderHook/act/cleanup to RTL +1/-1

Migrate renderHook/act/cleanup to RTL

• Switches hook test imports from @testing-library/react-hooks to @testing-library/react. Keeps the same focus management assertions with updated tooling.

packages/core/src/hooks/useActiveDescendantListFocus/tests/useActiveDescendantListFocus.test.ts

useAfterFirstRender.test.tsxSwitch renderHook to @testing-library/react +1/-1

Switch renderHook to @testing-library/react

• Updates renderHook import to @testing-library/react. Removes reliance on the deprecated hooks testing package.

packages/core/src/hooks/useAfterFirstRender/tests/useAfterFirstRender.test.tsx

useGridKeyboardNavigation.test.tsMove fireEvent/renderHook imports to RTL +1/-2

Move fireEvent/renderHook imports to RTL

• Imports fireEvent, renderHook, cleanup, and act from @testing-library/react instead of mixing with @testing-library/react-hooks. Keeps keyboard navigation test behavior consistent.

packages/core/src/hooks/useGridKeyboardNavigation/tests/useGridKeyboardNavigation.test.ts

useSetFocus.test.tsMigrate renderHook/act/cleanup to RTL +1/-1

Migrate renderHook/act/cleanup to RTL

• Switches hook test utilities to @testing-library/react. Removes usage of @testing-library/react-hooks without changing test logic.

packages/core/src/hooks/useSetFocus/tests/useSetFocus.test.ts

useSwitch.test.tsUpdate renderHook usage and loosen result typing for RTL +3/-3

Update renderHook usage and loosen result typing for RTL

• Moves to @testing-library/react renderHook and adjusts helper typing to match RTL's result shape. Preserves existing switch hook behavior checks while dropping the deprecated hooks library.

packages/core/src/hooks/useSwitch/tests/useSwitch.test.ts

useWizard.test.tsSwitch renderHook/act to @testing-library/react +1/-1

Switch renderHook/act to @testing-library/react

• Replaces @testing-library/react-hooks imports with @testing-library/react equivalents. Keeps wizard hook tests functionally identical.

packages/core/src/hooks/useWizard/tests/useWizard.test.ts

useGridKeyboardNavigationContext.interactions.tsUse @storybook/test waitFor for interaction assertions +6/-4

Use @storybook/test waitFor for interaction assertions

• Switches expect import from @storybook/jest to @storybook/test and wraps DOM assertions in waitFor. This accounts for React 18 batching and asynchronous rendering in Storybook play functions.

packages/docs/src/pages/components/GridKeyboardNavigationContext/useGridKeyboardNavigationContext.interactions.ts

useActiveDescendantListFocus.interactions.tsUpdate interaction flow to use @storybook/test userEvent + waitFor +13/-12

Update interaction flow to use @storybook/test userEvent + waitFor

• Moves to @storybook/test for expect/userEvent/waitFor and wraps focus/visual-focus assertions in waitFor. Adjusts initial focus acquisition to use tabbing to match how focus is managed in the story under React 18.

packages/docs/src/pages/hooks/useActiveDescendantListFocus/useActiveDescendantListFocus.interactions.ts

useClickOutside.test.tsMove fireEvent/renderHook imports to @testing-library/react +1/-2

Move fireEvent/renderHook imports to @testing-library/react

• Replaces @testing-library/react-hooks usage by importing renderHook/cleanup/act from @testing-library/react and fireEvent from the same module. Keeps hook behavior validations unchanged.

packages/hooks/src/useClickOutside/tests/useClickOutside.test.ts

Other (16) +62 / -68
package.jsonBump React devDeps and Testing Library to React 18 toolchain +4/-4

Bump React devDeps and Testing Library to React 18 toolchain

• Upgrades devDependencies to react/react-dom/react-test-renderer 18.2 and @testing-library/react 14. This aligns local testing/build tooling with React 18 without changing runtime peer requirements.

packages/base/package.json

package.jsonUpgrade dev React + @testing-library/react for button package +4/-4

Upgrade dev React + @testing-library/react for button package

• Moves the package's devDependencies from React 16 to React 18.2 and bumps @testing-library/react to v14. Updates react-test-renderer accordingly.

packages/components/button/package.json

package.jsonUpgrade dev React + @testing-library/react for clickable package +4/-4

Upgrade dev React + @testing-library/react for clickable package

• Bumps React devDependencies to 18.2 and @testing-library/react to v14. Updates react-test-renderer to match the React version.

packages/components/clickable/package.json

package.jsonUpgrade dialog devDeps; remove @testing-library/react-hooks +4/-5

Upgrade dialog devDeps; remove @testing-library/react-hooks

• Upgrades @testing-library/react to v14 and moves React devDependencies to 18.2. Removes deprecated @testing-library/react-hooks from devDependencies.

packages/components/dialog/package.json

package.jsonUpgrade icon-button dev React + RTL versions +4/-4

Upgrade icon-button dev React + RTL versions

• Bumps @testing-library/react to v14 and moves React devDependencies to 18.2. Updates react-test-renderer to 18.2 as well.

packages/components/icon-button/package.json

package.jsonUpgrade icon package dev React to 18.2 +2/-2

Upgrade icon package dev React to 18.2

• Bumps react/react-dom devDependencies from 16.x to 18.2. Keeps the rest of the tooling intact.

packages/components/icon/package.json

package.jsonUpgrade layer dev React + RTL versions +4/-4

Upgrade layer dev React + RTL versions

• Moves React devDependencies to 18.2 and bumps @testing-library/react to v14. Updates react-test-renderer to 18.2 to match.

packages/components/layer/package.json

package.jsonUpgrade layout dev React + RTL versions +4/-4

Upgrade layout dev React + RTL versions

• Bumps @testing-library/react to v14 and upgrades react/react-dom/react-test-renderer devDependencies to 18.2. Aligns local tests with React 18 behavior.

packages/components/layout/package.json

package.jsonUpgrade loader dev React + RTL versions +4/-4

Upgrade loader dev React + RTL versions

• Upgrades React devDependencies to 18.2 and @testing-library/react to v14. Updates react-test-renderer to 18.2.

packages/components/loader/package.json

package.jsonUpgrade tooltip dev React + RTL versions +4/-4

Upgrade tooltip dev React + RTL versions

• Bumps React devDependencies to 18.2 and upgrades @testing-library/react to v14. Updates react-test-renderer to 18.2.

packages/components/tooltip/package.json

package.jsonUpgrade typography dev React + RTL versions +4/-4

Upgrade typography dev React + RTL versions

• Moves React devDependencies from 16.x to 18.2 and bumps @testing-library/react to v14. Updates react-test-renderer to 18.2.

packages/components/typography/package.json

package.jsonCore dev toolchain upgrades and removal of unused hot-loader +5/-7

Core dev toolchain upgrades and removal of unused hot-loader

• Upgrades React devDependencies and react-test-renderer to 18.2 and bumps @testing-library/react to v14 while removing @testing-library/react-hooks. Removes unused @hot-loader/react-dom and updates @types/react-test-renderer to 18.x.

packages/core/package.json

package.jsonDocs/Storybook devDeps: React 18.2, RTL v14, drop hot-loader +5/-7

Docs/Storybook devDeps: React 18.2, RTL v14, drop hot-loader

• Upgrades React devDependencies and react-test-renderer to 18.2 and bumps @testing-library/react to v14 while removing @testing-library/react-hooks. Removes unused @hot-loader/react-dom from docs tooling.

packages/docs/package.json

package.jsonUpgrade hooks package devDeps; remove react-hooks testing library +4/-5

Upgrade hooks package devDeps; remove react-hooks testing library

• Bumps React devDependencies to 18.2 and upgrades @testing-library/react to v14. Removes @testing-library/react-hooks from devDependencies.

packages/hooks/package.json

package.jsonUpgrade shared tooling dev React to 18.2 +2/-2

Upgrade shared tooling dev React to 18.2

• Bumps react and react-dom in devDependencies to 18.2 for shared tooling. Does not alter peerDependencies (consumer compatibility remains unchanged).

packages/shared/package.json

package.jsonUpgrade storybook-blocks devDeps to React 18.2 + RTL v14 +4/-4

Upgrade storybook-blocks devDeps to React 18.2 + RTL v14

• Bumps @testing-library/react to v14 and upgrades react/react-dom/react-test-renderer to 18.2. Aligns Storybook blocks development environment with React 18.

packages/storybook-blocks/package.json

userEvent.keyboard() dispatches events based on user-event's internal
focus tracking, not document.activeElement. Calling element.focus()
directly doesn't update that tracking, so keyboard events were
dispatched on the wrong element. Using userEvent.tab() properly updates
both browser focus and user-event's tracked focus target.
const initialStateValue = "";
let onChangeCallbackStub: Mock;
let hookResult: RenderHookResult<unknown, UseDebounceResult>;
let hookResult: ReturnType<typeof renderHook<UseDebounceResult>>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. Invalid renderhook returntype typing 📘 Rule violation ≡ Correctness

useDebounceEvent.test.ts declares hookResult as `ReturnType<typeof
renderHook<UseDebounceResult>>, but applying generic type arguments inside a typeof` type query is
invalid TypeScript and can fail the test build/typecheck. This risks breaking CI and undermines the
reliability of the migrated React 18 test suite.
Agent Prompt
## Issue description
`packages/core/src/hooks/__tests__/useDebounceEvent.test.ts` types `hookResult` as `ReturnType<typeof renderHook<UseDebounceResult>>`, but generic parameters cannot be applied inside a `typeof` type query, making this invalid TypeScript syntax. This can break TypeScript compilation of the test suite and block CI.

## Issue Context
This PR migrates hook tests from `@testing-library/react-hooks` to `@testing-library/react`, and the intent is to correctly type the value returned by `renderHook(...)` while keeping the tests reliable under the React 18 tooling upgrade.

## Fix Focus Areas
- packages/core/src/hooks/__tests__/useDebounceEvent.test.ts[10-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit c9caf40

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.

1 participant