Files
gridpilot.gg/tests/integration/league/members-data-flow.integration.test.ts
2026-01-21 22:36:01 +01:00

305 lines
12 KiB
TypeScript

/**
* Integration Test: League Members Data Flow
*
* Tests the complete data flow from database to API response for league members:
* 1. Database query returns correct data
* 2. Use case processes the data correctly
* 3. Presenter transforms data to DTOs
* 4. API returns correct response
*/
import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import { IntegrationTestHarness, createTestHarness } from '../harness';
describe('League Members - Data Flow Integration', () => {
let harness: IntegrationTestHarness;
beforeAll(async () => {
harness = createTestHarness();
await harness.beforeAll();
}, 120000);
afterAll(async () => {
await harness.afterAll();
}, 30000);
beforeEach(async () => {
await harness.beforeEach();
});
describe('API to View Data Flow', () => {
it('should return correct members DTO structure from API', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Members Test League' });
const season = await factory.createSeason(league.id.toString());
// Create drivers
const drivers = await Promise.all([
factory.createDriver({ name: 'Owner Driver', country: 'US' }),
factory.createDriver({ name: 'Admin Driver', country: 'UK' }),
factory.createDriver({ name: 'Member Driver', country: 'CA' }),
]);
// Create league memberships (simulated via database)
// Note: In real implementation, memberships would be created through the domain
// For this test, we'll verify the API response structure
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Verify: API response structure
expect(response).toBeDefined();
expect(response.memberships).toBeDefined();
expect(Array.isArray(response.memberships)).toBe(true);
// Verify: Each membership has correct DTO structure
for (const membership of response.memberships) {
expect(membership).toHaveProperty('driverId');
expect(membership).toHaveProperty('driver');
expect(membership).toHaveProperty('role');
expect(membership).toHaveProperty('status');
expect(membership).toHaveProperty('joinedAt');
// Verify driver DTO structure
expect(membership.driver).toHaveProperty('id');
expect(membership.driver).toHaveProperty('iracingId');
expect(membership.driver).toHaveProperty('name');
expect(membership.driver).toHaveProperty('country');
expect(membership.driver).toHaveProperty('joinedAt');
}
});
it('should return empty members for league with no members', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Empty Members League' });
const season = await factory.createSeason(league.id.toString());
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
expect(response.memberships).toEqual([]);
});
it('should handle league with single member', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Single Member League' });
const season = await factory.createSeason(league.id.toString());
const driver = await factory.createDriver({ name: 'Solo Member', country: 'US' });
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Should have at least the owner
expect(response.memberships.length).toBeGreaterThan(0);
const soloMember = response.memberships.find(m => m.driver.name === 'Solo Member');
expect(soloMember).toBeDefined();
expect(soloMember?.role).toBeDefined();
expect(soloMember?.status).toBeDefined();
});
});
describe('End-to-End Data Flow', () => {
it('should correctly transform member data to DTO', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Transformation Members League' });
const season = await factory.createSeason(league.id.toString());
const drivers = await Promise.all([
factory.createDriver({ name: 'Owner', country: 'US', iracingId: '1001' }),
factory.createDriver({ name: 'Admin', country: 'UK', iracingId: '1002' }),
factory.createDriver({ name: 'Member', country: 'CA', iracingId: '1003' }),
]);
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Verify all drivers are in the response
expect(response.memberships.length).toBeGreaterThanOrEqual(3);
// Verify each driver has correct data
for (const driver of drivers) {
const membership = response.memberships.find(m => m.driver.name === driver.name.toString());
expect(membership).toBeDefined();
expect(membership?.driver.id).toBe(driver.id.toString());
expect(membership?.driver.iracingId).toBe(driver.iracingId);
expect(membership?.driver.country).toBe(driver.country);
}
});
it('should handle league with many members', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Many Members League' });
const season = await factory.createSeason(league.id.toString());
// Create 15 drivers
const drivers = await Promise.all(
Array.from({ length: 15 }, (_, i) =>
factory.createDriver({ name: `Member ${i + 1}`, iracingId: `${2000 + i}` })
)
);
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Should have all drivers
expect(response.memberships.length).toBeGreaterThanOrEqual(15);
// All memberships should have correct structure
for (const membership of response.memberships) {
expect(membership).toHaveProperty('driverId');
expect(membership).toHaveProperty('driver');
expect(membership).toHaveProperty('role');
expect(membership).toHaveProperty('status');
expect(membership).toHaveProperty('joinedAt');
}
});
it('should handle members with different roles', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Roles League' });
const season = await factory.createSeason(league.id.toString());
const drivers = await Promise.all([
factory.createDriver({ name: 'Owner', country: 'US' }),
factory.createDriver({ name: 'Admin', country: 'UK' }),
factory.createDriver({ name: 'Member', country: 'CA' }),
]);
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Should have members with different roles
const roles = response.memberships.map(m => m.role);
expect(roles.length).toBeGreaterThan(0);
// Verify roles are present
const hasOwner = roles.some(r => r === 'owner' || r === 'OWNER');
const hasAdmin = roles.some(r => r === 'admin' || r === 'ADMIN');
const hasMember = roles.some(r => r === 'member' || r === 'MEMBER');
// At least owner should exist
expect(hasOwner || hasAdmin || hasMember).toBe(true);
});
});
describe('Data Consistency', () => {
it('should maintain data consistency across multiple API calls', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Consistency Members League' });
const season = await factory.createSeason(league.id.toString());
const driver = await factory.createDriver({ name: 'Consistent Member', country: 'DE' });
const api = harness.getApi();
// Make multiple calls
const response1 = await api.get(`/leagues/${league.id}/memberships`);
const response2 = await api.get(`/leagues/${league.id}/memberships`);
const response3 = await api.get(`/leagues/${league.id}/memberships`);
// All responses should be identical
expect(response1).toEqual(response2);
expect(response2).toEqual(response3);
// Verify data integrity
expect(response1.memberships.length).toBeGreaterThan(0);
const consistentMember = response1.memberships.find(m => m.driver.name === 'Consistent Member');
expect(consistentMember).toBeDefined();
expect(consistentMember?.driver.country).toBe('DE');
});
it('should handle edge case: league with many members and complex data', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Complex Members League' });
const season = await factory.createSeason(league.id.toString());
// Create 20 drivers
const drivers = await Promise.all(
Array.from({ length: 20 }, (_, i) =>
factory.createDriver({
name: `Complex Member ${i + 1}`,
iracingId: `${3000 + i}`,
country: ['US', 'UK', 'CA', 'DE', 'FR'][i % 5]
})
)
);
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Should have all drivers
expect(response.memberships.length).toBeGreaterThanOrEqual(20);
// All memberships should have correct structure
for (const membership of response.memberships) {
expect(membership).toHaveProperty('driverId');
expect(membership).toHaveProperty('driver');
expect(membership).toHaveProperty('role');
expect(membership).toHaveProperty('status');
expect(membership).toHaveProperty('joinedAt');
// Verify driver has all required fields
expect(membership.driver).toHaveProperty('id');
expect(membership.driver).toHaveProperty('iracingId');
expect(membership.driver).toHaveProperty('name');
expect(membership.driver).toHaveProperty('country');
expect(membership.driver).toHaveProperty('joinedAt');
}
// Verify all drivers are present
const driverNames = response.memberships.map(m => m.driver.name);
for (const driver of drivers) {
expect(driverNames).toContain(driver.name.toString());
}
});
it('should handle edge case: members with optional fields', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'Optional Fields League' });
const season = await factory.createSeason(league.id.toString());
// Create driver without bio (should be optional)
const driver = await factory.createDriver({ name: 'Test Member', country: 'US' });
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
expect(response.memberships.length).toBeGreaterThan(0);
const testMember = response.memberships.find(m => m.driver.name === 'Test Member');
expect(testMember).toBeDefined();
expect(testMember?.driver.bio).toBeUndefined(); // Optional field
expect(testMember?.driver.name).toBe('Test Member');
expect(testMember?.driver.country).toBe('US');
});
it('should handle edge case: league with no completed races but has members', async () => {
const factory = harness.getFactory();
const league = await factory.createLeague({ name: 'No Races Members League' });
const season = await factory.createSeason(league.id.toString());
const driver = await factory.createDriver({ name: 'Waiting Member', country: 'US' });
// Create only scheduled races (no completed races)
const race = await factory.createRace({
leagueId: league.id.toString(),
track: 'Future Track',
car: 'Future Car',
scheduledAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
status: 'scheduled'
});
const api = harness.getApi();
const response = await api.get(`/leagues/${league.id}/memberships`);
// Should still have members even with no completed races
expect(response.memberships.length).toBeGreaterThan(0);
const waitingMember = response.memberships.find(m => m.driver.name === 'Waiting Member');
expect(waitingMember).toBeDefined();
});
});
});