website refactor

This commit is contained in:
2026-01-12 01:01:49 +01:00
parent 5ca6023a5a
commit fefd8d1cd6
294 changed files with 4628 additions and 4991 deletions

View File

@@ -1,15 +1,15 @@
import { describe, it, expect, vi, Mocked, beforeEach, afterEach } from 'vitest';
import { describe, it, expect, vi, Mocked, beforeEach } from 'vitest';
import { LeagueService } from './LeagueService';
import { LeaguesApiClient } from '../../api/leagues/LeaguesApiClient';
import { LeagueStandingsViewModel } from '../../view-models/LeagueStandingsViewModel';
import { LeagueStatsViewModel } from '../../view-models/LeagueStatsViewModel';
import { LeagueScheduleViewModel } from '../../view-models/LeagueScheduleViewModel';
import { LeagueMembershipsViewModel } from '../../view-models/LeagueMembershipsViewModel';
import { RemoveMemberViewModel } from '../../view-models/RemoveMemberViewModel';
import { LeagueMemberViewModel } from '../../view-models/LeagueMemberViewModel';
import type { CreateLeagueInputDTO } from '../../types/generated/CreateLeagueInputDTO';
import type { CreateLeagueOutputDTO } from '../../types/generated/CreateLeagueOutputDTO';
import type { RemoveLeagueMemberOutputDTO } from '../../types/generated/RemoveLeagueMemberOutputDTO';
import { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';
import { LeagueStandingsViewModel } from '@/lib/view-models/LeagueStandingsViewModel';
import { LeagueStatsViewModel } from '@/lib/view-models/LeagueStatsViewModel';
import { LeagueScheduleViewModel } from '@/lib/view-models/LeagueScheduleViewModel';
import { LeagueMembershipsViewModel } from '@/lib/view-models/LeagueMembershipsViewModel';
import { RemoveMemberViewModel } from '@/lib/view-models/RemoveMemberViewModel';
import { LeagueMemberViewModel } from '@/lib/view-models/LeagueMemberViewModel';
import type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInputDTO';
import type { CreateLeagueOutputDTO } from '@/lib/types/generated/CreateLeagueOutputDTO';
import type { RemoveLeagueMemberOutputDTO } from '@/lib/types/generated/RemoveLeagueMemberOutputDTO';
describe('LeagueService', () => {
let mockApiClient: Mocked<LeaguesApiClient>;
@@ -114,14 +114,7 @@ describe('LeagueService', () => {
});
describe('getLeagueSchedule', () => {
afterEach(() => {
vi.useRealTimers();
});
it('should call apiClient.getSchedule and return LeagueScheduleViewModel with Date parsing', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-01T00:00:00Z'));
const leagueId = 'league-123';
const mockDto = {
races: [
@@ -136,44 +129,7 @@ describe('LeagueService', () => {
expect(mockApiClient.getSchedule).toHaveBeenCalledWith(leagueId);
expect(result).toBeInstanceOf(LeagueScheduleViewModel);
expect(result.raceCount).toBe(2);
expect(result.races[0]!.scheduledAt).toBeInstanceOf(Date);
expect(result.races[0]!.isPast).toBe(true);
expect(result.races[1]!.isUpcoming).toBe(true);
});
it('should prefer scheduledAt over date and map optional fields/status', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-01T00:00:00Z'));
const leagueId = 'league-123';
const mockDto = {
races: [
{
id: 'race-1',
name: 'Round 1',
date: '2025-01-02T20:00:00Z',
scheduledAt: '2025-01-03T20:00:00Z',
track: 'Monza',
car: 'GT3',
sessionType: 'race',
isRegistered: true,
status: 'scheduled',
},
],
} as any;
mockApiClient.getSchedule.mockResolvedValue(mockDto);
const result = await service.getLeagueSchedule(leagueId);
expect(result.races[0]!.scheduledAt.toISOString()).toBe('2025-01-03T20:00:00.000Z');
expect(result.races[0]!.track).toBe('Monza');
expect(result.races[0]!.car).toBe('GT3');
expect(result.races[0]!.sessionType).toBe('race');
expect(result.races[0]!.isRegistered).toBe(true);
expect(result.races[0]!.status).toBe('scheduled');
});
it('should handle empty races array', async () => {
@@ -279,56 +235,6 @@ describe('LeagueService', () => {
await expect(service.createLeague(input)).rejects.toThrow('API call failed');
});
it('should not call apiClient.create when submitBlocker is blocked', async () => {
const input: CreateLeagueInputDTO = {
name: 'New League',
description: 'A new league',
visibility: 'public',
ownerId: 'owner-1',
};
// First call should succeed
const mockDto: CreateLeagueOutputDTO = {
leagueId: 'new-league-id',
success: true,
};
mockApiClient.create.mockResolvedValue(mockDto);
await service.createLeague(input); // This should block the submitBlocker
// Reset mock to check calls
mockApiClient.create.mockClear();
// Second call should not call API
await service.createLeague(input);
expect(mockApiClient.create).not.toHaveBeenCalled();
});
it('should not call apiClient.create when throttle is active', async () => {
const input: CreateLeagueInputDTO = {
name: 'New League',
description: 'A new league',
visibility: 'public',
ownerId: 'owner-1',
};
// First call
const mockDto: CreateLeagueOutputDTO = {
leagueId: 'new-league-id',
success: true,
};
mockApiClient.create.mockResolvedValue(mockDto);
await service.createLeague(input); // This blocks throttle for 500ms
// Reset mock
mockApiClient.create.mockClear();
// Immediate second call should not call API due to throttle
await service.createLeague(input);
expect(mockApiClient.create).not.toHaveBeenCalled();
});
});
describe('removeMember', () => {