import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, act } from '@testing-library/react'; import { Suspense } from 'react'; import ShiftDetailPage from '../../app/(protected)/shifts/[id]/page'; vi.mock('@/hooks/useShifts', () => ({ useShift: vi.fn(), useSignUpShift: vi.fn(), useCancelSignUp: vi.fn(), })); vi.mock('next/navigation', () => ({ useRouter: vi.fn(() => ({ push: vi.fn(), back: vi.fn(), })), })); vi.mock('@/contexts/tenant-context', () => ({ useTenant: vi.fn(() => ({ activeClubId: 'club-123', userRole: 'Member', })), })); vi.mock('next-auth/react', () => ({ useSession: vi.fn(() => ({ data: { user: { id: 'user-123' } }, status: 'authenticated', })), })); import { useShift, useSignUpShift, useCancelSignUp } from '@/hooks/useShifts'; describe('ShiftDetailPage', () => { const mockSignUp = vi.fn(); const mockCancel = vi.fn(); beforeEach(() => { vi.clearAllMocks(); (useSignUpShift as ReturnType).mockReturnValue({ mutateAsync: mockSignUp, isPending: false }); (useCancelSignUp as ReturnType).mockReturnValue({ mutateAsync: mockCancel, isPending: false }); }); it('shows "Sign Up" button if capacity available', async () => { (useShift as ReturnType).mockReturnValue({ data: { id: '1', title: 'Detail Shift', startTime: new Date(Date.now() + 100000).toISOString(), endTime: new Date(Date.now() + 200000).toISOString(), capacity: 3, signups: [{ id: 's1', memberId: 'other-user' }], }, isLoading: false, }); const params = Promise.resolve({ id: '1' }); await act(async () => { render( Loading...}> ); }); expect(screen.getByRole('button', { name: 'Sign Up' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Cancel Sign-up' })).not.toBeInTheDocument(); }); it('shows "Cancel Sign-up" button if user is signed up', async () => { (useShift as ReturnType).mockReturnValue({ data: { id: '1', title: 'Detail Shift', startTime: new Date(Date.now() + 100000).toISOString(), endTime: new Date(Date.now() + 200000).toISOString(), capacity: 3, signups: [{ id: 's1', memberId: 'user-123' }], }, isLoading: false, }); const params = Promise.resolve({ id: '1' }); await act(async () => { render( Loading...}> ); }); expect(screen.getByRole('button', { name: 'Cancel Sign-up' })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: 'Sign Up' })).not.toBeInTheDocument(); }); it('calls sign up mutation on click', async () => { (useShift as ReturnType).mockReturnValue({ data: { id: '1', title: 'Detail Shift', startTime: new Date(Date.now() + 100000).toISOString(), endTime: new Date(Date.now() + 200000).toISOString(), capacity: 3, signups: [], }, isLoading: false, }); const params = Promise.resolve({ id: '1' }); await act(async () => { render( Loading...}> ); }); const signUpBtn = screen.getByRole('button', { name: 'Sign Up' }); fireEvent.click(signUpBtn); expect(mockSignUp).toHaveBeenCalledWith('1'); }); });