Skip to content

set up vitest + RTL, added Navbar tests#277

Merged
mehul-m-prajapati merged 2 commits into
GitMetricsLab:mainfrom
parinaB:main
May 17, 2026
Merged

set up vitest + RTL, added Navbar tests#277
mehul-m-prajapati merged 2 commits into
GitMetricsLab:mainfrom
parinaB:main

Conversation

@parinaB
Copy link
Copy Markdown
Contributor

@parinaB parinaB commented May 16, 2026

Related Issue


Description

The frontend had zero test coverage — no test runner, no configuration, no test files. This PR sets up the complete testing infrastructure and adds the first test suite for the Navbar component.

Changes made:

  • Installed vitest, @testing-library/react, @testing-library/user-event, @testing-library/jest-dom, jsdom as dev dependencies
  • Added test block to vite.config.ts with jsdom environment
  • Created src/setupTests.ts to load jest-dom matchers
  • Added "test": "vitest" script to package.json
  • Created src/components/__test__/Navbar.test.tsx

How Has This Been Tested?

Ran npm test locally. All 9 tests pass.

Test Files  1 passed
Tests       9 passed

Tests cover:

  • Logo and nav links render correctly
  • Theme toggle calls toggleTheme on click
  • Mobile menu opens and closes correctly
  • Null guard when ThemeContext is missing

Screenshots (if applicable)

Screenshot 2026-05-16 at 4 37 10 PM

Note: spec/auth.routes.spec.cjs and spec/user.model.spec.cjs backend tests are failing but are pre-existing failures unrelated to this PR. I'll open a separate issue to track those.


Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

  • Tests
    • Added comprehensive navigation component tests and test setup for DOM matchers.
    • Configured project test runner and environment for frontend and backend tests; updated backend test command.
  • Chores
    • Added frontend testing dev dependencies and test environment tooling.
  • Refactor
    • Simplified user save behavior implementation (internal refactor; no public API changes).

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 16, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit d390578
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a095c8ea71e3b0008f40fd6
😎 Deploy Preview https://deploy-preview-277--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.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1d456af-615c-42ca-82fe-3aee6d7f22fe

📥 Commits

Reviewing files that changed from the base of the PR and between 634daa6 and d390578.

📒 Files selected for processing (5)
  • backend/models/User.js
  • backend/package.json
  • package.json
  • spec/auth.routes.spec.cjs
  • spec/user.model.spec.cjs
✅ Files skipped from review due to trivial changes (1)
  • backend/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json

📝 Walkthrough

Walkthrough

Adds Vitest and React Testing Library to the frontend (scripts, deps, vite test config, setup file) and a comprehensive Navbar test suite; updates backend test script/specs and refactors the User model pre-save hook to an async implementation.

Changes

Test Infrastructure & Backend Adjustments

Layer / File(s) Summary
Frontend test scripts & dependencies
package.json
Adds test (vitest) and test:backend scripts; adds @testing-library/jest-dom, @testing-library/react, @testing-library/user-event, jsdom, and vitest devDependencies; updates related devDependency versions.
Vitest config and setup file
vite.config.ts, src/setupTests.ts
Extends vite.config.ts with test block (globals, jsdom environment, setupFiles), and adds src/setupTests.ts importing @testing-library/jest-dom.
Navbar component tests
src/components/__test__/Navbar.test.tsx
Adds tests rendering Navbar inside MemoryRouter with mocked ThemeContext; covers desktop links, theme toggle clicks, mobile menu open/close, mobile theme toggle, and behavior when ThemeContext is missing.
Backend test script, specs, and model hook
backend/package.json, spec/*.spec.cjs, backend/models/User.js
Updates backend scripts.test to run Jasmine; simplifies mongoose.connect calls in spec/auth.routes.spec.cjs and spec/user.model.spec.cjs by removing legacy options; refactors UserSchema.pre('save') hook to an async early-return implementation that hashes password when modified.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

gssoc25, level1

Poem

🐰
I hopped in code to add a test,
Vitest awake, the suite impressed,
Navbar clicks in day and night,
Backend specs now run just right,
A tiny rabbit cheers the rest.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: setting up vitest + React Testing Library (RTL) and adding the first test suite for Navbar.
Description check ✅ Passed The description follows the template with all required sections: Related Issue, Description, How Has This Been Tested, and Type of Change; additional context and screenshots are provided.
Linked Issues check ✅ Passed All coding requirements from issue #275 are met: vitest + RTL dependencies added, vite.config.ts configured with test block and jsdom, setup file created, test script added, and Navbar test suite provided.
Out of Scope Changes check ✅ Passed The PR includes backend test infrastructure updates (User.js pre-hook refactor, mongoose connection cleanup) that are not directly required by issue #275 but align with modernizing the test suite.
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.

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 @parinaB 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.

🧹 Nitpick comments (4)
src/components/__test__/Navbar.test.tsx (4)

69-70: ⚡ Quick win

Replace brittle link selector based on array position.

Lines 69–70 select the mobile "Home" link by getting all links with that name and clicking the last one (homeLinks[homeLinks.length - 1]). This assumes the mobile link is always last, which is fragile and will break if link order changes.

Consider using a scoped query within the mobile menu container or adding a test ID to distinguish desktop from mobile links.

♻️ Example with scoped query

If the mobile menu has a container with a test ID or role:

 fireEvent.click(hamburger)                          // open
-const homeLinks = screen.getAllByRole('link', { name: /home/i })
-fireEvent.click(homeLinks[homeLinks.length - 1]) // click the mobile one
+const mobileMenu = screen.getByRole('navigation', { name: /mobile/i })
+const mobileHomeLink = within(mobileMenu).getByRole('link', { name: /home/i })
+fireEvent.click(mobileHomeLink)
 expect(screen.queryByText('About')).not.toBeInTheDocument()  // closed

You'll need to import within from @testing-library/react.

🤖 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/__test__/Navbar.test.tsx` around lines 69 - 70, The test
currently finds the mobile "Home" link by array position (homeLinks =
screen.getAllByRole('link', { name: /home/i }) and clicking
homeLinks[homeLinks.length - 1]), which is brittle; change the test to scope the
query to the mobile menu container (e.g., use within on the mobile menu element
or a specific data-testid for the mobile link) and then query that scoped
container for the "Home" link, or add a distinct test id to the mobile link and
use getByTestId; remember to import within from `@testing-library/react` if you
use scoped queries and update the click to target the scoped/mobile element
instead of indexing the whole list.

40-41: ⚡ Quick win

Replace brittle array-index selector with a specific query.

Lines 40 and 46 select the theme button using screen.getAllByRole('button')[0], which assumes the theme button is always the first button in the DOM. This will break if button order changes.

Consider querying by accessible name or adding an aria-label to the theme button in the component.

♻️ Example with aria-label

If the Navbar component adds an aria-label to the theme button:

<button aria-label="Toggle theme" onClick={toggleTheme}>
  {mode === 'light' ? <Moon /> : <Sun />}
</button>

Then update the test:

-const themeBtn = screen.getAllByRole('button')[0]
+const themeBtn = screen.getByRole('button', { name: /toggle theme/i })
 expect(themeBtn).toBeInTheDocument()

Also applies to: 46-46

🤖 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/__test__/Navbar.test.tsx` around lines 40 - 41, The test is
using a brittle index-based selector for the theme button; update Navbar and its
tests so the button has an accessible name (e.g., add aria-label="Toggle theme"
on the theme toggle in the Navbar component where toggleTheme/mode/Moon/Sun are
used) and replace screen.getAllByRole('button')[0] in Navbar.test.tsx with a
specific query such as screen.getByRole('button', { name: /toggle theme/i }) or
screen.getByLabelText('Toggle theme') to reliably target the themeBtn.

2-2: ⚡ Quick win

Prefer userEvent over fireEvent for more realistic interactions.

The test suite uses fireEvent.click throughout (lines 47, 60, 68, 70, 77, 78), but React Testing Library best practices recommend userEvent for simulating actual browser behavior—including focus, hover, and timing—rather than synchronous DOM event dispatch.

Since @testing-library/user-event is already installed (per PR objectives), consider migrating to it for higher-fidelity tests.

♻️ Example migration for one test
-import { render, screen, fireEvent } from '`@testing-library/react`'
+import { render, screen } from '`@testing-library/react`'
+import userEvent from '`@testing-library/user-event`'
 import { describe, it, expect, vi, beforeEach } from 'vitest'

Then in a test:

-it('calls toggleTheme when the theme button is clicked', () => {
+it('calls toggleTheme when the theme button is clicked', async () => {
   const { toggleTheme } = renderNavbar('light')
   const themeBtn = screen.getAllByRole('button')[0]
-  fireEvent.click(themeBtn)
+  await userEvent.click(themeBtn)
   expect(toggleTheme).toHaveBeenCalledTimes(1)
 })

Also applies to: 47-47, 60-60, 68-68, 70-70, 77-77, 78-78

🤖 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/__test__/Navbar.test.tsx` at line 2, The tests import and use
fireEvent for clicks; replace fireEvent with `@testing-library/user-event` to
simulate interactions more realistically: add import of userEvent from
'`@testing-library/user-event`', call const user = userEvent.setup() inside each
test (or a shared beforeEach), and replace fireEvent.click(...) with await
user.click(...) (and add async to tests where needed). Update all occurrences of
fireEvent.click in the Navbar.test.tsx tests (the click calls used around the
render assertions and handlers) to use user.click with appropriate awaits so
focus/timing behavior is preserved.

59-59: ⚡ Quick win

Replace brittle array-index selector for the hamburger button.

Lines 59, 67, and 76 select the hamburger button using screen.getAllByRole('button')[1], which assumes it's always the second button. This will break if button order changes.

Consider adding an accessible label to the hamburger button in the component and querying by name.

♻️ Example with aria-label

If the hamburger button in Navbar has an aria-label:

<button aria-label="Toggle menu" onClick={toggleMenu}>
  <Menu />
</button>

Then update the tests:

-const hamburger = screen.getAllByRole('button')[1]
+const hamburger = screen.getByRole('button', { name: /toggle menu/i })
 fireEvent.click(hamburger)

Also applies to: 67-67, 76-76

🤖 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/__test__/Navbar.test.tsx` at line 59, Tests use a brittle
array-index selector (screen.getAllByRole('button')[1]) to find the hamburger;
update the Navbar component to give the hamburger button an accessible name
(e.g., add aria-label="Toggle menu" on the button that renders the Menu icon /
calls toggleMenu) and change the tests (the places that create the hamburger
variable in Navbar.test.tsx around the current selectors) to query by role+name
such as getByRole('button', { name: /toggle menu/i }) instead of index-based
access so the selector is stable if button order changes.
🤖 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.

Nitpick comments:
In `@src/components/__test__/Navbar.test.tsx`:
- Around line 69-70: The test currently finds the mobile "Home" link by array
position (homeLinks = screen.getAllByRole('link', { name: /home/i }) and
clicking homeLinks[homeLinks.length - 1]), which is brittle; change the test to
scope the query to the mobile menu container (e.g., use within on the mobile
menu element or a specific data-testid for the mobile link) and then query that
scoped container for the "Home" link, or add a distinct test id to the mobile
link and use getByTestId; remember to import within from `@testing-library/react`
if you use scoped queries and update the click to target the scoped/mobile
element instead of indexing the whole list.
- Around line 40-41: The test is using a brittle index-based selector for the
theme button; update Navbar and its tests so the button has an accessible name
(e.g., add aria-label="Toggle theme" on the theme toggle in the Navbar component
where toggleTheme/mode/Moon/Sun are used) and replace
screen.getAllByRole('button')[0] in Navbar.test.tsx with a specific query such
as screen.getByRole('button', { name: /toggle theme/i }) or
screen.getByLabelText('Toggle theme') to reliably target the themeBtn.
- Line 2: The tests import and use fireEvent for clicks; replace fireEvent with
`@testing-library/user-event` to simulate interactions more realistically: add
import of userEvent from '`@testing-library/user-event`', call const user =
userEvent.setup() inside each test (or a shared beforeEach), and replace
fireEvent.click(...) with await user.click(...) (and add async to tests where
needed). Update all occurrences of fireEvent.click in the Navbar.test.tsx tests
(the click calls used around the render assertions and handlers) to use
user.click with appropriate awaits so focus/timing behavior is preserved.
- Line 59: Tests use a brittle array-index selector
(screen.getAllByRole('button')[1]) to find the hamburger; update the Navbar
component to give the hamburger button an accessible name (e.g., add
aria-label="Toggle menu" on the button that renders the Menu icon / calls
toggleMenu) and change the tests (the places that create the hamburger variable
in Navbar.test.tsx around the current selectors) to query by role+name such as
getByRole('button', { name: /toggle menu/i }) instead of index-based access so
the selector is stable if button order changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 46bba6f7-8ac8-4a3a-8ec4-ccd05096c876

📥 Commits

Reviewing files that changed from the base of the PR and between 7a15543 and 634daa6.

📒 Files selected for processing (4)
  • package.json
  • src/components/__test__/Navbar.test.tsx
  • src/setupTests.ts
  • vite.config.ts

@parinaB
Copy link
Copy Markdown
Contributor Author

parinaB commented May 17, 2026

Hey, while working on the frontend test setup (#275), I investigated the failing backend tests and fixed them too. Here's a full breakdown of what was wrong and what I changed:


Issues Found & Fixed

1 — No test runner configured

The backend had no way to actually run the spec files. npm test returned Error: no test specified. Jasmine and Supertest weren't installed either.

Fix: Installed jasmine and supertest as dev dependencies, added "test:backend": "jasmine spec/**/*.spec.cjs" to root package.json, and initialized Jasmine.


2 — Deprecated Mongoose connection options (spec/auth.routes.spec.cjs, spec/user.model.spec.cjs)

Both spec files were connecting to MongoDB with useNewUrlParser: true and useUnifiedTopology: true. These options were removed in Mongoose 8.x and threw a MongoParseError in beforeAll, which caused all 8 tests to be skipped entirely.

Fix: Removed the options object from both spec files.


3 — Async pre-save hook using next() incorrectly (backend/models/User.js)

The password hashing hook was declared as async function (next) and called next() manually. In Mongoose 8.x, async hooks don't receive a next parameter — calling it threw TypeError: next is not a function on every .save(), breaking all User Model tests and causing 500 errors in Auth Routes.

Fix: Removed next from the hook signature entirely. Mongoose handles async hooks automatically via the resolved/rejected promise.


Result

8 specs, 0 failures
Finished in 1.601 seconds

✅ User Model — should create a user with hashed password
✅ User Model — should not hash password again if not modified
✅ User Model — should compare passwords correctly
✅ Auth Routes — should sign up a new user
✅ Auth Routes — should not sign up a user with existing email
✅ Auth Routes — should login a user with correct credentials
✅ Auth Routes — should not login a user with wrong password
✅ Auth Routes — should logout a logged-in user

Screenshot 2026-05-17 at 11 40 56 AM

@github-actions
Copy link
Copy Markdown

🎉🎉 Thank you for your contribution! Your PR #277 has been merged! 🎉🎉

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.

test(frontend): set up Vitest + React Testing Library for React components — no frontend test coverage currently exists

2 participants