Skip to content

MM-69835 Convert remaining Enzyme tests to RTL - #8

Open
hmhealey wants to merge 2 commits into
0.34from
MM-69835-1
Open

MM-69835 Convert remaining Enzyme tests to RTL#8
hmhealey wants to merge 2 commits into
0.34from
MM-69835-1

Conversation

@hmhealey

@hmhealey hmhealey commented Aug 4, 2026

Copy link
Copy Markdown
Member

Summary

This is the first part of updating to React 19 by finally getting rid of Enzyme in the tests for React Bootstrap. This was done primarily using Claude

Ticket Link

https://mattermost.atlassian.net/browse/MM-69835

@hmhealey

hmhealey commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai If possible, review this

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

@hmhealey: I will review pull request #8, with focus on the Enzyme-to-RTL test conversions.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

@hmhealey I will review pull request #8.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The test suite migrates from Enzyme to React Testing Library. Shared DOM assertion helpers and controlled interaction fixtures replace Enzyme APIs. Enzyme dependencies are removed, and Karma uses ChromeHeadless by default.

Changes

React Testing Library migration

Layer / File(s) Summary
Test infrastructure and headless execution
karma.conf.js, package.json, test/helpers.js, test/index.js
The default Karma browser is now ChromeHeadless. Enzyme dependencies and setup are removed. Shared DOM assertions and reliable warning-spy cleanup are added.
Form and input component tests
test/CheckboxSpec.js, test/ControlLabelSpec.js, test/FormControlFeedbackSpec.js, test/FormControlSpec.js, test/FormControlStaticSpec.js, test/FormSpec.js, test/HelpBlockSpec.js, test/InputGroupSpec.js, test/MenuItemSpec.js, test/RadioSpec.js
Tests render components with React Testing Library and verify DOM attributes, classes, text, refs, validation states, and custom components.
Navigation and panel interaction tests
test/NavSpec.js, test/PanelGroupSpec.js, test/PanelSpec.js, test/SafeAnchorSpec.js
Tests use DOM queries, fireEvent, act, controlled state, event properties, and ARIA attributes for navigation and panel behaviour.
Tabs and toggle group tests
test/TabContainerSpec.js, test/ToggleButtonGroupSpec.js
Tests verify rendered roles, pane state, accessibility relationships, input state, and click-driven changes without Enzyme instance updates.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly describes the main change: converting the remaining Enzyme tests to React Testing Library.
Description check ✅ Passed The description directly relates the Enzyme removal to the React 19 migration and identifies the associated ticket.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MM-69835-1

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/MenuItemSpec.js`:
- Around line 148-155: Update the tests in MenuItemSpec.js to verify behavior
rather than checking the absent onselect attribute: use a callback spy and
dispatch the appropriate selection event to assert onSelect is invoked, and use
a separate onClick callback for click behavior. Remove the duplicated
onSelect-based click test while preserving coverage that internal props do not
leak and click handlers are called.

In `@test/SafeAnchorSpec.js`:
- Around line 85-89: Update the disabled-link test around SafeAnchor.handleClick
to verify propagation is stopped, not only that the component’s onClick prop is
skipped. Render SafeAnchor inside a parent with a separate onClick spy, trigger
the disabled click, and assert the parent spy was not called while preserving
the existing defaultPrevented and clickSpy assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a85dd4e7-c6dc-40da-a5ff-f545210fb695

📥 Commits

Reviewing files that changed from the base of the PR and between 05559f4 and e909302.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (20)
  • karma.conf.js
  • package.json
  • test/CheckboxSpec.js
  • test/ControlLabelSpec.js
  • test/FormControlFeedbackSpec.js
  • test/FormControlSpec.js
  • test/FormControlStaticSpec.js
  • test/FormSpec.js
  • test/HelpBlockSpec.js
  • test/InputGroupSpec.js
  • test/MenuItemSpec.js
  • test/NavSpec.js
  • test/PanelGroupSpec.js
  • test/PanelSpec.js
  • test/RadioSpec.js
  • test/SafeAnchorSpec.js
  • test/TabContainerSpec.js
  • test/ToggleButtonGroupSpec.js
  • test/helpers.js
  • test/index.js
💤 Files with no reviewable changes (1)
  • package.json

Comment thread test/MenuItemSpec.js
Comment on lines +148 to +155
// `onSelect` is an internal prop and must not leak onto the rendered DOM
// node. There is no DOM attribute for `onSelect`, so the closest observable
// check is that the rendered anchor carries no `onselect` attribute (and no
// React unknown-prop warning is emitted, which the harness would surface).
const { container } = render(<MenuItem onSelect={() => {}}>Item</MenuItem>);
const anchor = container.querySelector('a');

assert.equal(anchor.getAttribute('onselect'), null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the exact prop filtering and forwarding path. Do not execute repository code.
rg -n -C 6 'splitBsPropsAndOmit|onSelect|onClick|SafeAnchor|createChainedFunction' src/MenuItem.js

fd -i '^SafeAnchor\.js$' src -0 |
  xargs -0 -r rg -n -C 6 'onSelect|onClick|elementProps|props|<a'

Repository: mattermost/react-bootstrap

Length of output: 4972


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- test/MenuItemSpec.js ---'
sed -n '130,172p' test/MenuItemSpec.js

printf '%s\n' '--- splitBsPropsAndOmit implementation ---'
rg -n -C 8 'function splitBsPropsAndOmit|const splitBsPropsAndOmit|export.*splitBsPropsAndOmit' src/utils

Repository: mattermost/react-bootstrap

Length of output: 2829


Replace the onselect attribute checks with behavioural assertions.

onSelect is a React synthetic event, so getAttribute('onselect') remains null even when onSelect reaches SafeAnchor. Both tests can therefore pass without proving prop omission. The second test also passes onSelect, not onClick, and duplicates the first test. Use a callback spy with a selection event, and pass an onClick callback when testing click behaviour.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/MenuItemSpec.js` around lines 148 - 155, Update the tests in
MenuItemSpec.js to verify behavior rather than checking the absent onselect
attribute: use a callback spy and dispatch the appropriate selection event to
assert onSelect is invoked, and use a separate onClick callback for click
behavior. Remove the duplicated onSelect-based click test while preserving
coverage that internal props do not leak and click handlers are called.

Comment thread test/SafeAnchorSpec.js
Comment on lines +85 to +89
// Disabled links must not fire the user-provided onClick handler. This also
// stands in for the removed `isPropagationStopped()` assertion: the disabled
// path returns early after stopping propagation, so onClick is never called.
expect(clickSpy).to.have.not.been.called;
expect(spy.getCall(0).args[0].isDefaultPrevented()).to.equal(true);
expect(spy.getCall(0).args[0].isPropagationStopped()).to.equal(true);
expect(spy.getCall(0).args[0].defaultPrevented).to.equal(true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Retain the propagation assertion.

clickSpy verifies only that SafeAnchor does not call its own onClick prop. It does not verify event.stopPropagation().

If SafeAnchor.handleClick removes event.stopPropagation() but keeps the early return, this test still passes while disabled-link clicks bubble to parent handlers. Render the anchor inside a parent with an onClick spy, then assert that the parent spy was not called.

Proposed test update
   it('Should disable link behavior', () => {
     let clickSpy = sinon.spy();
+    let parentClickSpy = sinon.spy();
     let spy = sinon.spy(SafeAnchor.prototype, 'handleClick');

     const { container } = render(
-      <SafeAnchor disabled href="`#foo`" onClick={clickSpy}>
-        Title
-      </SafeAnchor>
+      <div onClick={parentClickSpy}>
+        <SafeAnchor disabled href="`#foo`" onClick={clickSpy}>
+          Title
+        </SafeAnchor>
+      </div>
     );
     fireEvent.click(container.querySelector('a'));

     expect(spy).to.have.been.calledOnce;
     expect(clickSpy).to.have.not.been.called;
+    expect(parentClickSpy).to.have.not.been.called;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/SafeAnchorSpec.js` around lines 85 - 89, Update the disabled-link test
around SafeAnchor.handleClick to verify propagation is stopped, not only that
the component’s onClick prop is skipped. Render SafeAnchor inside a parent with
a separate onClick spy, trigger the disabled click, and assert the parent spy
was not called while preserving the existing defaultPrevented and clickSpy
assertions.

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