integration tests
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m50s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
This commit is contained in:
@@ -0,0 +1,353 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { LeagueDetailPageQuery } from '../../../../apps/website/lib/page-queries/LeagueDetailPageQuery';
|
||||
import { WebsiteTestContext } from '../WebsiteTestContext';
|
||||
|
||||
// Mock data factories
|
||||
const createMockLeagueData = (leagueId: string = 'league-1') => ({
|
||||
leagues: [
|
||||
{
|
||||
id: leagueId,
|
||||
name: 'Test League',
|
||||
description: 'A test league',
|
||||
ownerId: 'driver-1',
|
||||
createdAt: new Date().toISOString(),
|
||||
usedSlots: 5,
|
||||
settings: {
|
||||
maxDrivers: 10,
|
||||
},
|
||||
scoring: {
|
||||
gameId: 'game-1',
|
||||
gameName: 'Test Game',
|
||||
primaryChampionshipType: 'driver' as const,
|
||||
scoringPresetId: 'preset-1',
|
||||
scoringPresetName: 'Test Preset',
|
||||
dropPolicySummary: 'No drops',
|
||||
scoringPatternSummary: 'Standard scoring',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const createMockMembershipsData = () => ({
|
||||
members: [
|
||||
{
|
||||
driverId: 'driver-1',
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
name: 'Driver 1',
|
||||
},
|
||||
role: 'owner',
|
||||
joinedAt: new Date().toISOString(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const createMockRacesData = (leagueId: string = 'league-1') => ({
|
||||
races: [
|
||||
{
|
||||
id: 'race-1',
|
||||
track: 'Test Track',
|
||||
car: 'Test Car',
|
||||
scheduledAt: new Date().toISOString(),
|
||||
leagueId: leagueId,
|
||||
leagueName: 'Test League',
|
||||
status: 'scheduled',
|
||||
strengthOfField: 50,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const createMockDriverData = () => ({
|
||||
id: 'driver-1',
|
||||
name: 'Test Driver',
|
||||
avatarUrl: 'https://example.com/avatar.png',
|
||||
});
|
||||
|
||||
const createMockConfigData = () => ({
|
||||
form: {
|
||||
scoring: {
|
||||
presetId: 'preset-1',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('LeagueDetailPageQuery Integration', () => {
|
||||
const ctx = WebsiteTestContext.create();
|
||||
|
||||
beforeEach(() => {
|
||||
ctx.setup();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ctx.teardown();
|
||||
});
|
||||
|
||||
describe('Happy Path', () => {
|
||||
it('should return valid league detail data when API returns success', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-1';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId)); // For getAllWithCapacityAndScoring
|
||||
ctx.mockFetchResponse(createMockMembershipsData()); // For getMemberships
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId)); // For getPageData
|
||||
ctx.mockFetchResponse(createMockDriverData()); // For getDriver
|
||||
ctx.mockFetchResponse(createMockConfigData()); // For getLeagueConfig
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
|
||||
expect(data.leagueId).toBe(leagueId);
|
||||
expect(data.name).toBe('Test League');
|
||||
expect(data.ownerSummary).toBeDefined();
|
||||
expect(data.ownerSummary?.driverName).toBe('Test Driver');
|
||||
});
|
||||
|
||||
it('should handle league without owner', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-2';
|
||||
const leagueData = createMockLeagueData(leagueId);
|
||||
leagueData.leagues[0].ownerId = ''; // No owner
|
||||
|
||||
ctx.mockFetchResponse(leagueData); // getAllWithCapacityAndScoring
|
||||
ctx.mockFetchResponse(createMockMembershipsData()); // getMemberships
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId)); // getPageData
|
||||
ctx.mockFetchResponse(createMockConfigData()); // getLeagueConfig
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.ownerSummary).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle league with no races', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-3';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId)); // getAllWithCapacityAndScoring
|
||||
ctx.mockFetchResponse(createMockMembershipsData()); // getMemberships
|
||||
ctx.mockFetchResponse({ races: [] }); // getPageData
|
||||
ctx.mockFetchResponse(createMockDriverData()); // getDriver
|
||||
ctx.mockFetchResponse(createMockConfigData()); // getLeagueConfig
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.info.racesCount).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
it('should handle 404 error when league not found', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'non-existent-league';
|
||||
ctx.mockFetchResponse({ leagues: [] }); // getAllWithCapacityAndScoring
|
||||
ctx.mockFetchResponse(createMockMembershipsData()); // getMemberships
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId)); // getPageData
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('notFound');
|
||||
});
|
||||
|
||||
it('should handle 500 error when API server error', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse({ message: 'Internal Server Error' }, 500, false);
|
||||
ctx.mockFetchResponse({ message: 'Internal Server Error' }, 500, false);
|
||||
ctx.mockFetchResponse({ message: 'Internal Server Error' }, 500, false);
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('serverError');
|
||||
});
|
||||
|
||||
it('should handle network error', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchError(new Error('Network error: Unable to reach the API server'));
|
||||
ctx.mockFetchError(new Error('Network error: Unable to reach the API server'));
|
||||
ctx.mockFetchError(new Error('Network error: Unable to reach the API server'));
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('serverError');
|
||||
});
|
||||
|
||||
it('should handle timeout error', async () => {
|
||||
// Arrange
|
||||
const timeoutError = new Error('Request timed out after 30 seconds');
|
||||
timeoutError.name = 'AbortError';
|
||||
ctx.mockFetchError(timeoutError);
|
||||
ctx.mockFetchError(timeoutError);
|
||||
ctx.mockFetchError(timeoutError);
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('serverError');
|
||||
});
|
||||
|
||||
it('should handle unauthorized error', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse({ message: 'Unauthorized' }, 401, false);
|
||||
ctx.mockFetchResponse({ message: 'Unauthorized' }, 401, false);
|
||||
ctx.mockFetchResponse({ message: 'Unauthorized' }, 401, false);
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('unauthorized');
|
||||
});
|
||||
|
||||
it('should handle forbidden error', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse({ message: 'Forbidden' }, 403, false);
|
||||
ctx.mockFetchResponse({ message: 'Forbidden' }, 403, false);
|
||||
ctx.mockFetchResponse({ message: 'Forbidden' }, 403, false);
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('unauthorized');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Missing Data', () => {
|
||||
it('should handle API returning partial data (missing memberships)', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-1';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId));
|
||||
ctx.mockFetchResponse(null); // Missing memberships
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId));
|
||||
ctx.mockFetchResponse(createMockDriverData());
|
||||
ctx.mockFetchResponse(createMockConfigData());
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.info.membersCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle API returning partial data (missing races)', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-1';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId));
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(null); // Missing races
|
||||
ctx.mockFetchResponse(createMockDriverData());
|
||||
ctx.mockFetchResponse(createMockConfigData());
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.info.racesCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle API returning partial data (missing scoring config)', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-1';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId));
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId));
|
||||
ctx.mockFetchResponse(createMockDriverData());
|
||||
ctx.mockFetchResponse({ message: 'Config not found' }, 404, false); // Missing config
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.info.scoring).toBe('Standard');
|
||||
});
|
||||
|
||||
it('should handle API returning partial data (missing owner)', async () => {
|
||||
// Arrange
|
||||
const leagueId = 'league-1';
|
||||
ctx.mockFetchResponse(createMockLeagueData(leagueId));
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(createMockRacesData(leagueId));
|
||||
ctx.mockFetchResponse(null); // Missing owner
|
||||
ctx.mockFetchResponse(createMockConfigData());
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute(leagueId);
|
||||
|
||||
// Assert
|
||||
expect(result.isOk()).toBe(true);
|
||||
const data = result.unwrap();
|
||||
expect(data.ownerSummary).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle API returning empty leagues array', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse({ leagues: [] });
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(createMockRacesData('league-1'));
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('notFound');
|
||||
});
|
||||
|
||||
it('should handle API returning null data', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse(null);
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(createMockRacesData('league-1'));
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('notFound');
|
||||
});
|
||||
|
||||
it('should handle API returning malformed data', async () => {
|
||||
// Arrange
|
||||
ctx.mockFetchResponse({ someOtherKey: [] });
|
||||
ctx.mockFetchResponse(createMockMembershipsData());
|
||||
ctx.mockFetchResponse(createMockRacesData('league-1'));
|
||||
|
||||
// Act
|
||||
const result = await LeagueDetailPageQuery.execute('league-1');
|
||||
|
||||
// Assert
|
||||
expect(result.isErr()).toBe(true);
|
||||
expect(result.getError()).toBe('notFound');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user