Files
gridpilot.gg/tests/contracts/driver-contract.test.ts
Marc Mintel 12027793b1
Some checks failed
Contract Testing / contract-tests (pull_request) Failing after 5m47s
Contract Testing / contract-snapshot (pull_request) Has been skipped
contract tests
2026-01-22 17:31:54 +01:00

1329 lines
57 KiB
TypeScript

import { describe, expect, it } from 'vitest';
/**
* Contract Validation Tests for Driver Module
*
* These tests validate that the driver API DTOs and OpenAPI spec are consistent
* and that the generated types will be compatible with the website driver client.
*/
import * as fs from 'fs/promises';
import * as path from 'path';
interface OpenAPISchema {
type?: string;
format?: string;
$ref?: string;
items?: OpenAPISchema;
properties?: Record<string, OpenAPISchema>;
required?: string[];
enum?: string[];
nullable?: boolean;
description?: string;
default?: unknown;
}
interface OpenAPISpec {
openapi: string;
info: {
title: string;
description: string;
version: string;
};
paths: Record<string, {
get?: {
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
responses: Record<string, {
content: Record<string, {
schema: { $ref: string };
}>;
}>;
requestBody?: {
content: Record<string, {
schema: { $ref: string };
}>;
};
};
post?: {
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
responses: Record<string, {
content: Record<string, {
schema: { $ref: string };
}>;
}>;
requestBody?: {
content: Record<string, {
schema: { $ref: string };
}>;
};
};
put?: {
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
responses: Record<string, {
content: Record<string, {
schema: { $ref: string };
}>;
}>;
requestBody?: {
content: Record<string, {
schema: { $ref: string };
}>;
};
};
patch?: {
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
responses: Record<string, {
content: Record<string, {
schema: { $ref: string };
}>;
}>;
requestBody?: {
content: Record<string, {
schema: { $ref: string };
}>;
};
};
delete?: {
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
responses: Record<string, {
content: Record<string, {
schema: { $ref: string };
}>;
}>;
};
parameters?: Array<{ name: string; in: string; schema?: OpenAPISchema }>;
}>;
components: {
schemas: Record<string, OpenAPISchema>;
};
}
describe('Driver Module Contract Validation', () => {
it('should pass', () => {
expect(true).toBe(true);
});
const apiRoot = path.join(__dirname, '../..');
const openapiPath = path.join(apiRoot, 'apps/api/openapi.json');
const generatedTypesDir = path.join(apiRoot, 'apps/website/lib/types/generated');
const websiteTypesDir = path.join(apiRoot, 'apps/website/lib/types');
describe('OpenAPI Spec Integrity for Driver Endpoints', () => {
it('should have driver endpoints defined in OpenAPI spec', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Check for driver endpoints
expect(spec.paths['/drivers/leaderboard']).toBeDefined();
expect(spec.paths['/drivers/total-drivers']).toBeDefined();
expect(spec.paths['/drivers/current']).toBeDefined();
expect(spec.paths['/drivers/{driverId}']).toBeDefined();
expect(spec.paths['/drivers/{driverId}/profile']).toBeDefined();
expect(spec.paths['/drivers/{driverId}/liveries']).toBeDefined();
expect(spec.paths['/drivers/{driverId}/races/{raceId}/registration-status']).toBeDefined();
expect(spec.paths['/drivers/complete-onboarding']).toBeDefined();
// Verify GET methods exist
expect(spec.paths['/drivers/leaderboard'].get).toBeDefined();
expect(spec.paths['/drivers/total-drivers'].get).toBeDefined();
expect(spec.paths['/drivers/current'].get).toBeDefined();
expect(spec.paths['/drivers/{driverId}'].get).toBeDefined();
expect(spec.paths['/drivers/{driverId}/profile'].get).toBeDefined();
expect(spec.paths['/drivers/{driverId}/liveries'].get).toBeDefined();
expect(spec.paths['/drivers/{driverId}/races/{raceId}/registration-status'].get).toBeDefined();
// Verify POST methods exist
expect(spec.paths['/drivers/complete-onboarding'].post).toBeDefined();
});
it('should have GetDriverOutputDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverOutputDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('id');
expect(schema.required).toContain('iracingId');
expect(schema.required).toContain('name');
expect(schema.required).toContain('country');
expect(schema.required).toContain('joinedAt');
// Verify optional fields
expect(schema.properties?.bio).toBeDefined();
expect(schema.properties?.category).toBeDefined();
expect(schema.properties?.rating).toBeDefined();
expect(schema.properties?.experienceLevel).toBeDefined();
expect(schema.properties?.wins).toBeDefined();
expect(schema.properties?.podiums).toBeDefined();
expect(schema.properties?.totalRaces).toBeDefined();
expect(schema.properties?.avatarUrl).toBeDefined();
});
it('should have GetDriverProfileOutputDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverProfileOutputDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('teamMemberships');
expect(schema.required).toContain('socialSummary');
// Verify optional fields
expect(schema.properties?.currentDriver).toBeDefined();
expect(schema.properties?.stats).toBeDefined();
expect(schema.properties?.finishDistribution).toBeDefined();
expect(schema.properties?.extendedProfile).toBeDefined();
});
it('should have DriverRegistrationStatusDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriverRegistrationStatusDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('isRegistered');
expect(schema.required).toContain('raceId');
expect(schema.required).toContain('driverId');
});
it('should have DriversLeaderboardDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriversLeaderboardDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('drivers');
expect(schema.required).toContain('totalRaces');
expect(schema.required).toContain('totalWins');
expect(schema.required).toContain('activeCount');
});
it('should have DriverLeaderboardItemDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriverLeaderboardItemDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('id');
expect(schema.required).toContain('name');
expect(schema.required).toContain('rating');
expect(schema.required).toContain('skillLevel');
expect(schema.required).toContain('nationality');
expect(schema.required).toContain('racesCompleted');
expect(schema.required).toContain('wins');
expect(schema.required).toContain('podiums');
expect(schema.required).toContain('isActive');
expect(schema.required).toContain('rank');
// Verify optional fields
expect(schema.properties?.category).toBeDefined();
expect(schema.properties?.avatarUrl).toBeDefined();
});
it('should have CompleteOnboardingInputDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['CompleteOnboardingInputDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('firstName');
expect(schema.required).toContain('lastName');
expect(schema.required).toContain('displayName');
expect(schema.required).toContain('country');
// Verify optional fields
expect(schema.properties?.timezone).toBeDefined();
expect(schema.properties?.bio).toBeDefined();
});
it('should have CompleteOnboardingOutputDTO schema defined', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['CompleteOnboardingOutputDTO'];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// Verify required fields
expect(schema.required).toContain('success');
// Verify optional fields
expect(schema.properties?.driverId).toBeDefined();
expect(schema.properties?.errorMessage).toBeDefined();
});
it('should have proper request/response structure for driver leaderboard endpoint', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const leaderboardPath = spec.paths['/drivers/leaderboard']?.get;
expect(leaderboardPath).toBeDefined();
// Verify response
const response200 = leaderboardPath.responses['200'];
expect(response200).toBeDefined();
expect(response200.content['application/json']?.schema.$ref).toBe('#/components/schemas/DriversLeaderboardDTO');
});
it('should have proper request/response structure for get driver endpoint', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const driverPath = spec.paths['/drivers/{driverId}']?.get;
expect(driverPath).toBeDefined();
// Verify path parameters
expect(driverPath.parameters).toBeDefined();
const driverIdParam = driverPath.parameters.find((p: { name: string }) => p.name === 'driverId');
expect(driverIdParam).toBeDefined();
expect(driverIdParam.in).toBe('path');
// Verify response
const response200 = driverPath.responses['200'];
expect(response200).toBeDefined();
expect(response200.content['application/json']?.schema.$ref).toBe('#/components/schemas/GetDriverOutputDTO');
});
it('should have proper request/response structure for get driver profile endpoint', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const profilePath = spec.paths['/drivers/{driverId}/profile']?.get;
expect(profilePath).toBeDefined();
// Verify path parameters
expect(profilePath.parameters).toBeDefined();
const driverIdParam = profilePath.parameters.find((p: { name: string }) => p.name === 'driverId');
expect(driverIdParam).toBeDefined();
expect(driverIdParam.in).toBe('path');
// Verify response
const response200 = profilePath.responses['200'];
expect(response200).toBeDefined();
expect(response200.content['application/json']?.schema.$ref).toBe('#/components/schemas/GetDriverProfileOutputDTO');
});
it('should have proper request/response structure for complete onboarding endpoint', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const onboardingPath = spec.paths['/drivers/complete-onboarding']?.post;
expect(onboardingPath).toBeDefined();
// Verify request body
expect(onboardingPath.requestBody).toBeDefined();
expect(onboardingPath.requestBody?.content['application/json']?.schema.$ref).toBe('#/components/schemas/CompleteOnboardingInputDTO');
// Verify response
const response200 = onboardingPath.responses['200'];
expect(response200).toBeDefined();
expect(response200.content['application/json']?.schema.$ref).toBe('#/components/schemas/CompleteOnboardingOutputDTO');
});
it('should have proper request/response structure for driver registration status endpoint', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const registrationPath = spec.paths['/drivers/{driverId}/races/{raceId}/registration-status']?.get;
expect(registrationPath).toBeDefined();
// Verify path parameters
expect(registrationPath.parameters).toBeDefined();
const driverIdParam = registrationPath.parameters.find((p: { name: string }) => p.name === 'driverId');
const raceIdParam = registrationPath.parameters.find((p: { name: string }) => p.name === 'raceId');
expect(driverIdParam).toBeDefined();
expect(raceIdParam).toBeDefined();
expect(driverIdParam.in).toBe('path');
expect(raceIdParam.in).toBe('path');
// Verify response
const response200 = registrationPath.responses['200'];
expect(response200).toBeDefined();
expect(response200.content['application/json']?.schema.$ref).toBe('#/components/schemas/DriverRegistrationStatusDTO');
});
});
describe('DTO Consistency', () => {
it('should have generated DTO files for driver schemas', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const generatedFiles = await fs.readdir(generatedTypesDir);
const generatedDTOs = generatedFiles
.filter(f => f.endsWith('.ts'))
.map(f => f.replace('.ts', ''));
// Check for driver-related DTOs
const driverDTOs = [
'GetDriverOutputDTO',
'GetDriverProfileOutputDTO',
'DriverRegistrationStatusDTO',
'DriversLeaderboardDTO',
'DriverLeaderboardItemDTO',
'CompleteOnboardingInputDTO',
'CompleteOnboardingOutputDTO',
'GetDriverLiveriesOutputDTO',
];
for (const dtoName of driverDTOs) {
expect(spec.components.schemas[dtoName]).toBeDefined();
expect(generatedDTOs).toContain(dtoName);
}
});
it('should have consistent property types between DTOs and schemas', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schemas = spec.components.schemas;
// Test GetDriverOutputDTO
const getDriverSchema = schemas['GetDriverOutputDTO'];
const getDriverDtoPath = path.join(generatedTypesDir, 'GetDriverOutputDTO.ts');
const getDriverDtoExists = await fs.access(getDriverDtoPath).then(() => true).catch(() => false);
if (getDriverDtoExists) {
const getDriverDtoContent = await fs.readFile(getDriverDtoPath, 'utf-8');
// Check that all required properties are present
if (getDriverSchema.required) {
for (const requiredProp of getDriverSchema.required) {
expect(getDriverDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (getDriverSchema.properties) {
for (const propName of Object.keys(getDriverSchema.properties)) {
expect(getDriverDtoContent).toContain(propName);
}
}
}
// Test GetDriverProfileOutputDTO
const getDriverProfileSchema = schemas['GetDriverProfileOutputDTO'];
const getDriverProfileDtoPath = path.join(generatedTypesDir, 'GetDriverProfileOutputDTO.ts');
const getDriverProfileDtoExists = await fs.access(getDriverProfileDtoPath).then(() => true).catch(() => false);
if (getDriverProfileDtoExists) {
const getDriverProfileDtoContent = await fs.readFile(getDriverProfileDtoPath, 'utf-8');
// Check that all required properties are present
if (getDriverProfileSchema.required) {
for (const requiredProp of getDriverProfileSchema.required) {
expect(getDriverProfileDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (getDriverProfileSchema.properties) {
for (const propName of Object.keys(getDriverProfileSchema.properties)) {
expect(getDriverProfileDtoContent).toContain(propName);
}
}
}
// Test DriverRegistrationStatusDTO
const driverRegistrationSchema = schemas['DriverRegistrationStatusDTO'];
const driverRegistrationDtoPath = path.join(generatedTypesDir, 'DriverRegistrationStatusDTO.ts');
const driverRegistrationDtoExists = await fs.access(driverRegistrationDtoPath).then(() => true).catch(() => false);
if (driverRegistrationDtoExists) {
const driverRegistrationDtoContent = await fs.readFile(driverRegistrationDtoPath, 'utf-8');
// Check that all required properties are present
if (driverRegistrationSchema.required) {
for (const requiredProp of driverRegistrationSchema.required) {
expect(driverRegistrationDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (driverRegistrationSchema.properties) {
for (const propName of Object.keys(driverRegistrationSchema.properties)) {
expect(driverRegistrationDtoContent).toContain(propName);
}
}
}
// Test DriversLeaderboardDTO
const driversLeaderboardSchema = schemas['DriversLeaderboardDTO'];
const driversLeaderboardDtoPath = path.join(generatedTypesDir, 'DriversLeaderboardDTO.ts');
const driversLeaderboardDtoExists = await fs.access(driversLeaderboardDtoPath).then(() => true).catch(() => false);
if (driversLeaderboardDtoExists) {
const driversLeaderboardDtoContent = await fs.readFile(driversLeaderboardDtoPath, 'utf-8');
// Check that all required properties are present
if (driversLeaderboardSchema.required) {
for (const requiredProp of driversLeaderboardSchema.required) {
expect(driversLeaderboardDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (driversLeaderboardSchema.properties) {
for (const propName of Object.keys(driversLeaderboardSchema.properties)) {
expect(driversLeaderboardDtoContent).toContain(propName);
}
}
}
// Test DriverLeaderboardItemDTO
const driverLeaderboardItemSchema = schemas['DriverLeaderboardItemDTO'];
const driverLeaderboardItemDtoPath = path.join(generatedTypesDir, 'DriverLeaderboardItemDTO.ts');
const driverLeaderboardItemDtoExists = await fs.access(driverLeaderboardItemDtoPath).then(() => true).catch(() => false);
if (driverLeaderboardItemDtoExists) {
const driverLeaderboardItemDtoContent = await fs.readFile(driverLeaderboardItemDtoPath, 'utf-8');
// Check that all required properties are present
if (driverLeaderboardItemSchema.required) {
for (const requiredProp of driverLeaderboardItemSchema.required) {
expect(driverLeaderboardItemDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (driverLeaderboardItemSchema.properties) {
for (const propName of Object.keys(driverLeaderboardItemSchema.properties)) {
expect(driverLeaderboardItemDtoContent).toContain(propName);
}
}
}
// Test CompleteOnboardingInputDTO
const completeOnboardingInputSchema = schemas['CompleteOnboardingInputDTO'];
const completeOnboardingInputDtoPath = path.join(generatedTypesDir, 'CompleteOnboardingInputDTO.ts');
const completeOnboardingInputDtoExists = await fs.access(completeOnboardingInputDtoPath).then(() => true).catch(() => false);
if (completeOnboardingInputDtoExists) {
const completeOnboardingInputDtoContent = await fs.readFile(completeOnboardingInputDtoPath, 'utf-8');
// Check that all required properties are present
if (completeOnboardingInputSchema.required) {
for (const requiredProp of completeOnboardingInputSchema.required) {
expect(completeOnboardingInputDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (completeOnboardingInputSchema.properties) {
for (const propName of Object.keys(completeOnboardingInputSchema.properties)) {
expect(completeOnboardingInputDtoContent).toContain(propName);
}
}
}
// Test CompleteOnboardingOutputDTO
const completeOnboardingOutputSchema = schemas['CompleteOnboardingOutputDTO'];
const completeOnboardingOutputDtoPath = path.join(generatedTypesDir, 'CompleteOnboardingOutputDTO.ts');
const completeOnboardingOutputDtoExists = await fs.access(completeOnboardingOutputDtoPath).then(() => true).catch(() => false);
if (completeOnboardingOutputDtoExists) {
const completeOnboardingOutputDtoContent = await fs.readFile(completeOnboardingOutputDtoPath, 'utf-8');
// Check that all required properties are present
if (completeOnboardingOutputSchema.required) {
for (const requiredProp of completeOnboardingOutputSchema.required) {
expect(completeOnboardingOutputDtoContent).toContain(requiredProp);
}
}
// Check that all properties are present
if (completeOnboardingOutputSchema.properties) {
for (const propName of Object.keys(completeOnboardingOutputSchema.properties)) {
expect(completeOnboardingOutputDtoContent).toContain(propName);
}
}
}
});
it('should have driver types defined in tbd folder', async () => {
const generatedFiles = await fs.readdir(generatedTypesDir);
const driverGenerated = generatedFiles.filter(f =>
f.includes('Driver') ||
f.includes('GetDriver') ||
f.includes('CompleteOnboarding')
);
expect(driverGenerated.length).toBeGreaterThanOrEqual(8);
});
it('should have driver types re-exported from main types file', async () => {
// Check if there's a driver.ts file or if types are exported elsewhere
const driverTypesPath = path.join(websiteTypesDir, 'driver.ts');
const driverTypesExists = await fs.access(driverTypesPath).then(() => true).catch(() => false);
if (driverTypesExists) {
const driverTypesContent = await fs.readFile(driverTypesPath, 'utf-8');
// Verify re-exports
expect(driverTypesContent).toContain('GetDriverOutputDTO');
expect(driverTypesContent).toContain('GetDriverProfileOutputDTO');
expect(driverTypesContent).toContain('DriverRegistrationStatusDTO');
expect(driverTypesContent).toContain('DriversLeaderboardDTO');
expect(driverTypesContent).toContain('DriverLeaderboardItemDTO');
expect(driverTypesContent).toContain('CompleteOnboardingInputDTO');
expect(driverTypesContent).toContain('CompleteOnboardingOutputDTO');
}
});
});
describe('Driver API Client Contract', () => {
it('should have DriversApiClient defined', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientExists = await fs.access(driversApiClientPath).then(() => true).catch(() => false);
expect(driversApiClientExists).toBe(true);
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify class definition
expect(driversApiClientContent).toContain('export class DriversApiClient');
expect(driversApiClientContent).toContain('extends BaseApiClient');
// Verify methods exist
expect(driversApiClientContent).toContain('getLeaderboard');
expect(driversApiClientContent).toContain('completeOnboarding');
expect(driversApiClientContent).toContain('getCurrent');
expect(driversApiClientContent).toContain('getRegistrationStatus');
expect(driversApiClientContent).toContain('getDriver');
expect(driversApiClientContent).toContain('getDriverProfile');
expect(driversApiClientContent).toContain('updateProfile');
// Verify method signatures
expect(driversApiClientContent).toContain('getLeaderboard()');
expect(driversApiClientContent).toContain('completeOnboarding(input: CompleteOnboardingInputDTO)');
expect(driversApiClientContent).toContain('getCurrent()');
expect(driversApiClientContent).toContain('getRegistrationStatus(driverId: string, raceId: string)');
expect(driversApiClientContent).toContain('getDriver(driverId: string)');
expect(driversApiClientContent).toContain('getDriverProfile(driverId: string)');
expect(driversApiClientContent).toContain('updateProfile(updates: { bio?: string; country?: string })');
});
it('should have proper request construction in getLeaderboard method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify GET request
expect(driversApiClientContent).toContain("return this.get<DriversLeaderboardDto>('/drivers/leaderboard')");
});
it('should have proper request construction in completeOnboarding method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify POST request with input
expect(driversApiClientContent).toContain("return this.post<CompleteOnboardingOutputDTO>('/drivers/complete-onboarding', input)");
});
it('should have proper request construction in getCurrent method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify GET request with options
expect(driversApiClientContent).toContain("return this.get<GetDriverOutputDTO | null>('/drivers/current'");
expect(driversApiClientContent).toContain('allowUnauthenticated: true');
expect(driversApiClientContent).toContain('retry: false');
});
it('should have proper request construction in getRegistrationStatus method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify GET request with path parameters
expect(driversApiClientContent).toContain("return this.get<DriverRegistrationStatusDTO>(`/drivers/${driverId}/races/${raceId}/registration-status`)");
});
it('should have proper request construction in getDriver method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify GET request with path parameter
expect(driversApiClientContent).toContain("return this.get<GetDriverOutputDTO | null>(`/drivers/${driverId}`)");
});
it('should have proper request construction in getDriverProfile method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify GET request with path parameter
expect(driversApiClientContent).toContain("return this.get<GetDriverProfileOutputDTO>(`/drivers/${driverId}/profile`)");
});
it('should have proper request construction in updateProfile method', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify PUT request with updates
expect(driversApiClientContent).toContain("return this.put<GetDriverOutputDTO>('/drivers/profile', updates)");
});
});
describe('Request Correctness Tests', () => {
it('should validate GetDriverOutputDTO required fields', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverOutputDTO'];
// Verify all required fields are present
expect(schema.required).toContain('id');
expect(schema.required).toContain('iracingId');
expect(schema.required).toContain('name');
expect(schema.required).toContain('country');
expect(schema.required).toContain('joinedAt');
// Verify no extra required fields
expect(schema.required.length).toBe(5);
});
it('should validate GetDriverOutputDTO optional fields', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverOutputDTO'];
// Verify optional fields are not required
expect(schema.required).not.toContain('bio');
expect(schema.required).not.toContain('category');
expect(schema.required).not.toContain('rating');
expect(schema.required).not.toContain('experienceLevel');
expect(schema.required).not.toContain('wins');
expect(schema.required).not.toContain('podiums');
expect(schema.required).not.toContain('totalRaces');
expect(schema.required).not.toContain('avatarUrl');
// Verify optional fields exist
expect(schema.properties?.bio).toBeDefined();
expect(schema.properties?.category).toBeDefined();
expect(schema.properties?.rating).toBeDefined();
expect(schema.properties?.experienceLevel).toBeDefined();
expect(schema.properties?.wins).toBeDefined();
expect(schema.properties?.podiums).toBeDefined();
expect(schema.properties?.totalRaces).toBeDefined();
expect(schema.properties?.avatarUrl).toBeDefined();
});
it('should validate GetDriverProfileOutputDTO required fields', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverProfileOutputDTO'];
// Verify all required fields are present
expect(schema.required).toContain('teamMemberships');
expect(schema.required).toContain('socialSummary');
// Verify no extra required fields
expect(schema.required.length).toBe(2);
});
it('should validate GetDriverProfileOutputDTO optional fields', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['GetDriverProfileOutputDTO'];
// Verify optional fields are not required
expect(schema.required).not.toContain('currentDriver');
expect(schema.required).not.toContain('stats');
expect(schema.required).not.toContain('finishDistribution');
expect(schema.required).not.toContain('extendedProfile');
// Verify optional fields exist
expect(schema.properties?.currentDriver).toBeDefined();
expect(schema.properties?.stats).toBeDefined();
expect(schema.properties?.finishDistribution).toBeDefined();
expect(schema.properties?.extendedProfile).toBeDefined();
});
it('should validate DriverRegistrationStatusDTO structure', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriverRegistrationStatusDTO'];
// Verify all required fields
expect(schema.required).toContain('isRegistered');
expect(schema.required).toContain('raceId');
expect(schema.required).toContain('driverId');
// Verify field types
expect(schema.properties?.isRegistered?.type).toBe('boolean');
expect(schema.properties?.raceId?.type).toBe('string');
expect(schema.properties?.driverId?.type).toBe('string');
});
it('should validate DriversLeaderboardDTO structure', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriversLeaderboardDTO'];
// Verify all required fields
expect(schema.required).toContain('drivers');
expect(schema.required).toContain('totalRaces');
expect(schema.required).toContain('totalWins');
expect(schema.required).toContain('activeCount');
// Verify field types
expect(schema.properties?.drivers?.type).toBe('array');
expect(schema.properties?.totalRaces?.type).toBe('number');
expect(schema.properties?.totalWins?.type).toBe('number');
expect(schema.properties?.activeCount?.type).toBe('number');
});
it('should validate DriverLeaderboardItemDTO structure', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['DriverLeaderboardItemDTO'];
// Verify all required fields
expect(schema.required).toContain('id');
expect(schema.required).toContain('name');
expect(schema.required).toContain('rating');
expect(schema.required).toContain('skillLevel');
expect(schema.required).toContain('nationality');
expect(schema.required).toContain('racesCompleted');
expect(schema.required).toContain('wins');
expect(schema.required).toContain('podiums');
expect(schema.required).toContain('isActive');
expect(schema.required).toContain('rank');
// Verify field types
expect(schema.properties?.id?.type).toBe('string');
expect(schema.properties?.name?.type).toBe('string');
expect(schema.properties?.rating?.type).toBe('number');
expect(schema.properties?.skillLevel?.type).toBe('string');
expect(schema.properties?.nationality?.type).toBe('string');
expect(schema.properties?.racesCompleted?.type).toBe('number');
expect(schema.properties?.wins?.type).toBe('number');
expect(schema.properties?.podiums?.type).toBe('number');
expect(schema.properties?.isActive?.type).toBe('boolean');
expect(schema.properties?.rank?.type).toBe('number');
});
it('should validate CompleteOnboardingInputDTO structure', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['CompleteOnboardingInputDTO'];
// Verify all required fields
expect(schema.required).toContain('firstName');
expect(schema.required).toContain('lastName');
expect(schema.required).toContain('displayName');
expect(schema.required).toContain('country');
// Verify field types
expect(schema.properties?.firstName?.type).toBe('string');
expect(schema.properties?.lastName?.type).toBe('string');
expect(schema.properties?.displayName?.type).toBe('string');
expect(schema.properties?.country?.type).toBe('string');
expect(schema.properties?.timezone?.type).toBe('string');
expect(schema.properties?.bio?.type).toBe('string');
});
it('should validate CompleteOnboardingOutputDTO structure', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const schema = spec.components.schemas['CompleteOnboardingOutputDTO'];
// Verify all required fields
expect(schema.required).toContain('success');
// Verify field types
expect(schema.properties?.success?.type).toBe('boolean');
expect(schema.properties?.driverId?.type).toBe('string');
expect(schema.properties?.errorMessage?.type).toBe('string');
});
});
describe('Response Handling Tests', () => {
it('should handle successful driver response', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const getDriverSchema = spec.components.schemas['GetDriverOutputDTO'];
// Verify response structure
expect(getDriverSchema.properties?.id).toBeDefined();
expect(getDriverSchema.properties?.iracingId).toBeDefined();
expect(getDriverSchema.properties?.name).toBeDefined();
expect(getDriverSchema.properties?.country).toBeDefined();
expect(getDriverSchema.properties?.joinedAt).toBeDefined();
expect(getDriverSchema.properties?.bio).toBeDefined();
expect(getDriverSchema.properties?.category).toBeDefined();
expect(getDriverSchema.properties?.rating).toBeDefined();
expect(getDriverSchema.properties?.experienceLevel).toBeDefined();
expect(getDriverSchema.properties?.wins).toBeDefined();
expect(getDriverSchema.properties?.podiums).toBeDefined();
expect(getDriverSchema.properties?.totalRaces).toBeDefined();
expect(getDriverSchema.properties?.avatarUrl).toBeDefined();
});
it('should handle response with all required fields', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const getDriverSchema = spec.components.schemas['GetDriverOutputDTO'];
// Verify all required fields are present
for (const field of ['id', 'iracingId', 'name', 'country', 'joinedAt']) {
expect(getDriverSchema.required).toContain(field);
expect(getDriverSchema.properties?.[field]).toBeDefined();
}
});
it('should handle optional fields in driver response correctly', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const driverSchema = spec.components.schemas['GetDriverOutputDTO'];
// Verify optional fields are nullable
expect(driverSchema.properties?.bio?.nullable).toBe(true);
expect(driverSchema.properties?.category?.nullable).toBe(true);
expect(driverSchema.properties?.rating?.nullable).toBe(true);
expect(driverSchema.properties?.experienceLevel?.nullable).toBe(true);
expect(driverSchema.properties?.wins?.nullable).toBe(true);
expect(driverSchema.properties?.podiums?.nullable).toBe(true);
expect(driverSchema.properties?.totalRaces?.nullable).toBe(true);
expect(driverSchema.properties?.avatarUrl?.nullable).toBe(true);
// Verify optional fields are not in required array
expect(driverSchema.required).not.toContain('bio');
expect(driverSchema.required).not.toContain('category');
expect(driverSchema.required).not.toContain('rating');
expect(driverSchema.required).not.toContain('experienceLevel');
expect(driverSchema.required).not.toContain('wins');
expect(driverSchema.required).not.toContain('podiums');
expect(driverSchema.required).not.toContain('totalRaces');
expect(driverSchema.required).not.toContain('avatarUrl');
});
it('should handle optional fields in driver profile response correctly', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const profileSchema = spec.components.schemas['GetDriverProfileOutputDTO'];
// Verify optional fields are nullable
expect(profileSchema.properties?.currentDriver?.nullable).toBe(true);
expect(profileSchema.properties?.stats?.nullable).toBe(true);
expect(profileSchema.properties?.finishDistribution?.nullable).toBe(true);
expect(profileSchema.properties?.extendedProfile?.nullable).toBe(true);
// Verify optional fields are not in required array
expect(profileSchema.required).not.toContain('currentDriver');
expect(profileSchema.required).not.toContain('stats');
expect(profileSchema.required).not.toContain('finishDistribution');
expect(profileSchema.required).not.toContain('extendedProfile');
});
it('should handle optional fields in leaderboard item response correctly', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const leaderboardItemSchema = spec.components.schemas['DriverLeaderboardItemDTO'];
// Verify optional fields are nullable
expect(leaderboardItemSchema.properties?.category?.nullable).toBe(true);
expect(leaderboardItemSchema.properties?.avatarUrl?.nullable).toBe(true);
// Verify optional fields are not in required array
expect(leaderboardItemSchema.required).not.toContain('category');
expect(leaderboardItemSchema.required).not.toContain('avatarUrl');
});
it('should handle optional fields in complete onboarding output correctly', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const completeOnboardingSchema = spec.components.schemas['CompleteOnboardingOutputDTO'];
// Verify optional fields are nullable
expect(completeOnboardingSchema.properties?.driverId?.nullable).toBe(true);
expect(completeOnboardingSchema.properties?.errorMessage?.nullable).toBe(true);
// Verify optional fields are not in required array
expect(completeOnboardingSchema.required).not.toContain('driverId');
expect(completeOnboardingSchema.required).not.toContain('errorMessage');
});
});
describe('Error Handling Tests', () => {
it('should document 401 Unauthorized response for driver endpoints', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Check if 401 response is documented for driver endpoints
const driverEndpoints = [
'/drivers/current',
'/drivers/{driverId}',
'/drivers/{driverId}/profile',
'/drivers/{driverId}/liveries',
'/drivers/{driverId}/races/{raceId}/registration-status',
];
for (const endpoint of driverEndpoints) {
const driverPath = spec.paths[endpoint];
if (driverPath) {
const methods = Object.keys(driverPath);
for (const method of methods) {
const operation = driverPath[method];
if (operation.responses['401']) {
expect(operation.responses['401']).toBeDefined();
}
}
}
}
});
it('should document 404 Not Found response for driver endpoints', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Check if 404 response is documented for driver endpoints
const driverEndpoints = [
'/drivers/{driverId}',
'/drivers/{driverId}/profile',
'/drivers/{driverId}/liveries',
'/drivers/{driverId}/races/{raceId}/registration-status',
];
for (const endpoint of driverEndpoints) {
const driverPath = spec.paths[endpoint];
if (driverPath) {
const methods = Object.keys(driverPath);
for (const method of methods) {
const operation = driverPath[method];
if (operation.responses['404']) {
expect(operation.responses['404']).toBeDefined();
}
}
}
}
});
it('should document 500 Internal Server Error response', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Check if 500 response is documented for driver endpoints
const driverEndpoints = [
'/drivers/leaderboard',
'/drivers/total-drivers',
'/drivers/current',
'/drivers/{driverId}',
'/drivers/{driverId}/profile',
'/drivers/{driverId}/liveries',
'/drivers/{driverId}/races/{raceId}/registration-status',
'/drivers/complete-onboarding',
];
for (const endpoint of driverEndpoints) {
const driverPath = spec.paths[endpoint];
if (driverPath) {
const methods = Object.keys(driverPath);
for (const method of methods) {
const operation = driverPath[method];
if (operation.responses['500']) {
expect(operation.responses['500']).toBeDefined();
}
}
}
}
});
it('should have proper error handling in DriversApiClient', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify BaseApiClient is extended (which provides error handling)
expect(driversApiClientContent).toContain('extends BaseApiClient');
// Verify methods use BaseApiClient methods (which handle errors)
expect(driversApiClientContent).toContain('this.get<');
expect(driversApiClientContent).toContain('this.post<');
expect(driversApiClientContent).toContain('this.put<');
});
});
describe('Semantic Guarantee Tests', () => {
it('should maintain consistency between request and response schemas', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Verify driver overview request/response consistency
const getDriverSchema = spec.components.schemas['GetDriverOutputDTO'];
// Output should contain all required fields
expect(getDriverSchema.properties?.id).toBeDefined();
expect(getDriverSchema.properties?.iracingId).toBeDefined();
expect(getDriverSchema.properties?.name).toBeDefined();
expect(getDriverSchema.properties?.country).toBeDefined();
expect(getDriverSchema.properties?.joinedAt).toBeDefined();
});
it('should validate semantic consistency in driver data', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const getDriverSchema = spec.components.schemas['GetDriverOutputDTO'];
// Verify driver has all required fields
expect(getDriverSchema.required).toContain('id');
expect(getDriverSchema.required).toContain('iracingId');
expect(getDriverSchema.required).toContain('name');
expect(getDriverSchema.required).toContain('country');
expect(getDriverSchema.required).toContain('joinedAt');
});
it('should validate idempotency for driver endpoints', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Check if driver leaderboard endpoint exists
const leaderboardPath = spec.paths['/drivers/leaderboard']?.get;
if (leaderboardPath) {
// Verify it's a GET request (idempotent)
expect(leaderboardPath).toBeDefined();
// Verify no request body (GET requests are idempotent)
expect(leaderboardPath.requestBody).toBeUndefined();
}
// Check if get driver endpoint exists
const driverPath = spec.paths['/drivers/{driverId}']?.get;
if (driverPath) {
// Verify it's a GET request (idempotent)
expect(driverPath).toBeDefined();
// Verify no request body (GET requests are idempotent)
expect(driverPath.requestBody).toBeUndefined();
}
// Check if get driver profile endpoint exists
const profilePath = spec.paths['/drivers/{driverId}/profile']?.get;
if (profilePath) {
// Verify it's a GET request (idempotent)
expect(profilePath).toBeDefined();
// Verify no request body (GET requests are idempotent)
expect(profilePath.requestBody).toBeUndefined();
}
// Check if get driver registration status endpoint exists
const registrationPath = spec.paths['/drivers/{driverId}/races/{raceId}/registration-status']?.get;
if (registrationPath) {
// Verify it's a GET request (idempotent)
expect(registrationPath).toBeDefined();
// Verify no request body (GET requests are idempotent)
expect(registrationPath.requestBody).toBeUndefined();
}
});
it('should validate uniqueness constraints for driver IDs', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const driverSchema = spec.components.schemas['GetDriverOutputDTO'];
const driverLeaderboardItemSchema = spec.components.schemas['DriverLeaderboardItemDTO'];
// Verify driver ID is a required field
expect(driverSchema.required).toContain('id');
expect(driverSchema.properties?.id?.type).toBe('string');
// Verify driver leaderboard item ID is a required field
expect(driverLeaderboardItemSchema.required).toContain('id');
expect(driverLeaderboardItemSchema.properties?.id?.type).toBe('string');
});
it('should validate consistency between request and response types', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Verify all DTOs have consistent type definitions
const dtos = [
'GetDriverOutputDTO',
'GetDriverProfileOutputDTO',
'DriverRegistrationStatusDTO',
'DriversLeaderboardDTO',
'DriverLeaderboardItemDTO',
'CompleteOnboardingInputDTO',
'CompleteOnboardingOutputDTO',
];
for (const dtoName of dtos) {
const schema = spec.components.schemas[dtoName];
expect(schema).toBeDefined();
expect(schema.type).toBe('object');
// All should have properties defined
expect(schema.properties).toBeDefined();
// All should have required fields (even if empty array)
expect(schema.required).toBeDefined();
}
});
it('should validate semantic consistency in driver data', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const driversLeaderboardSchema = spec.components.schemas['DriversLeaderboardDTO'];
// Verify drivers are arrays
expect(driversLeaderboardSchema.properties?.drivers?.type).toBe('array');
// Verify counts are numbers
expect(driversLeaderboardSchema.properties?.totalRaces?.type).toBe('number');
expect(driversLeaderboardSchema.properties?.totalWins?.type).toBe('number');
expect(driversLeaderboardSchema.properties?.activeCount?.type).toBe('number');
});
it('should validate pagination is not applicable for driver endpoints', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
// Driver endpoints should not have pagination
const driverEndpoints = [
'/drivers/leaderboard',
'/drivers/total-drivers',
'/drivers/current',
'/drivers/{driverId}',
'/drivers/{driverId}/profile',
'/drivers/{driverId}/liveries',
'/drivers/{driverId}/races/{raceId}/registration-status',
'/drivers/complete-onboarding',
];
for (const endpoint of driverEndpoints) {
const driverPath = spec.paths[endpoint];
if (driverPath) {
const methods = Object.keys(driverPath);
for (const method of methods) {
const operation = driverPath[method];
if (operation.parameters) {
const paramNames = operation.parameters.map((p: { name: string }) => p.name);
// Driver endpoints should not have page/limit parameters
expect(paramNames).not.toContain('page');
expect(paramNames).not.toContain('limit');
}
}
}
}
});
});
describe('Driver Module Integration Tests', () => {
it('should have consistent types between API DTOs and website types', async () => {
const content = await fs.readFile(openapiPath, 'utf-8');
const spec: OpenAPISpec = JSON.parse(content);
const generatedFiles = await fs.readdir(generatedTypesDir);
const generatedDTOs = generatedFiles
.filter(f => f.endsWith('.ts'))
.map(f => f.replace('.ts', ''));
// Check all driver DTOs exist in generated types
const driverDTOs = [
'GetDriverOutputDTO',
'GetDriverProfileOutputDTO',
'DriverRegistrationStatusDTO',
'DriversLeaderboardDTO',
'DriverLeaderboardItemDTO',
'CompleteOnboardingInputDTO',
'CompleteOnboardingOutputDTO',
'GetDriverLiveriesOutputDTO',
];
for (const dtoName of driverDTOs) {
expect(spec.components.schemas[dtoName]).toBeDefined();
expect(generatedDTOs).toContain(dtoName);
}
});
it('should have DriversApiClient methods matching API endpoints', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify getLeaderboard method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async getLeaderboard');
expect(driversApiClientContent).toContain("return this.get<DriversLeaderboardDto>('/drivers/leaderboard')");
// Verify completeOnboarding method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async completeOnboarding');
expect(driversApiClientContent).toContain("return this.post<CompleteOnboardingOutputDTO>('/drivers/complete-onboarding', input)");
// Verify getCurrent method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async getCurrent');
expect(driversApiClientContent).toContain("return this.get<GetDriverOutputDTO | null>('/drivers/current'");
// Verify getRegistrationStatus method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async getRegistrationStatus');
expect(driversApiClientContent).toContain("return this.get<DriverRegistrationStatusDTO>(`/drivers/${driverId}/races/${raceId}/registration-status`)");
// Verify getDriver method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async getDriver');
expect(driversApiClientContent).toContain("return this.get<GetDriverOutputDTO | null>(`/drivers/${driverId}`)");
// Verify getDriverProfile method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async getDriverProfile');
expect(driversApiClientContent).toContain("return this.get<GetDriverProfileOutputDTO>(`/drivers/${driverId}/profile`)");
// Verify updateProfile method exists and uses correct endpoint
expect(driversApiClientContent).toContain('async updateProfile');
expect(driversApiClientContent).toContain("return this.put<GetDriverOutputDTO>('/drivers/profile', updates)");
});
it('should have proper error handling in DriversApiClient', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify BaseApiClient is extended (which provides error handling)
expect(driversApiClientContent).toContain('extends BaseApiClient');
// Verify methods use BaseApiClient methods (which handle errors)
expect(driversApiClientContent).toContain('this.get<');
expect(driversApiClientContent).toContain('this.post<');
expect(driversApiClientContent).toContain('this.put<');
});
it('should have consistent type imports in DriversApiClient', async () => {
const driversApiClientPath = path.join(apiRoot, 'apps/website/lib/api/drivers/DriversApiClient.ts');
const driversApiClientContent = await fs.readFile(driversApiClientPath, 'utf-8');
// Verify all required types are imported
expect(driversApiClientContent).toContain('CompleteOnboardingInputDTO');
expect(driversApiClientContent).toContain('CompleteOnboardingOutputDTO');
expect(driversApiClientContent).toContain('DriverRegistrationStatusDTO');
expect(driversApiClientContent).toContain('DriverLeaderboardItemDTO');
expect(driversApiClientContent).toContain('GetDriverOutputDTO');
expect(driversApiClientContent).toContain('GetDriverProfileOutputDTO');
});
});
});