Files
gridpilot.gg/apps/website/app/leagues/[id]/stewarding/protests/[protestId]/page.test.tsx
2025-12-28 12:04:12 +01:00

106 lines
3.0 KiB
TypeScript

import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import ProtestReviewPage from './page';
// Mocks for Next.js navigation
const mockPush = vi.fn();
vi.mock('next/navigation', () => ({
useRouter: () => ({
push: mockPush,
}),
useParams: () => ({ id: 'league-1', protestId: 'protest-1' }),
}));
// Mock effective driver id hook
vi.mock('@/hooks/useEffectiveDriverId', () => ({
useEffectiveDriverId: () => 'driver-1',
}));
const mockGetProtestDetailViewModel = vi.fn();
const mockFetchLeagueMemberships = vi.fn();
const mockGetMembership = vi.fn();
vi.mock('@/lib/services/ServiceProvider', () => ({
useServices: () => ({
leagueStewardingService: {
getProtestDetailViewModel: mockGetProtestDetailViewModel,
},
protestService: {
applyPenalty: vi.fn(),
requestDefense: vi.fn(),
},
leagueMembershipService: {
fetchLeagueMemberships: mockFetchLeagueMemberships,
getMembership: mockGetMembership,
},
}),
}));
const mockIsLeagueAdminOrHigherRole = vi.fn();
vi.mock('@/lib/utilities/LeagueRoleUtility', () => ({
LeagueRoleUtility: {
isLeagueAdminOrHigherRole: (...args: unknown[]) => mockIsLeagueAdminOrHigherRole(...args),
},
}));
describe('ProtestReviewPage', () => {
beforeEach(() => {
mockPush.mockReset();
mockGetProtestDetailViewModel.mockReset();
mockFetchLeagueMemberships.mockReset();
mockGetMembership.mockReset();
mockIsLeagueAdminOrHigherRole.mockReset();
mockFetchLeagueMemberships.mockResolvedValue(undefined);
mockGetMembership.mockReturnValue({ role: 'admin' });
mockIsLeagueAdminOrHigherRole.mockReturnValue(true);
});
it('loads protest detail via LeagueStewardingService view model method', async () => {
mockGetProtestDetailViewModel.mockResolvedValue({
protest: {
id: 'protest-1',
raceId: 'race-1',
protestingDriverId: 'driver-1',
accusedDriverId: 'driver-2',
description: 'desc',
submittedAt: '2023-10-01T10:00:00Z',
status: 'pending',
incident: { lap: 1 },
},
race: {
id: 'race-1',
name: 'Test Race',
formattedDate: '10/1/2023',
},
protestingDriver: { id: 'driver-1', name: 'Driver 1' },
accusedDriver: { id: 'driver-2', name: 'Driver 2' },
penaltyTypes: [
{
type: 'time_penalty',
label: 'Time Penalty',
description: 'Add seconds to race result',
requiresValue: true,
valueLabel: 'seconds',
defaultValue: 5,
},
],
defaultReasons: { upheld: 'Upheld reason', dismissed: 'Dismissed reason' },
initialPenaltyType: 'time_penalty',
initialPenaltyValue: 5,
});
render(<ProtestReviewPage />);
await waitFor(() => {
expect(mockGetProtestDetailViewModel).toHaveBeenCalledWith('league-1', 'protest-1');
});
expect(await screen.findByText('Protest Review')).toBeInTheDocument();
});
});