Skip to content

Add React Testing Library migration infrastructure and first conversions#385

Open
blaipr wants to merge 1 commit into
ctrliq:mainfrom
blaipr:feature/rtl-migration
Open

Add React Testing Library migration infrastructure and first conversions#385
blaipr wants to merge 1 commit into
ctrliq:mainfrom
blaipr:feature/rtl-migration

Conversation

@blaipr

@blaipr blaipr commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Stage 3 groundwork of the React stack modernization: start retiring enzyme, which is dead upstream and has no adapter beyond React 17 — it is the single hard blocker for ever moving to React 18/19 (495 test files depend on it).

This PR makes incremental conversion possible and establishes the pattern:

  • testUtils/rtlContexts.jsrenderWithContexts(), the React Testing Library counterpart of mountWithContexts: same context defaults and override mechanism (i18n, session, config, router with optional custom history), plus a ready userEvent instance and the history object in the return value.
  • @testing-library/jest-dom matchers loaded globally in setupTests.js (suites no longer import them individually; existing per-file imports keep working).
  • Seven representative suites converted as the pattern: ContentEmpty, ContentLoading, AlertModal, FormActionGroup, ChipGroup, ToolbarSyncSourceButton (interaction) and DeleteButton (modal open → confirm flow → async error). Where the enzyme versions only asserted wrapper length or component props, the RTL versions assert rendered behavior — e.g. ChipGroup's old test asserted a prop on an effectively empty render; it now renders actual chips and asserts the visible overflow text.

Conversion recipe

enzyme RTL
mountWithContexts(<X/>) renderWithContexts(<X/>)
wrapper.find('button').simulate('click') await user.click(screen.getByRole('button', { name }))
waitForElement(wrapper, 'X') await screen.findBy...
asserting .props() / .length assert visible text/roles
act(...) wrapping usually unnecessary

Both helpers coexist; the remaining ~490 enzyme suites convert incrementally (screen directory at a time works well). When the last one converts, enzyme + the React 17 adapter come out of package.json — unblocking React 18.

Independent of all open PRs — test-only changes (no production code, no dependency changes). Note for the future: when the react-router compat migration (#392) merges, rtlContexts should gain the same controlled v6 Router layer its enzyme counterpart gets there — a 5-line follow-up.

ISSUE TYPE

  • New or Enhanced Feature

COMPONENT NAME

  • UI

ASCENDER VERSION

awx: 25.4.1.dev5+gcda0899.d20260610

ADDITIONAL INFORMATION

npm --prefix awx/ui run lint     # clean
npm --prefix awx/ui run test     # 544 suites passed (1 skipped), 2855 tests passed (19 skipped)

Production build unaffected (test files and test utilities only).

Groundwork for retiring enzyme (dead upstream, no adapter beyond React
17 - it is the hard blocker for React 18+):

- testUtils/rtlContexts.js: renderWithContexts(), the RTL counterpart of
  mountWithContexts. Same context defaults and override mechanism
  (i18n, session, config, router with optional custom history), plus a
  ready userEvent instance and the history object in the return value.
- @testing-library/jest-dom matchers are loaded globally in setupTests
  (individual suites no longer need to import them).
- Seven representative suites converted from enzyme to RTL as the
  pattern: ContentEmpty, ContentLoading, AlertModal, FormActionGroup,
  ChipGroup, ToolbarSyncSourceButton (interaction) and DeleteButton
  (modal open, confirm flow, async error). Where the enzyme versions
  only asserted wrapper length or props, the RTL versions assert
  rendered behavior; ChipGroup's old test asserted a prop on an empty
  render and now renders actual chips and asserts the visible overflow
  text.

Conversion recipe:
  mountWithContexts(<X/>)            -> renderWithContexts(<X/>)
  wrapper.find('button').simulate    -> await user.click(screen.getByRole('button', { name }))
  waitForElement(wrapper, 'X')       -> await screen.findBy...
  wrapper.find(...).props() asserts  -> assert visible text/roles instead
  act(...) wrapping                  -> usually unnecessary (RTL wraps)

545 suites remain on enzyme; they convert incrementally with both
helpers coexisting.

Copilot AI left a comment

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.

Pull request overview

This PR lays the groundwork for incrementally migrating Ascender’s UI test suite from Enzyme (React 17-bound) to React Testing Library by introducing a shared RTL render helper and converting an initial set of representative component tests.

Changes:

  • Added renderWithContexts() helper to mirror Enzyme’s mountWithContexts() provider wiring for RTL tests.
  • Loaded @testing-library/jest-dom matchers globally via setupTests.js.
  • Converted 7 component test suites from Enzyme to RTL patterns (behavior/DOM assertions + userEvent interactions).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
awx/ui/testUtils/rtlContexts.js Adds RTL context render helper used for incremental Enzyme → RTL conversions.
awx/ui/src/setupTests.js Globally registers @testing-library/jest-dom matchers for all UI tests.
awx/ui/src/components/PaginatedTable/ToolbarSyncSourceButton.test.js Converts suite to RTL and userEvent click interaction.
awx/ui/src/components/FormActionGroup/FormActionGroup.test.js Converts to RTL with accessible-button clicks and handler assertions.
awx/ui/src/components/DeleteButton/DeleteButton.test.js Converts modal flow tests to RTL patterns (findByRole, waitFor).
awx/ui/src/components/ContentLoading/ContentLoading.test.js Converts to RTL with role-based assertion.
awx/ui/src/components/ContentEmpty/ContentEmpty.test.js Converts to RTL with visible-text assertion.
awx/ui/src/components/ChipGroup/ChipGroup.test.js Converts to RTL and asserts visible collapsed count text.
awx/ui/src/components/AlertModal/AlertModal.test.js Converts to RTL and asserts dialog/title/body rendering.

Comment on lines +17 to +26
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { I18nProvider } from '@lingui/react';
import { i18n } from '@lingui/core';
import english from '../src/locales/en/messages';
import { SessionProvider } from '../src/contexts/Session';
import { ConfigProvider } from '../src/contexts/Config';

i18n.load({ en: english.messages });
i18n.activate('en');
Comment thread awx/ui/testUtils/rtlContexts.js
Comment on lines +70 to +74
request: CredentialsAPI.read.mockRejectedValue(
new Error({
response: {
config: {
method: 'get',
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants