Files
gridpilot.gg/tests/integration/website/queries/LeaguesPageQuery.integration.test.ts
Marc Mintel 6df38a462a
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
integration tests
2026-01-23 11:44:59 +01:00

310 lines
8.7 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { LeaguesPageQuery } from '../../../../apps/website/lib/page-queries/LeaguesPageQuery';
import { WebsiteTestContext } from '../WebsiteTestContext';
// Mock data factories
const createMockLeaguesData = () => ({
leagues: [
{
id: 'league-1',
name: 'Test League 1',
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',
},
},
{
id: 'league-2',
name: 'Test League 2',
description: 'Another test league',
ownerId: 'driver-2',
createdAt: new Date().toISOString(),
usedSlots: 15,
settings: {
maxDrivers: 20,
},
scoring: {
gameId: 'game-1',
gameName: 'Test Game',
primaryChampionshipType: 'driver' as const,
scoringPresetId: 'preset-1',
scoringPresetName: 'Test Preset',
dropPolicySummary: 'No drops',
scoringPatternSummary: 'Standard scoring',
},
},
],
totalCount: 2,
});
const createMockEmptyLeaguesData = () => ({
leagues: [],
});
describe('LeaguesPageQuery Integration', () => {
const ctx = WebsiteTestContext.create();
beforeEach(() => {
ctx.setup();
});
afterEach(() => {
ctx.teardown();
});
describe('Happy Path', () => {
it('should return valid leagues data when API returns success', async () => {
// Arrange
const mockData = createMockLeaguesData();
ctx.mockFetchResponse(mockData);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isOk()).toBe(true);
const viewData = result.unwrap();
expect(viewData).toBeDefined();
expect(viewData.leagues).toBeDefined();
expect(viewData.leagues.length).toBe(2);
// Verify first league
expect(viewData.leagues[0].id).toBe('league-1');
expect(viewData.leagues[0].name).toBe('Test League 1');
expect(viewData.leagues[0].maxDrivers).toBe(10);
expect(viewData.leagues[0].usedDriverSlots).toBe(5);
// Verify second league
expect(viewData.leagues[1].id).toBe('league-2');
expect(viewData.leagues[1].name).toBe('Test League 2');
expect(viewData.leagues[1].maxDrivers).toBe(20);
expect(viewData.leagues[1].usedDriverSlots).toBe(15);
});
it('should handle single league correctly', async () => {
// Arrange
const mockData = {
leagues: [
{
id: 'single-league',
name: 'Single League',
description: 'Only one league',
ownerId: 'driver-1',
createdAt: new Date().toISOString(),
usedSlots: 3,
settings: {
maxDrivers: 5,
},
scoring: {
gameId: 'game-1',
gameName: 'Test Game',
primaryChampionshipType: 'driver' as const,
scoringPresetId: 'preset-1',
scoringPresetName: 'Test Preset',
dropPolicySummary: 'No drops',
scoringPatternSummary: 'Standard scoring',
},
},
],
};
ctx.mockFetchResponse(mockData);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isOk()).toBe(true);
const viewData = result.unwrap();
expect(viewData.leagues.length).toBe(1);
expect(viewData.leagues[0].id).toBe('single-league');
expect(viewData.leagues[0].name).toBe('Single League');
});
});
describe('Empty Results', () => {
it('should handle empty leagues list from API', async () => {
// Arrange
const mockData = createMockEmptyLeaguesData();
ctx.mockFetchResponse(mockData);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isOk()).toBe(true);
const viewData = result.unwrap();
expect(viewData).toBeDefined();
expect(viewData.leagues).toBeDefined();
expect(viewData.leagues.length).toBe(0);
});
});
describe('Error Handling', () => {
it('should handle 404 error when leagues endpoint not found', async () => {
// Arrange
ctx.mockFetchResponse({ message: 'Leagues not found' }, 404, false);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('notFound');
});
it('should handle 500 error when API server error', async () => {
// Arrange
ctx.mockFetchResponse({ message: 'Internal Server Error' }, 500, false);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('LEAGUES_FETCH_FAILED');
});
it('should handle network error', async () => {
// Arrange
ctx.mockFetchError(new Error('Network error: Unable to reach the API server'));
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('LEAGUES_FETCH_FAILED');
});
it('should handle timeout error', async () => {
// Arrange
const timeoutError = new Error('Request timed out after 30 seconds');
timeoutError.name = 'AbortError';
ctx.mockFetchError(timeoutError);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('LEAGUES_FETCH_FAILED');
});
it('should handle unauthorized error (redirect)', async () => {
// Arrange
ctx.mockFetchResponse({ message: 'Unauthorized' }, 401, false);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('redirect');
});
it('should handle forbidden error (redirect)', async () => {
// Arrange
ctx.mockFetchResponse({ message: 'Forbidden' }, 403, false);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('redirect');
});
it('should handle unknown error type', async () => {
// Arrange
ctx.mockFetchResponse({ message: 'Unknown error' }, 999, false);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('LEAGUES_FETCH_FAILED');
});
});
describe('Edge Cases', () => {
it('should handle API returning null or undefined data', async () => {
// Arrange
ctx.mockFetchResponse({ leagues: null });
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('UNKNOWN_ERROR');
});
it('should handle API returning malformed data', async () => {
// Arrange
const mockData = {
// Missing 'leagues' property
someOtherProperty: 'value',
};
ctx.mockFetchResponse(mockData);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
expect(result.isErr()).toBe(true);
const error = result.getError();
expect(error).toBe('UNKNOWN_ERROR');
});
it('should handle API returning leagues with missing required fields', async () => {
// Arrange
const mockData = {
leagues: [
{
id: 'league-1',
name: 'Test League',
// Missing other required fields
settings: { maxDrivers: 10 },
usedSlots: 5,
createdAt: new Date().toISOString(),
},
],
};
ctx.mockFetchResponse(mockData);
// Act
const result = await LeaguesPageQuery.execute();
// Assert
// Should still succeed - the builder should handle partial data
expect(result.isOk()).toBe(true);
const viewData = result.unwrap();
expect(viewData.leagues.length).toBe(1);
});
});
});