diff --git a/package.json b/package.json
index f2d89f5..e5b4fe1 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
"dev": "vite --host",
"build": "vite build",
"lint": "eslint .",
+ "test": "vitest",
"preview": "vite preview",
"docker:dev": "docker compose --profile dev up --build",
"docker:prod": "docker compose --profile prod up -d --build"
@@ -32,6 +33,9 @@
},
"devDependencies": {
"@eslint/js": "^9.13.0",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@testing-library/user-event": "^14.6.1",
"@types/jasmine": "^5.1.8",
"@types/node": "^22.10.1",
"@types/react": "^18.3.23",
@@ -48,9 +52,11 @@
"express-session": "^1.18.2",
"globals": "^15.11.0",
"jasmine": "^5.9.0",
+ "jsdom": "^29.1.1",
"passport": "^0.7.0",
"passport-local": "^1.0.0",
"supertest": "^7.1.4",
- "vite": "^5.4.10"
+ "vite": "^5.4.10",
+ "vitest": "^4.1.6"
}
}
diff --git a/src/components/__test__/Navbar.test.tsx b/src/components/__test__/Navbar.test.tsx
new file mode 100644
index 0000000..780b9bb
--- /dev/null
+++ b/src/components/__test__/Navbar.test.tsx
@@ -0,0 +1,91 @@
+// src/components/__tests__/Navbar.test.tsx
+import { render, screen, fireEvent } from '@testing-library/react'
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+import { MemoryRouter } from 'react-router-dom'
+import { ThemeContext } from "../../context/ThemeContext";
+import Navbar from '../Navbar.tsx'
+
+// Helper to render Navbar with a mock ThemeContext
+const renderNavbar = (mode: 'light' | 'dark' = 'light') => {
+ const toggleTheme = vi.fn()
+ render(
+
+
+
+
+
+ )
+ return { toggleTheme }
+}
+
+describe('Navbar', () => {
+ // --- Rendering ---
+ it('renders the GitHub Tracker logo link', () => {
+ renderNavbar()
+ expect(screen.getByText('GitHub Tracker')).toBeInTheDocument()
+ })
+
+ it('renders all desktop nav links', () => {
+ renderNavbar()
+ expect(screen.getByRole('link', { name: /home/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: /^tracker$/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: /contributors/i })).toBeInTheDocument()
+ expect(screen.getByRole('link', { name: /login/i })).toBeInTheDocument()
+ })
+
+ // --- Theme toggle ---
+ it('shows Moon icon in light mode', () => {
+ renderNavbar('light')
+ // Lucide renders an