Skip to content

Frontend: integrate Vitest and React Testing Library architecture#615

Open
Xploit-Ghost wants to merge 5 commits into
GitMetricsLab:mainfrom
Xploit-Ghost:main
Open

Frontend: integrate Vitest and React Testing Library architecture#615
Xploit-Ghost wants to merge 5 commits into
GitMetricsLab:mainfrom
Xploit-Ghost:main

Conversation

@Xploit-Ghost
Copy link
Copy Markdown

@Xploit-Ghost Xploit-Ghost commented May 29, 2026

Description

This PR introduces the foundational testing suite for the React/Vite frontend using Vitest and React Testing Library, addressing the frontend UI reliability requirements outlined in #613.

Changes Made

  • Scripts: Added the test:client script to package.json for unified frontend test execution.
  • Component Tests: Wrote foundational UI unit tests for the Navbar component (handling ThemeContext and MemoryRouter wrapping) and the ActivityFeed component (mocking the global fetch API for asynchronous state testing).
  • Documentation: Updated README.md with the new frontend testing commands to parallel the existing backend documentation.

Related Issue

Resolves #613

Summary by CodeRabbit

  • Documentation

    • Updated Setup Guide with frontend testing commands and information on testing tools.
  • Tests

    • Added test suites for ActivityFeed and Navbar components.
  • Chores

    • Added npm run test:client script to run frontend tests.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@Xploit-Ghost, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 26 minutes and 18 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eb7cf3ad-f9af-4c21-bdbd-0852dab008be

📥 Commits

Reviewing files that changed from the base of the PR and between 746ba66 and a5ce1ec.

📒 Files selected for processing (1)
  • src/components/ActivityFeed.test.tsx
📝 Walkthrough

Walkthrough

This PR implements frontend unit testing infrastructure for the React components using Vitest and React Testing Library. It adds a new test:client npm script, updates the README with testing guidance, and introduces test suites for ActivityFeed and Navbar components covering loading states, successful data rendering, and user interactions.

Changes

Frontend Unit Testing Suite

Layer / File(s) Summary
Testing Infrastructure Setup
package.json, README.md
test:client npm script is added to run Vitest; README Setup Guide now documents frontend testing tools (Vitest + React Testing Library) and provides the test execution command.
ActivityFeed Component Tests
src/components/ActivityFeed.test.tsx
Tests verify the loading state display, successful event rendering (including emoji labels and repository names), and empty-result fallback messaging using mocked global fetch.
Navbar Component Tests
src/components/Navbar.test.tsx
A renderWithProviders helper wraps tests with ThemeContext and MemoryRouter; tests verify brand/logo rendering, desktop navigation labels, theme toggle presence, and mobile menu open/close behavior with keyboard/click interactions.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • GitMetricsLab/github_tracker#277: Both PRs implement Vitest/React Testing Library frontend testing with Navbar test suites and related package.json script configuration.

Suggested labels

level:intermediate, quality:clean

Poem

🐰 A test suite hops in with care,
Vitest and RTL declare,
ActivityFeed and Navbar now shine,
With mocks and assertions so fine,
No bugs shall escape our snare!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: integrating Vitest and React Testing Library for frontend testing, which aligns with the primary objective of the PR.
Description check ✅ Passed The description covers the main changes (scripts, component tests, documentation), references the related issue (#613), but does not fully follow the template structure with explicit sections like 'How Has This Been Tested?' and 'Type of Change'.
Linked Issues check ✅ Passed The PR successfully addresses all core coding requirements from issue #613: Vitest and React Testing Library integration, component tests for UI components (Navbar and ActivityFeed with proper mocking/wrapping), test:client script, and README documentation updates.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the scope of issue #613: test infrastructure setup, test files, npm script addition, and documentation updates for frontend testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@netlify
Copy link
Copy Markdown

netlify Bot commented May 29, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit a5ce1ec
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a19d8b73354d900071f4c74
😎 Deploy Preview https://deploy-preview-615--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🎉 Thank you @Xploit-Ghost for your contribution. Please make sure your PR follows https://github.com/GitMetricsLab/github_tracker/blob/main/CONTRIBUTING.md#-pull-request-guidelines

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
src/components/Navbar.test.tsx (3)

35-42: ⚡ Quick win

Strengthen the theme toggle assertion.

The test only verifies that at least one toggle button exists (length > 0), but the comment states there should be two (desktop + mobile). Use a specific assertion.

♻️ Proposed fix
   it('renders the correct theme toggle icon based on context', () => {
     // Render with dark mode
     renderWithProviders(<Navbar />, 'dark');
     const toggleButtons = screen.getAllByLabelText('Toggle Theme');
     
-    // Check that the toggle buttons are present (one for desktop, one for mobile)
-    expect(toggleButtons.length).toBeGreaterThan(0);
+    // Check that there are exactly two toggle buttons (one for desktop, one for mobile)
+    expect(toggleButtons).toHaveLength(2);
   });
🤖 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/components/Navbar.test.tsx` around lines 35 - 42, The test for Navbar's
theme toggle uses a weak assertion
(expect(toggleButtons.length).toBeGreaterThan(0)); update it to assert exactly
two toggles are rendered (desktop + mobile) by replacing that check with
expect(toggleButtons).toHaveLength(2). Locate the check in the test that calls
renderWithProviders(<Navbar />, 'dark') and uses
screen.getAllByLabelText('Toggle Theme'); ensure the assertion uses
toHaveLength(2) and optionally add a second assertion that each button displays
the expected icon/text for the 'dark' context if you want to validate icon
correctness.

8-18: ⚡ Quick win

Return mockToggleTheme from the helper to enable interaction verification.

The mockToggleTheme function is created but not returned, preventing tests from verifying that theme toggle interactions actually call toggleTheme. Return it alongside the render result.

♻️ Proposed enhancement
-const renderWithProviders = (ui: React.ReactElement, themeMode: 'light' | 'dark' = 'light') => {
+const renderWithProviders = (ui: React.ReactElement, themeMode: 'light' | 'dark' = 'light') => {
   const mockToggleTheme = vi.fn();
   
-  return render(
+  const renderResult = render(
     <ThemeContext.Provider value={{ mode: themeMode, toggleTheme: mockToggleTheme }}>
       <MemoryRouter>
         {ui}
       </MemoryRouter>
     </ThemeContext.Provider>
   );
+  
+  return { ...renderResult, mockToggleTheme };
 };

Then tests can verify toggle behavior:

it('calls toggleTheme when theme toggle button is clicked', () => {
  const { mockToggleTheme } = renderWithProviders(<Navbar />);
  const toggleButton = screen.getAllByLabelText('Toggle Theme')[0];
  fireEvent.click(toggleButton);
  expect(mockToggleTheme).toHaveBeenCalledTimes(1);
});
🤖 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/components/Navbar.test.tsx` around lines 8 - 18, The helper
renderWithProviders creates mockToggleTheme but does not return it, preventing
tests from asserting toggle calls; update renderWithProviders to return the
render result together with mockToggleTheme (e.g., return an object containing
the result of render(...) and the mockToggleTheme) so callers of
renderWithProviders can destructure { mockToggleTheme } and assert calls to
toggleTheme when interacting with the Navbar.

44-53: ⚡ Quick win

Use a more robust assertion for mobile menu visibility.

Counting "Home" text occurrences is fragile and could break if the desktop navigation changes. Consider querying for a mobile-specific container, role, or data-testid instead.

♻️ Alternative approach

If the mobile menu has a specific container or role:

it('opens mobile menu when hamburger icon is clicked', () => {
  renderWithProviders(<Navbar />);
  
  const menuButton = screen.getByLabelText('Toggle Menu');
  
  // Verify menu is initially not visible (adjust selector based on actual implementation)
  expect(screen.queryByRole('navigation', { name: /mobile/i })).not.toBeInTheDocument();
  
  fireEvent.click(menuButton);
  
  // Verify mobile menu is now visible
  expect(screen.getByRole('navigation', { name: /mobile/i })).toBeInTheDocument();
});

Or if the Navbar component accepts adding data-testid:

// In the component, add data-testid="mobile-menu" to the mobile menu container
expect(screen.getByTestId('mobile-menu')).toBeVisible();
🤖 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/components/Navbar.test.tsx` around lines 44 - 53, The test in
Navbar.test.tsx is fragile because it counts 'Home' occurrences; update the test
for Navbar to assert the mobile menu visibility using a mobile-specific selector
(e.g., a role or data-testid) instead of text counts:
renderWithProviders(<Navbar />), assert the mobile nav container (e.g.,
role="navigation" with accessible name containing "mobile" or
data-testid="mobile-menu") is initially not present/visible, fireEvent.click on
the menu toggle (label 'Toggle Menu'), then assert that getByRole/getByTestId
for the mobile menu container is now present and visible; modify the Navbar
component to add a data-testid="mobile-menu" or an accessible name on the mobile
navigation container if needed.
package.json (1)

11-12: ⚡ Quick win

Clarify the distinction between test and test:client scripts.

Both scripts execute the same command (vitest), creating ambiguity about which to use. Consider either:

  1. Updating the test script to run both frontend and backend tests (e.g., "test": "npm run test:client && npm run test:backend"), OR
  2. Removing the test script entirely if test:client and test:backend are sufficient.
♻️ Proposed fix (Option 1: run both test suites)
-    "test": "vitest",
+    "test": "npm run test:client && npm run test:backend",
     "test:client": "vitest",
🤖 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 `@package.json` around lines 11 - 12, The package.json currently has duplicate
scripts ("test" and "test:client") both running vitest; update the "test" script
to run both frontend and backend suites by chaining the existing "test:client"
and a new/expected "test:backend" (e.g., make "test" invoke "npm run
test:client" and "npm run test:backend"), and if "test:backend" doesn't exist
add it to run the backend test runner; alternatively, if you prefer separate
commands remove the redundant "test" script—adjust the "test", "test:client",
and "test:backend" entries accordingly.
src/components/ActivityFeed.test.tsx (1)

16-55: ⚡ Quick win

Add test coverage for fetch error scenarios.

The test suite covers loading, success, and empty results, but doesn't verify error handling when fetch rejects (network failures, API errors, etc.). If ActivityFeed implements error handling, it should be tested.

🧪 Suggested error handling test
it('displays an error message when fetch fails', async () => {
  vi.mocked(global.fetch).mockRejectedValueOnce(new Error('Network error'));
  
  render(<ActivityFeed username="testuser" />);
  
  await waitFor(() => {
    expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
  });
  
  // Adjust the expected error message based on ActivityFeed's actual error UI
  expect(screen.getByText(/error|failed/i)).toBeInTheDocument();
});
🤖 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/components/ActivityFeed.test.tsx` around lines 16 - 55, Add a new test to
ActivityFeed.test.tsx that asserts the component shows an error UI when fetch
rejects: mock global.fetch to reject (e.g., mockRejectedValueOnce(new
Error('Network error'))), render <ActivityFeed username="testuser" />, wait for
the loading indicator to disappear with waitFor, and then assert that the error
message element (match by text pattern like /error|failed/i or whatever
ActivityFeed renders on errors) is present; place it alongside the existing
tests so the suite covers the fetch failure path for the ActivityFeed component.
🤖 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/components/ActivityFeed.test.tsx`:
- Line 22: The tests currently cast global.fetch to any (e.g., (global.fetch as
any).mockResolvedValueOnce(...)) and return a minimal object lacking standard
Response fields; replace these with a properly typed mock by using
vi.mocked(global.fetch) (or cast to MockedFunction) and mockResolvedValueOnce
with a full Response-like object containing ok, status, statusText and json:
async () => <payload>; update each occurrence referenced (the mocks around
ActivityFeed.test.tsx lines where fetch is mocked) to return this typed mock so
ESLint/type checks pass and components relying on response.ok/status behave
correctly.
- Line 5: The test replaces global.fetch with vi.fn() but never restores it,
causing leaks; capture the original fetch (e.g., const originalFetch =
global.fetch) before mocking and add an afterEach or afterAll hook in
ActivityFeed.test.tsx that restores global.fetch = originalFetch and restores
mocks (vi.restoreAllMocks() or similar) so other tests aren't affected.

---

Nitpick comments:
In `@package.json`:
- Around line 11-12: The package.json currently has duplicate scripts ("test"
and "test:client") both running vitest; update the "test" script to run both
frontend and backend suites by chaining the existing "test:client" and a
new/expected "test:backend" (e.g., make "test" invoke "npm run test:client" and
"npm run test:backend"), and if "test:backend" doesn't exist add it to run the
backend test runner; alternatively, if you prefer separate commands remove the
redundant "test" script—adjust the "test", "test:client", and "test:backend"
entries accordingly.

In `@src/components/ActivityFeed.test.tsx`:
- Around line 16-55: Add a new test to ActivityFeed.test.tsx that asserts the
component shows an error UI when fetch rejects: mock global.fetch to reject
(e.g., mockRejectedValueOnce(new Error('Network error'))), render <ActivityFeed
username="testuser" />, wait for the loading indicator to disappear with
waitFor, and then assert that the error message element (match by text pattern
like /error|failed/i or whatever ActivityFeed renders on errors) is present;
place it alongside the existing tests so the suite covers the fetch failure path
for the ActivityFeed component.

In `@src/components/Navbar.test.tsx`:
- Around line 35-42: The test for Navbar's theme toggle uses a weak assertion
(expect(toggleButtons.length).toBeGreaterThan(0)); update it to assert exactly
two toggles are rendered (desktop + mobile) by replacing that check with
expect(toggleButtons).toHaveLength(2). Locate the check in the test that calls
renderWithProviders(<Navbar />, 'dark') and uses
screen.getAllByLabelText('Toggle Theme'); ensure the assertion uses
toHaveLength(2) and optionally add a second assertion that each button displays
the expected icon/text for the 'dark' context if you want to validate icon
correctness.
- Around line 8-18: The helper renderWithProviders creates mockToggleTheme but
does not return it, preventing tests from asserting toggle calls; update
renderWithProviders to return the render result together with mockToggleTheme
(e.g., return an object containing the result of render(...) and the
mockToggleTheme) so callers of renderWithProviders can destructure {
mockToggleTheme } and assert calls to toggleTheme when interacting with the
Navbar.
- Around line 44-53: The test in Navbar.test.tsx is fragile because it counts
'Home' occurrences; update the test for Navbar to assert the mobile menu
visibility using a mobile-specific selector (e.g., a role or data-testid)
instead of text counts: renderWithProviders(<Navbar />), assert the mobile nav
container (e.g., role="navigation" with accessible name containing "mobile" or
data-testid="mobile-menu") is initially not present/visible, fireEvent.click on
the menu toggle (label 'Toggle Menu'), then assert that getByRole/getByTestId
for the mobile menu container is now present and visible; modify the Navbar
component to add a data-testid="mobile-menu" or an accessible name on the mobile
navigation container if needed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4eeeb1ba-a4fc-4b54-beac-5731e39a1ce4

📥 Commits

Reviewing files that changed from the base of the PR and between e7b8fc8 and 746ba66.

📒 Files selected for processing (4)
  • README.md
  • package.json
  • src/components/ActivityFeed.test.tsx
  • src/components/Navbar.test.tsx

Comment thread src/components/ActivityFeed.test.tsx Outdated
Comment thread src/components/ActivityFeed.test.tsx Outdated
Refactor fetch mocking in ActivityFeed tests to use a helper function for creating mock responses and ensure original fetch is restored after tests.
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.

Enhancement: Implement Frontend Unit Testing Suite using Vitest and React Testing Library

1 participant