Skip to content

[8.19] Backward compatible testing library changes for switching to createRoot (#213367)#220500

Merged
Dosant merged 7 commits intoelastic:8.19from
Dosant:backport/8.19/pr-213367
May 9, 2025
Merged

[8.19] Backward compatible testing library changes for switching to createRoot (#213367)#220500
Dosant merged 7 commits intoelastic:8.19from
Dosant:backport/8.19/pr-213367

Conversation

@Dosant
Copy link
Contributor

@Dosant Dosant commented May 8, 2025

Backport

This will backport the following commits from main to 8.19:

Questions ?

Please refer to the Backport tool documentation

…#213367)

Closes elastic#218076.
Part of the preparation for migrating Kibana to React’s createRoot
([Epic](elastic/kibana-team#1564)).

## What’s in this PR

- Switch to `createRoot` in tests: Updates `@testing-library/react` to
use `createRoot` by default. All unit tests using Testing Library now
run in concurrent mode. See commit:
elastic@8e51e07
- Test updates: Most test failures from the switch have been addressed.
About a dozen tests still explicitly set `legacyRoot: true`. These will
need closer review by the owning teams during app migrations.
- Enzyme tests: Enzyme tests continue to use the React 17 adapter and
run in legacy mode. [Current
plan](https://docs.google.com/document/d/1CXybQiBAtXt3Kay0j_CJxWO7bZ2EYYhaveK4fban2-M/edit?tab=t.kfgvma8ti7q0)
is to migrate away from Enzyme before upgrading to React 19.

## Background

When we upgraded to React 18, we also updated `@testing-library/react`,
which by default uses `createRoot`.
To avoid dealing with concurrent mode failures early, we temporarily
forced Testing Library to use `legacyRoot` (`ReactDOM.render`).

This PR removes that override and fixes the resulting test issues,
completing the move to concurrent root for Testing Library tests.

### Common Failures

####  🔴 `el.click()`

A common testing mistake is using el.click() and immediately checking
for a DOM update:
```
el.click();
expect(el).toHaveAttribute('state-updated');
```

This often fails with Concurrent React, because state updates might not
be synchronous anymore.
Directly calling `el.click()` doesn't automatically trigger React’s
update cycle (`act`), so your test can read outdated DOM.

Instead, you should either manually wrap the interaction in `act`, or
(better) use `userEvent.click`, which already uses `act` internally and
simulates real user behavior more accurately:

```diff
- el.click();
+ await userEvent.click(el);
expect(el).toHaveAttribute('state-updated');
```

#### 🔴 Wrapping `render` call inside `act` `act(() => render(<App/>))`

Another common mistake is wrapping the render call inside act:

```
await act(async () => {
  render(<MyComponent />);
});
```

This is sometimes done to "mute" warnings about Promises resolving
inside `useEffect`.
However, wrapping `render` in `act` manually breaks a lot of tests in
Concurrent React, because the library (like React Testing Library)
already wraps render in act internally. Manually adding act here can
cause unexpected behavior, like missing updates or wrong timing.

The approach I took was to remove the manual `act` around `render` in
places where tests started failing with Concurrent React, even if, in
some cases, it means seeing `act` warnings in the console. This is safer
for correctness and allows the tests to pass reliably.

To properly mute such warnings, the right way would be to wrap the
actual resolved Promises (like those inside useEffect) in act.However,
since doing that depends a lot on the specific test setup, and could
vary case-by-case, I chose not to try to fix it myself. Teams are
welcome to follow up if they wish.

### 🟡 In specific tests we keep `legacyMode: true`

When it wasn't immediately clear to me what caused the failure or when
the tests were checking React internals, like the number of re-renders,
I decided to keep that test running in legacy mode by using the option
`legacyRoot: true` in `render`.

The idea behind these in-place overrides is that when we're ready to
start migrating the runtime to concurrent mode, the owning teams will
need to take a closer look at those tests when moving their apps to the
concurrent root.

(cherry picked from commit 24d4c8a)

# Conflicts:
#	src/platform/packages/shared/kbn-test/src/jest/setup/react_testing_library.js
#	src/platform/packages/shared/kbn-unified-tabs/src/components/tab/tab.test.tsx
#	src/platform/packages/shared/shared-ux/error_boundary/src/ui/error_boundary.test.tsx
#	src/platform/packages/shared/shared-ux/error_boundary/src/ui/section_error_boundary.test.tsx
#	src/platform/plugins/shared/home/public/application/components/tutorial/tutorial.test.tsx
#	src/platform/plugins/shared/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.test.tsx
#	x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/api/chat_complete/use_chat_complete.test.ts
#	x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/settings/settings_context_menu/settings_context_menu.test.tsx
#	x-pack/platform/plugins/shared/automatic_import/public/components/create_integration/create_automatic_import/flyout/cel_configuration/steps/upload_spec_step/api_definition_input.test.tsx
#	x-pack/platform/plugins/shared/automatic_import/public/components/create_integration/create_automatic_import/flyout/cel_configuration/steps/upload_spec_step/upload_spec_step.test.tsx
#	x-pack/platform/plugins/shared/lens/public/editor_frame_service/editor_frame/editor_frame.test.tsx
#	x-pack/platform/plugins/shared/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx
#	x-pack/platform/plugins/shared/security/public/account_management/user_profile/user_profile.test.tsx
#	x-pack/platform/plugins/shared/spaces/public/management/edit_space/edit_space_general_tab.test.tsx
#	x-pack/solutions/observability/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall_container.test.tsx
#	x-pack/solutions/security/plugins/security_solution/public/common/test/eui/super_select.ts
#	x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/pages/rule_management/__integration_tests__/rules_upgrade/test_utils/rule_upgrade_flyout.tsx
#	x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/search_bar/integrations_filter_button.test.tsx
#	x-pack/solutions/security/plugins/security_solution/public/detections/components/alert_summary/table/more_actions_row_control_column.test.tsx
#	x-pack/solutions/security/plugins/security_solution/public/detections/pages/alert_summary/alert_summary.test.tsx
#	x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/settings_menu.test.tsx
#	x-pack/solutions/security/plugins/security_solution/public/flyout/ai_for_soc/components/take_action_button.test.tsx
@Dosant Dosant requested a review from kibanamachine as a code owner May 8, 2025 12:08
@Dosant Dosant added the backport This PR is a backport of another PR label May 8, 2025
@Dosant Dosant enabled auto-merge (squash) May 8, 2025 12:08
@botelastic botelastic bot added Team:Fleet Team label for Observability Data Collection Fleet team Team:obs-ux-infra_services - DEPRECATED DEPRECATED - Use Team:obs-presentation. Team:actionable-obs Formerly "obs-ux-management", responsible for SLO, o11y alerting, significant events, & synthetics. labels May 8, 2025
@elasticmachine
Copy link
Contributor

Pinging @elastic/obs-ux-infra_services-team (Team:obs-ux-infra_services)

@elasticmachine
Copy link
Contributor

Pinging @elastic/fleet (Team:Fleet)

@elasticmachine
Copy link
Contributor

Pinging @elastic/obs-ux-management-team (Team:obs-ux-management)

@elasticmachine
Copy link
Contributor

elasticmachine commented May 9, 2025

💔 Build Failed

Failed CI Steps

Test Failures

  • [job] [logs] Jest Tests #4 / DatatableComponent renderCellValue getCellColor caching caches getCellColorFn by columnId
  • [job] [logs] Jest Tests #4 / DatatableComponent renderCellValue getCellColor caching caches getCellColorFn by columnId
  • [job] [logs] Jest Tests #4 / DatatableComponent renderCellValue getCellColor caching caches getCellColorFn by columnId with transpose columns
  • [job] [logs] Jest Tests #4 / DatatableComponent renderCellValue getCellColor caching caches getCellColorFn by columnId with transpose columns
  • [job] [logs] Jest Tests #4 / editor_frame state update should re-render config panel after state update
  • [job] [logs] Jest Tests #4 / editor_frame state update should re-render config panel after state update
  • [job] [logs] Jest Tests #5 / publishing subject render should render for each state update outside of click handler
  • [job] [logs] Jest Tests #5 / publishing subject render should render for each state update outside of click handler
  • [job] [logs] Jest Tests #19 / RequiredFields form part user can add his own custom field name and type
  • [job] [logs] Jest Tests #19 / RequiredFields form part user can add his own custom field name and type
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when only field name is empty
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when only field name is empty
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when only field type is empty
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when only field type is empty
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when same field name is selected more than once
  • [job] [logs] Jest Tests #19 / RequiredFields form part validation form is invalid when same field name is selected more than once
  • [job] [logs] Jest Tests #19 / RequiredFields form part warnings doesn't display a warning when field is invalid
  • [job] [logs] Jest Tests #19 / RequiredFields form part warnings doesn't display a warning when field is invalid
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is a an ndjson with a single record should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is a an ndjson with a single record should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content "test message 1" should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content "test message 1" should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content "test message 1" should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is invalid with logs content "test message 1" should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is multiline ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is multiline ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is valid ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when setting a ndjson logs sample when the file is valid ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when the file is neither a valid json nor ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when the file is neither a valid json nor ndjson should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when the file is too large should raise an appropriate error
  • [job] [logs] Jest Tests #9 / SampleLogsInput when the file is too large should raise an appropriate error
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is a json array under a key should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is a json array under a key should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content ["test message 1"] should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content ["test message 1"] should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content ["test message 1"] should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content ["test message 1"] should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content [] should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content [] should render error message
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content [] should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is invalid with logs content [] should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is valid json should set the integrationSetting correctly
  • [job] [logs] Jest Tests #9 / SampleLogsInput when uploading a json logs sample when the file is valid json should set the integrationSetting correctly
  • [job] [logs] Jest Tests #12 / SolutionFilter when no owner set renders options correctly

Metrics [docs]

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
core 433.8KB 433.8KB +12.0B

History

@Dosant Dosant changed the title [8.19] [Concurrent React@18] Switch testing library to createRoot (#213367) [8.19] [Concurrent React@18] Backward compatible testing library changes for switching to createRoot (#213367) May 9, 2025
@Dosant Dosant changed the title [8.19] [Concurrent React@18] Backward compatible testing library changes for switching to createRoot (#213367) [8.19] Backward compatible testing library changes for switching to createRoot (#213367) May 9, 2025
Copy link
Member

@tsullivan tsullivan left a comment

Choose a reason for hiding this comment

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

LGTM

Thank you for this hard work to make future backports easier!

@Dosant Dosant merged commit 2e6e08e into elastic:8.19 May 9, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport This PR is a backport of another PR Team:actionable-obs Formerly "obs-ux-management", responsible for SLO, o11y alerting, significant events, & synthetics. Team:Fleet Team label for Observability Data Collection Fleet team Team:obs-ux-infra_services - DEPRECATED DEPRECATED - Use Team:obs-presentation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants