Files
tabatago/admin-web/components/sidebar.test.tsx
Millian Lamiaux 3da40c97ce test: implement comprehensive test strategy
- Add Playwright for E2E testing with auth.spec.ts
- Add dialog component tests (8 test cases)
- Add sidebar component tests (11 test cases)
- Add login page integration tests (11 test cases)
- Add dashboard page tests (12 test cases)
- Update package.json with e2e test scripts
- Configure Playwright for Chromium and Firefox
- Test coverage for UI interactions, auth flows, and navigation
2026-03-17 13:51:39 +01:00

135 lines
4.0 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Sidebar } from './sidebar'
// Mock next/navigation
const mockPush = vi.fn()
const mockPathname = vi.fn()
vi.mock('next/navigation', () => ({
useRouter: () => ({
push: mockPush,
}),
usePathname: () => mockPathname(),
}))
// Mock supabase
const mockSignOut = vi.fn()
vi.mock('@/lib/supabase', () => ({
supabase: {
auth: {
signOut: () => mockSignOut(),
},
},
}))
describe('Sidebar', () => {
beforeEach(() => {
vi.clearAllMocks()
mockPathname.mockReturnValue('/')
})
it('should render sidebar with logo and navigation', () => {
render(<Sidebar />)
expect(screen.getByText('TabataFit')).toBeInTheDocument()
expect(screen.getByText('Admin Dashboard')).toBeInTheDocument()
expect(screen.getByRole('button', { name: /logout/i })).toBeInTheDocument()
})
it('should render all navigation items', () => {
render(<Sidebar />)
expect(screen.getByRole('link', { name: /dashboard/i })).toBeInTheDocument()
expect(screen.getByRole('link', { name: /workouts/i })).toBeInTheDocument()
expect(screen.getByRole('link', { name: /trainers/i })).toBeInTheDocument()
expect(screen.getByRole('link', { name: /collections/i })).toBeInTheDocument()
expect(screen.getByRole('link', { name: /media/i })).toBeInTheDocument()
})
it('should highlight active navigation item', () => {
mockPathname.mockReturnValue('/workouts')
render(<Sidebar />)
const workoutsLink = screen.getByRole('link', { name: /workouts/i })
expect(workoutsLink).toHaveClass('text-orange-500')
expect(workoutsLink).toHaveClass('bg-orange-500/10')
})
it('should not highlight inactive navigation items', () => {
mockPathname.mockReturnValue('/workouts')
render(<Sidebar />)
const dashboardLink = screen.getByRole('link', { name: /dashboard/i })
expect(dashboardLink).toHaveClass('text-neutral-400')
expect(dashboardLink).not.toHaveClass('bg-orange-500/10')
})
it('should navigate to correct routes when clicking links', () => {
render(<Sidebar />)
const workoutsLink = screen.getByRole('link', { name: /workouts/i })
expect(workoutsLink).toHaveAttribute('href', '/workouts')
const trainersLink = screen.getByRole('link', { name: /trainers/i })
expect(trainersLink).toHaveAttribute('href', '/trainers')
})
it('should handle logout', async () => {
mockSignOut.mockResolvedValue({ error: null })
render(<Sidebar />)
const logoutButton = screen.getByRole('button', { name: /logout/i })
await userEvent.click(logoutButton)
await waitFor(() => {
expect(mockSignOut).toHaveBeenCalled()
})
expect(mockPush).toHaveBeenCalledWith('/login')
})
it('should handle logout errors gracefully', async () => {
mockSignOut.mockRejectedValueOnce(new Error('Network error'))
render(<Sidebar />)
const logoutButton = screen.getByRole('button', { name: /logout/i })
await userEvent.click(logoutButton)
await waitFor(() => {
expect(mockSignOut).toHaveBeenCalled()
})
})
it('should have correct styling for navigation', () => {
render(<Sidebar />)
const nav = screen.getByRole('navigation')
expect(nav).toBeInTheDocument()
const links = screen.getAllByRole('link')
links.forEach(link => {
expect(link).toHaveClass('flex', 'items-center', 'gap-3')
})
})
it('should display icons for navigation items', () => {
render(<Sidebar />)
// All nav links should have icons (lucide icons render as svg)
const links = screen.getAllByRole('link')
links.forEach(link => {
const icon = link.querySelector('svg')
expect(icon).toBeInTheDocument()
})
})
it('should be sticky positioned', () => {
render(<Sidebar />)
const sidebar = screen.getByRole('complementary') || document.querySelector('aside')
expect(sidebar).toHaveClass('sticky', 'top-0')
})
})