website refactor
This commit is contained in:
305
tests/integration/league/members-data-flow.integration.test.ts
Normal file
305
tests/integration/league/members-data-flow.integration.test.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user