Skip to content

test: React Testing Library + renderer component tests, coverage to 33% (Phase 3) - #3365

Merged
jeanfbrito merged 2 commits into
masterfrom
chore/coverage-phase3-rtl-infra
Jun 22, 2026
Merged

test: React Testing Library + renderer component tests, coverage to 33% (Phase 3)#3365
jeanfbrito merged 2 commits into
masterfrom
chore/coverage-phase3-rtl-infra

Conversation

@jeanfbrito

@jeanfbrito jeanfbrito commented Jun 22, 2026

Copy link
Copy Markdown
Member

What

Phase 3: introduces React Testing Library and uses it to test the renderer UI layer — the largest coverage gap. Stacked on Phase 2.

Stacked on chore/coverage-phase2-extract (#3364). Merge order: #3362#3363#3364 → this.

Coverage delta

Metric Phase 2 end Phase 3 end
Lines 26.72% 33.29%
Statements 26.76% 33.65%
Branches 23.72% 29.33%
Functions 19.45% 27.31%

912 tests pass, 2 skipped, 0 failures, 52 suites. Full yarn test:coverage green.

Infra (step 0)

  • Adds devDeps @testing-library/react 14.3.1, jest-dom 6.9.1, user-event 14.6.1, dom 9.3.4 (React 18 compatible).
  • @testing-library/jest-dom imported in src/.jest/setup.ts; src/jest-dom.d.ts registers its matcher types for tsc (the dotted .jest dir is outside the TS program).
  • src/ui/test-utils.tsx: renderWithStore() helper (redux Provider + preloaded state) + RTL/userEvent re-exports + the react-i18next mock snippet.
  • RTL works out-of-box under @kayahr/jest-electron-runner (real renderer DOM, no jsdom, no jest.config project change).

Component tests (14 specs)

Dialogs: UpdateDialog, ScreenSharingDialog, ClearCacheDialog, SupportedVersionDialog, OutlookCredentialsDialog. Containers: DownloadsManagerView, AddServerView, SideBar, Shell. Leaf: DownloadItem, ModalBackdrop, ServerButton. Helpers: createAnchor, ReparentingContainer.

Suite-stability fixes (the hard part)

Two distinct failure modes in the electron jest runner had to be solved before the suite could complete:

  1. Hanglogging/index.ts's setInterval(flushErrorJsonl, 10_000) ran under real timers in index.main.spec.ts, reloaded ~24× via isolateModules, leaving ~20 live ref'd intervals that kept libuv alive past --forceExit. Fixed with fake timers + afterEach cleanup (also applied to ScreenSharingRequestTracker, desktopCapturerCache).
  2. Crash — a manual afterEach(() => document.body.innerHTML = '') in two util specs raced RTL's auto-cleanup, so a portal's unmount removeChild threw NotFoundErrorsrc/.jest/setup.ts's strict uncaughtException handler did process.exit(1), killing the whole run. Fixed by removing the redundant manual wipe.

Key durable findings (in docs/KNOWN_ISSUES.md): under this runner, userEvent.type does not commit to React controlled inputs — use fireEvent.change; and any leaked timer/async-rejection in one spec aborts the whole suite via the strict exit handler.

Held back (follow-up)

Three specs (ErrorView, ServerInfoContent, AboutDialog) leak async/DOM teardown that the strict exit handler turns into a suite-killing process.exit(1). Quarantined out of this PR and tracked in docs/KNOWN_ISSUES.md — they need either targeted async-cleanup or a test-aware exit handler (evaluated, deferred — that handler is shared infra with real CI-failure duty).

Ratchet gate

coverageThreshold raised to lines/statements 32, branches 28, functions 26.

Toward 50%

33% now. Remaining headroom: the held-back 3 specs once de-leaked, the rest of the dialogs/containers, and ui/main non-webview logic. Each lands as a further wave; the goal is reachable via ui/ without touching the webview/Electron-integration files.

Summary by CodeRabbit

  • Documentation

    • Added a documented workaround for a known test DOM cleanup issue that can cause intermittent Jest failures.
  • Tests

    • Expanded automated coverage across many UI components and utilities with new Jest + React Testing Library specs.
    • Improved test stability via fake-timer handling, clearer teardown, and deterministic setup.
  • Chores

    • Increased global Jest coverage thresholds.
    • Added React Testing Library packages, enabled DOM matchers, and introduced a shared Redux-aware test render helper.

Cumulative progress (full coverage initiative)

This PR is the 4th in a stacked series. Overall increase from the original baseline:

Metric Start Now (this PR) Gain
Lines 17.15% 33.29% +16.1 pts (~1.9×)
Statements 17.67% 33.65% +16.0
Branches 13.18% 29.33% +16.2
Functions 11.87% 27.31% +15.4

Tests: ~282 → 912 (+630).

PR Phase Lines
#3362 Measurement tooling (baseline) 17.15%
#3363 Pure logic — reducers, redaction, classifiers, formatters → 22.34%
#3364 Extract-and-test — logging, screen-share trackers, navigation → 26.34%
#3365 RTL React component tests (this PR) 33.29%

Toward the 50% goal: +16 pts landed, ~17 to go — reachable via further ui/ waves (de-leaking the 3 quarantined specs + remaining dialogs/containers + non-webview ui/main logic), without touching webview/Electron-integration code.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b2497058-151c-4537-bb64-72544914da2b

📥 Commits

Reviewing files that changed from the base of the PR and between 71b221c and 777936f.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (23)
  • docs/KNOWN_ISSUES.md
  • jest.config.js
  • package.json
  • src/.jest/setup.ts
  • src/jest-dom.d.ts
  • src/logging/main/index.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/ui/components/AddServerView/index.spec.tsx
  • src/ui/components/ClearCacheDialog/index.spec.tsx
  • src/ui/components/DownloadsManagerView/DownloadItem.spec.tsx
  • src/ui/components/DownloadsManagerView/index.spec.tsx
  • src/ui/components/Modal/ModalBackdrop.spec.tsx
  • src/ui/components/OutlookCredentialsDialog/index.spec.tsx
  • src/ui/components/ScreenSharingDialog/index.spec.tsx
  • src/ui/components/Shell/index.spec.tsx
  • src/ui/components/SideBar/ServerButton.spec.tsx
  • src/ui/components/SideBar/index.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/ui/components/UpdateDialog/index.spec.tsx
  • src/ui/components/utils/ReparentingContainer.spec.tsx
  • src/ui/components/utils/createAnchor.spec.ts
  • src/ui/test-utils.tsx

Walkthrough

Adds React Testing Library (@testing-library/dom, @testing-library/jest-dom, @testing-library/react, @testing-library/user-event) as dev dependencies, a renderWithStore test helper, jest-dom TypeScript type augmentation, and 13 new component test suites. Fixes timer leaks in existing main-process specs and raises Jest coverage thresholds. Documents an RTL portal-cleanup known issue.

Changes

RTL Test Infrastructure and Component Specs

Layer / File(s) Summary
RTL dependency, setup, types, and test utility
package.json, src/.jest/setup.ts, src/jest-dom.d.ts, src/ui/test-utils.tsx, jest.config.js
Adds @testing-library/* devDependencies, imports jest-dom into the Jest global setup, declares the jest.Matchers TypeScript augmentation for DOM matchers, introduces the renderWithStore helper (with preloadedState support and re-exports of testing-library), and raises coverage thresholds for lines/statements/branches/functions.
Fake-timer leak fixes in existing specs
src/logging/main/index.main.spec.ts, src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts, src/screenSharing/main/desktopCapturerCache.main.spec.ts
Updates beforeEach/afterEach in three existing main-process spec files to switch to fake timers and call jest.clearAllTimers() on teardown, preventing active timer handles from blocking Jest shutdown.
Utility component tests: createAnchor and ReparentingContainer
src/ui/components/utils/createAnchor.spec.ts, src/ui/components/utils/ReparentingContainer.spec.tsx
Adds test suites for createAnchor/deleteAnchor (default tag, reuse, replacement, cleanup callback semantics) and ReparentingContainer (reparenting, ref forwarding, attribute propagation, DOM node reuse, deferred removal with fake timers, unmount cleanup, keyless children).
Dialog and modal component test suites
src/ui/components/Modal/ModalBackdrop.spec.tsx, src/ui/components/ClearCacheDialog/index.spec.tsx, src/ui/components/OutlookCredentialsDialog/index.spec.tsx, src/ui/components/ScreenSharingDialog/index.spec.tsx, src/ui/components/SupportedVersionDialog/index.spec.tsx, src/ui/components/UpdateDialog/index.spec.tsx
Adds RTL test suites for six dialogs/modals, mocking react-i18next, Redux useDispatch, and store listen/request APIs to drive component state and assert action type payloads, UI transitions, and guard behavior.
View and navigation component test suites
src/ui/components/AddServerView/index.spec.tsx, src/ui/components/DownloadsManagerView/DownloadItem.spec.tsx, src/ui/components/DownloadsManagerView/index.spec.tsx, src/ui/components/SideBar/ServerButton.spec.tsx, src/ui/components/SideBar/index.spec.tsx, src/ui/components/Shell/index.spec.tsx
Adds RTL test suites for view and navigation components: online/offline submission flows and error states for AddServerView; DownloadItem IPC action dispatch per download state; DownloadsManagerView rendering, search filtering via seeded localStorage, and back-button dispatch; ServerButton badge display and dropdown action dispatch; SideBar server rendering, selection, and settings menu; Shell layout, theme, transparency, and stylesheet injection.
RTL cleanup known issue documentation
docs/KNOWN_ISSUES.md
Documents the NotFoundError crash caused by manually clearing document.body.innerHTML in afterEach conflicting with RTL's LIFO portal/anchor cleanup, lists affected files, and specifies the unmount()-based workaround.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: introducing React Testing Library and component tests while raising coverage to 33%.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 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 `@src/ui/components/DownloadsManagerView/index.spec.tsx`:
- Around line 152-171: The test 'clears the search filter when the clear-all
button is clicked' currently uses user.type to populate the search field, but
this approach is unstable in this renderer as documented. Instead, seed the
download-search state directly in the preloadedState object passed to
renderWithStore with an initial value of 'beta', then remove the user.type call
entirely. This way the test verifies the actual persisted-filter clearing
behavior without relying on typing interactions, making it deterministic and
testing the real code path.

In `@src/ui/components/utils/createAnchor.spec.ts`:
- Around line 5-7: Remove the manual document.body.innerHTML = '' cleanup from
the afterEach hooks in createAnchor.spec.ts, as this can orphan portal anchors
and cause NotFoundError crashes during RTL cleanup. Instead, rely on React
Testing Library's automatic cleanup by removing these afterEach blocks entirely,
or use component-level cleanup methods like unmount() where needed. This applies
to multiple afterEach hooks in the file (including the ones around lines 5-7 and
54-56).

In `@src/ui/components/utils/ReparentingContainer.spec.tsx`:
- Around line 37-39: The test file is using a type cast to work around a type
mismatch in the ReparentingContainer component. The root issue is that
ReparentingContainerProps does not declare that the component accepts HTML div
attributes, even though it spreads extra props onto its inner div element.
Update the ReparentingContainerProps type definition to extend
React.HTMLAttributes<HTMLDivElement> in addition to its existing properties,
then remove the unnecessary type cast on lines 37-39 where Container is defined
in the test file.
🪄 Autofix (Beta)

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: aeede7c0-fe85-45b3-906e-c2d1feefd02e

📥 Commits

Reviewing files that changed from the base of the PR and between 35bacdd and 71b221c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (23)
  • docs/KNOWN_ISSUES.md
  • jest.config.js
  • package.json
  • src/.jest/setup.ts
  • src/jest-dom.d.ts
  • src/logging/main/index.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/ui/components/AddServerView/index.spec.tsx
  • src/ui/components/ClearCacheDialog/index.spec.tsx
  • src/ui/components/DownloadsManagerView/DownloadItem.spec.tsx
  • src/ui/components/DownloadsManagerView/index.spec.tsx
  • src/ui/components/Modal/ModalBackdrop.spec.tsx
  • src/ui/components/OutlookCredentialsDialog/index.spec.tsx
  • src/ui/components/ScreenSharingDialog/index.spec.tsx
  • src/ui/components/Shell/index.spec.tsx
  • src/ui/components/SideBar/ServerButton.spec.tsx
  • src/ui/components/SideBar/index.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/ui/components/UpdateDialog/index.spec.tsx
  • src/ui/components/utils/ReparentingContainer.spec.tsx
  • src/ui/components/utils/createAnchor.spec.ts
  • src/ui/test-utils.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Use TypeScript for all new code unless explicitly told otherwise
Use optional chaining with fallbacks for platform-specific APIs instead of mocking when possible. Example: const uid = process.getuid?.() ?? 1000;

Files:

  • src/jest-dom.d.ts
  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/ui/components/utils/createAnchor.spec.ts
  • src/logging/main/index.main.spec.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{tsx,ts}: MANDATORY: Use Fuselage components for all UI work. Only create custom components when Fuselage doesn't provide what's needed
Import UI components from @rocket.chat/fuselage and check Theme.d.ts for valid color tokens
Use React functional components with hooks
Use PascalCase for component file names

Files:

  • src/jest-dom.d.ts
  • src/ui/components/ScreenSharingDialog/index.spec.tsx
  • src/ui/components/OutlookCredentialsDialog/index.spec.tsx
  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/ui/components/DownloadsManagerView/DownloadItem.spec.tsx
  • src/ui/components/Modal/ModalBackdrop.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/ui/components/utils/createAnchor.spec.ts
  • src/ui/components/UpdateDialog/index.spec.tsx
  • src/logging/main/index.main.spec.ts
  • src/ui/components/SideBar/ServerButton.spec.tsx
  • src/ui/components/Shell/index.spec.tsx
  • src/ui/components/AddServerView/index.spec.tsx
  • src/ui/components/ClearCacheDialog/index.spec.tsx
  • src/ui/components/DownloadsManagerView/index.spec.tsx
  • src/ui/components/utils/ReparentingContainer.spec.tsx
  • src/ui/test-utils.tsx
  • src/ui/components/SideBar/index.spec.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Redux actions must follow FSA (Flux Standard Action) pattern
Avoid unnecessary comments — write self-documenting code through clear naming
Always verify libraries by checking official docs and .d.ts files in node_modules/. Never assume props, tokens, or APIs work without verification
Avoid subjective descriptors ('smart', 'excellent', 'dumb') in documentation and comments
Use measurable descriptions in code documentation: 'reduced memory usage', 'improved by X%' instead of subjective claims
NEVER invent metrics — don't include estimated time spent or speculated user counts. Only include numbers from actual logs, error messages, or documented sources

Files:

  • src/jest-dom.d.ts
  • src/ui/components/ScreenSharingDialog/index.spec.tsx
  • src/ui/components/OutlookCredentialsDialog/index.spec.tsx
  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/ui/components/DownloadsManagerView/DownloadItem.spec.tsx
  • src/ui/components/Modal/ModalBackdrop.spec.tsx
  • src/ui/components/SupportedVersionDialog/index.spec.tsx
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/ui/components/utils/createAnchor.spec.ts
  • src/ui/components/UpdateDialog/index.spec.tsx
  • src/logging/main/index.main.spec.ts
  • src/ui/components/SideBar/ServerButton.spec.tsx
  • src/ui/components/Shell/index.spec.tsx
  • src/ui/components/AddServerView/index.spec.tsx
  • src/ui/components/ClearCacheDialog/index.spec.tsx
  • src/ui/components/DownloadsManagerView/index.spec.tsx
  • src/ui/components/utils/ReparentingContainer.spec.tsx
  • src/ui/test-utils.tsx
  • src/ui/components/SideBar/index.spec.tsx
**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.spec.ts file naming for Renderer process tests

Files:

  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/ui/components/utils/createAnchor.spec.ts
  • src/logging/main/index.main.spec.ts
**/*.main.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use *.main.spec.ts file naming for Main process tests

Files:

  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/logging/main/index.main.spec.ts
**/*.{spec.ts,main.spec.ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Only mock platform-specific APIs when defensive coding isn't possible. Linux-only APIs requiring mocks: process.getuid(), process.getgid(), process.geteuid(), process.getegid()

Files:

  • src/screenSharing/main/desktopCapturerCache.main.spec.ts
  • src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts
  • src/ui/components/utils/createAnchor.spec.ts
  • src/logging/main/index.main.spec.ts
🪛 ast-grep (0.44.0)
src/ui/components/utils/createAnchor.spec.ts

[warning] 5-5: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.body.innerHTML = ''
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation

(dom-content-modification)


[warning] 54-54: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.body.innerHTML = ''
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation

(dom-content-modification)

🔇 Additional comments (18)
package.json (1)

114-117: LGTM!

src/.jest/setup.ts (1)

3-3: LGTM!

src/jest-dom.d.ts (1)

1-22: LGTM!

src/ui/test-utils.tsx (1)

1-55: LGTM!

jest.config.js (1)

15-18: LGTM!

src/logging/main/index.main.spec.ts (1)

130-133: LGTM!

Also applies to: 147-155

src/screenSharing/main/ScreenSharingRequestTracker.main.spec.ts (1)

44-57: LGTM!

src/screenSharing/main/desktopCapturerCache.main.spec.ts (1)

61-64: LGTM!

src/ui/components/utils/createAnchor.spec.ts (1)

9-51: LGTM!

Also applies to: 58-86

src/ui/components/utils/ReparentingContainer.spec.tsx (1)

1-33: LGTM!

Also applies to: 41-159

docs/KNOWN_ISSUES.md (1)

22-41: LGTM!

src/ui/components/Modal/ModalBackdrop.spec.tsx (1)

1-147: LGTM!

src/ui/components/ClearCacheDialog/index.spec.tsx (1)

1-158: LGTM!

src/ui/components/OutlookCredentialsDialog/index.spec.tsx (1)

1-194: LGTM!

src/ui/components/ScreenSharingDialog/index.spec.tsx (1)

1-117: LGTM!

src/ui/components/SupportedVersionDialog/index.spec.tsx (1)

1-167: LGTM!

src/ui/components/UpdateDialog/index.spec.tsx (1)

1-102: LGTM!

src/ui/components/AddServerView/index.spec.tsx (1)

154-157: No action needed — both enum members are valid and correctly used.

The enum ServerUrlResolutionStatus defines both INVALID_URL and INVALID as valid members. The test case on line 156 correctly uses ServerUrlResolutionStatus.INVALID, which is properly declared and consistent with its usage elsewhere in the codebase.

Comment on lines +152 to +171
it('clears the search filter when the clear-all button is clicked', async () => {
const user = userEvent.setup();
renderWithStore(<DownloadsManagerView />, {
preloadedState: populatedState,
});

const search = screen.getByLabelText(
'downloads.filters.search'
) as HTMLInputElement;
await user.type(search, 'beta');
expect(search.value).toBe('beta');

await user.click(
screen.getByRole('button', { name: 'downloads.filters.clear' })
);

expect(search.value).toBe('');
expect(screen.getByTestId('download-item-1')).toBeInTheDocument();
expect(screen.getByTestId('download-item-2')).toBeInTheDocument();
});

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the clear-filter test deterministic by seeding initial filter state.

This case currently uses user.type even though this file documents typing/state sync instability in this renderer. Seed download-search before render, then clear it; that verifies the real persisted-filter path.

Proposed adjustment
   it('clears the search filter when the clear-all button is clicked', async () => {
     const user = userEvent.setup();
+    seedFilter('download-search', 'beta');
     renderWithStore(<DownloadsManagerView />, {
       preloadedState: populatedState,
     });
 
     const search = screen.getByLabelText(
       'downloads.filters.search'
     ) as HTMLInputElement;
-    await user.type(search, 'beta');
     expect(search.value).toBe('beta');
 
     await user.click(
       screen.getByRole('button', { name: 'downloads.filters.clear' })
     );
🤖 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 `@src/ui/components/DownloadsManagerView/index.spec.tsx` around lines 152 -
171, The test 'clears the search filter when the clear-all button is clicked'
currently uses user.type to populate the search field, but this approach is
unstable in this renderer as documented. Instead, seed the download-search state
directly in the preloadedState object passed to renderWithStore with an initial
value of 'beta', then remove the user.type call entirely. This way the test
verifies the actual persisted-filter clearing behavior without relying on typing
interactions, making it deterministic and testing the real code path.

Comment on lines +5 to +7
afterEach(() => {
document.body.innerHTML = '';
});

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove manual document.body.innerHTML cleanup; it can crash the suite.

These afterEach hooks can orphan portal anchors before RTL cleanup runs, triggering NotFoundError during unmount and aborting the run. Use component-level cleanup (unmount()/anchor-specific cleanup) instead of wiping document.body.

Suggested change
 describe('createAnchor', () => {
-  afterEach(() => {
-    document.body.innerHTML = '';
-  });
-
   it('creates a div anchor by default and appends it to the body', () => {
     const anchor = createAnchor('anchor-default');
@@
 describe('deleteAnchor', () => {
-  afterEach(() => {
-    document.body.innerHTML = '';
-  });
-
   it('invokes the cleanup callback registered for the element', () => {

Also applies to: 54-56

🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 5-5: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: document.body.innerHTML = ''
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation

(dom-content-modification)

🤖 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 `@src/ui/components/utils/createAnchor.spec.ts` around lines 5 - 7, Remove the
manual document.body.innerHTML = '' cleanup from the afterEach hooks in
createAnchor.spec.ts, as this can orphan portal anchors and cause NotFoundError
crashes during RTL cleanup. Instead, rely on React Testing Library's automatic
cleanup by removing these afterEach blocks entirely, or use component-level
cleanup methods like unmount() where needed. This applies to multiple afterEach
hooks in the file (including the ones around lines 5-7 and 54-56).

Comment on lines +37 to +39
const Container = ReparentingContainer as unknown as React.FC<
React.HTMLAttributes<HTMLDivElement> & { children?: React.ReactNode }
>;

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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the contract mismatch and where test-side casts are used.
set -euo pipefail

fd -i 'ReparentingContainer.tsx' -x sed -n '1,140p' {}
echo '---'
rg -n -C3 'as unknown as React\\.FC|HTMLAttributes<HTMLDivElement>' src/ui/components/utils
echo '---'
rg -n -C3 'ReparentingContainer\\s*=\\s*forwardRef|type\\s+ReparentingContainerProps' src/ui/components/utils

Repository: RocketChat/Rocket.Chat.Electron

Length of output: 3778


Fix the component prop type instead of casting to React.FC in the test.

The component spreads extra props onto its inner div at runtime but declares only children in its prop type. Update ReparentingContainerProps to include React.HTMLAttributes<HTMLDivElement>, then remove the test-side cast on lines 37-39.

🤖 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 `@src/ui/components/utils/ReparentingContainer.spec.tsx` around lines 37 - 39,
The test file is using a type cast to work around a type mismatch in the
ReparentingContainer component. The root issue is that ReparentingContainerProps
does not declare that the component accepts HTML div attributes, even though it
spreads extra props onto its inner div element. Update the
ReparentingContainerProps type definition to extend
React.HTMLAttributes<HTMLDivElement> in addition to its existing properties,
then remove the unnecessary type cast on lines 37-39 where Container is defined
in the test file.

@jeanfbrito
jeanfbrito force-pushed the chore/coverage-phase2-extract branch from 35bacdd to c263950 Compare June 22, 2026 16:24
Base automatically changed from chore/coverage-phase2-extract to master June 22, 2026 16:24
Sets up component testing so the renderer layer can be covered.

- Add devDeps: @testing-library/react 14.3.1, jest-dom 6.9.1,
  user-event 14.6.1, dom 9.3.4 (React 18 compatible)
- Import @testing-library/jest-dom in src/.jest/setup.ts for DOM matchers
- src/jest-dom.d.ts: register jest-dom matcher types for tsc (the dotted
  .jest dir is excluded from the TS program, so the augmentation lives
  in an included path)
- src/ui/test-utils.tsx: renderWithStore() helper wrapping components in
  a redux Provider with preloaded state; re-exports RTL + userEvent;
  documents the react-i18next mock snippet for component specs
- Example spec: ServersView/ErrorView.spec.tsx proves the pattern

RTL works out-of-box under @kayahr/jest-electron-runner (real renderer
DOM, no jsdom, no jest.config change). 807 tests pass, lint clean.
Adds RTL behavior tests for 14 renderer components — dialogs (Update,
ScreenSharing, ClearCache, SupportedVersion, OutlookCredentials),
containers (DownloadsManagerView, AddServerView, SideBar, Shell), leaf
components (DownloadItem, ModalBackdrop, ServerButton) and the ui/utils
helpers (createAnchor, ReparentingContainer).

Also hardens 3 main-process specs (logging/index, ScreenSharingRequest-
Tracker, desktopCapturerCache) with fake timers + afterEach cleanup —
a real setInterval in logging/index.ts was leaking ref'd handles across
isolateModules reloads and hanging the suite past --forceExit.

Ratchets coverageThreshold to lines/statements 32, branches 28,
functions 26.

Coverage: lines 26.72% -> 33.29%, statements -> 33.65%, branches ->
29.33%, functions -> 27.31%. 912 tests pass, 2 skipped, 52 suites.

Three component specs (ErrorView, ServerInfoContent, AboutDialog) are
held back — they leak async/DOM teardown that the strict uncaught-
exception handler in src/.jest/setup.ts turns into a process.exit(1);
tracked in docs/KNOWN_ISSUES.md for a follow-up.
@jeanfbrito
jeanfbrito force-pushed the chore/coverage-phase3-rtl-infra branch from 71b221c to 777936f Compare June 22, 2026 16:25
@jeanfbrito
jeanfbrito merged commit d7a3cfe into master Jun 22, 2026
6 of 8 checks passed
@jeanfbrito
jeanfbrito deleted the chore/coverage-phase3-rtl-infra branch June 22, 2026 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant