import { describe, it, expect, vi, beforeEach } from 'vitest' import { render, screen, waitFor } from '@testing-library/react' import DashboardPage from './page' // Mock next/link vi.mock('next/link', () => { return { default: ({ children, href }: { children: React.ReactNode; href: string }) => ( {children} ), } }) // Mock supabase const mockFrom = vi.fn() vi.mock('@/lib/supabase', () => ({ supabase: { from: (...args: any[]) => mockFrom(...args), }, })) describe('DashboardPage', () => { beforeEach(() => { vi.clearAllMocks() }) it('should render dashboard header', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() expect(screen.getByRole('heading', { name: /dashboard/i })).toBeInTheDocument() expect(screen.getByText(/overview of your tabatafit content/i)).toBeInTheDocument() }) it('should render stat cards', async () => { mockFrom .mockReturnValueOnce({ select: () => Promise.resolve({ count: 15, error: null }), }) .mockReturnValueOnce({ select: () => Promise.resolve({ count: 5, error: null }), }) .mockReturnValueOnce({ select: () => Promise.resolve({ count: 3, error: null }), }) render() await waitFor(() => { expect(screen.getByText('15')).toBeInTheDocument() expect(screen.getByText('5')).toBeInTheDocument() expect(screen.getByText('3')).toBeInTheDocument() }) expect(screen.getByText('Workouts')).toBeInTheDocument() expect(screen.getByText('Trainers')).toBeInTheDocument() expect(screen.getByText('Collections')).toBeInTheDocument() }) it('should show loading state initially', () => { mockFrom.mockReturnValue({ select: () => new Promise(() => {}), // Never resolves }) render() const statValues = screen.getAllByText('-') expect(statValues.length).toBeGreaterThan(0) }) it('should render quick actions section', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() expect(screen.getByText(/quick actions/i)).toBeInTheDocument() expect(screen.getByText(/manage workouts/i)).toBeInTheDocument() expect(screen.getByText(/manage trainers/i)).toBeInTheDocument() expect(screen.getByText(/upload media/i)).toBeInTheDocument() }) it('should render getting started section', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() expect(screen.getByText(/getting started/i)).toBeInTheDocument() expect(screen.getByText(/create and edit tabata workouts/i)).toBeInTheDocument() expect(screen.getByText(/manage trainer profiles/i)).toBeInTheDocument() }) it('should link to correct routes', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() expect(screen.getByRole('link', { name: /workouts \d+/i })).toHaveAttribute('href', '/workouts') expect(screen.getByRole('link', { name: /trainers \d+/i })).toHaveAttribute('href', '/trainers') expect(screen.getByRole('link', { name: /collections \d+/i })).toHaveAttribute('href', '/collections') }) it('should handle stats fetch errors gracefully', async () => { const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}) mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: null, error: new Error('Database error') }), }) render() await waitFor(() => { expect(consoleError).toHaveBeenCalled() }) consoleError.mockRestore() }) it('should render correct icons', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() // All cards should have icons (lucide icons render as svg) const cards = screen.getAllByRole('article') cards.forEach(card => { const icon = card.querySelector('svg') expect(icon).toBeInTheDocument() }) }) it('should apply correct color classes to stats', async () => { mockFrom .mockReturnValueOnce({ select: () => Promise.resolve({ count: 10, error: null }), }) .mockReturnValueOnce({ select: () => Promise.resolve({ count: 5, error: null }), }) .mockReturnValueOnce({ select: () => Promise.resolve({ count: 3, error: null }), }) render() await waitFor(() => { const workoutCard = screen.getByText('Workouts').closest('article') expect(workoutCard?.querySelector('.text-orange-500')).toBeInTheDocument() const trainerCard = screen.getByText('Trainers').closest('article') expect(trainerCard?.querySelector('.text-blue-500')).toBeInTheDocument() const collectionCard = screen.getByText('Collections').closest('article') expect(collectionCard?.querySelector('.text-green-500')).toBeInTheDocument() }) }) it('should fetch stats on mount', () => { mockFrom.mockReturnValue({ select: () => Promise.resolve({ count: 0, error: null }), }) render() expect(mockFrom).toHaveBeenCalledWith('workouts') expect(mockFrom).toHaveBeenCalledWith('trainers') expect(mockFrom).toHaveBeenCalledWith('collections') }) })