resolve manual DTOs

This commit is contained in:
2025-12-18 22:19:40 +01:00
parent 4a3087ae35
commit d617654928
179 changed files with 3716 additions and 1257 deletions

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, vi, Mocked } from 'vitest';
import { MembershipFeeService, GetMembershipFeesOutputDto } from './MembershipFeeService';
import { MembershipFeeService } from './MembershipFeeService';
import { PaymentsApiClient } from '../../api/payments/PaymentsApiClient';
import { MembershipFeeViewModel } from '../../view-models';
import type { MembershipFeeDto } from '../../types/generated';
@@ -17,36 +17,30 @@ describe('MembershipFeeService', () => {
});
describe('getMembershipFees', () => {
it('should call apiClient.getMembershipFees with correct leagueId and return mapped view models', async () => {
it('should call apiClient.getMembershipFees with correct leagueId and return fee and payments', async () => {
const leagueId = 'league-123';
const mockFees: MembershipFeeDto[] = [
{ id: 'fee-1', leagueId: 'league-123' },
{ id: 'fee-2', leagueId: 'league-123' },
];
const mockOutput: GetMembershipFeesOutputDto = { fees: mockFees };
const mockFee: MembershipFeeDto = { id: 'fee-1', leagueId: 'league-123', seasonId: undefined, type: 'season', amount: 100, enabled: true, createdAt: new Date(), updatedAt: new Date() };
const mockPayments: any[] = [];
const mockOutput = { fee: mockFee, payments: mockPayments };
mockApiClient.getMembershipFees.mockResolvedValue(mockOutput);
const result = await service.getMembershipFees(leagueId);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith(leagueId);
expect(result).toHaveLength(2);
expect(result[0]).toBeInstanceOf(MembershipFeeViewModel);
expect(result[0].id).toEqual('fee-1');
expect(result[0].leagueId).toEqual('league-123');
expect(result[1]).toBeInstanceOf(MembershipFeeViewModel);
expect(result[1].id).toEqual('fee-2');
expect(result[1].leagueId).toEqual('league-123');
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith({ leagueId });
expect(result.fee).toBeInstanceOf(MembershipFeeViewModel);
expect(result.fee!.id).toEqual('fee-1');
expect(result.payments).toEqual([]);
});
it('should return empty array when no fees are returned', async () => {
it('should return null fee when no fee is returned', async () => {
const leagueId = 'league-456';
const mockOutput: GetMembershipFeesOutputDto = { fees: [] };
const mockOutput = { fee: null, payments: [] };
mockApiClient.getMembershipFees.mockResolvedValue(mockOutput);
const result = await service.getMembershipFees(leagueId);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith(leagueId);
expect(result).toEqual([]);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith({ leagueId });
expect(result.fee).toBeNull();
});
});
});

View File

@@ -4,7 +4,8 @@ import { PaymentsApiClient } from '../../api/payments/PaymentsApiClient';
// TODO: This DTO should be generated from OpenAPI spec when the endpoint is added
export interface GetMembershipFeesOutputDto {
fees: MembershipFeeDto[];
fee: MembershipFeeDto | null;
payments: import('./MemberPaymentDto').MemberPaymentDto[];
}
/**
@@ -21,8 +22,11 @@ export class MembershipFeeService {
/**
* Get membership fees by league ID with view model transformation
*/
async getMembershipFees(leagueId: string): Promise<MembershipFeeViewModel[]> {
const dto = await this.apiClient.getMembershipFees(leagueId);
return dto.fees.map((fee: MembershipFeeDto) => new MembershipFeeViewModel(fee));
async getMembershipFees(leagueId: string): Promise<{ fee: MembershipFeeViewModel | null; payments: any[] }> {
const dto = await this.apiClient.getMembershipFees({ leagueId });
return {
fee: dto.fee ? new MembershipFeeViewModel(dto.fee) : null,
payments: dto.payments // TODO: map to view models if needed
};
}
}

View File

@@ -42,7 +42,7 @@ describe('PaymentService', () => {
const result = await service.getPayments();
expect(mockApiClient.getPayments).toHaveBeenCalledWith(undefined, undefined);
expect(mockApiClient.getPayments).toHaveBeenCalledWith(undefined);
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(PaymentViewModel);
expect(result[0].id).toBe('payment-1');
@@ -54,7 +54,7 @@ describe('PaymentService', () => {
await service.getPayments('league-1', 'user-1');
expect(mockApiClient.getPayments).toHaveBeenCalledWith('league-1', 'user-1');
expect(mockApiClient.getPayments).toHaveBeenCalledWith({ leagueId: 'league-1', payerId: 'user-1' });
});
});
@@ -189,7 +189,7 @@ describe('PaymentService', () => {
const result = await service.getPrizes();
expect(mockApiClient.getPrizes).toHaveBeenCalledWith(undefined, undefined);
expect(mockApiClient.getPrizes).toHaveBeenCalledWith(undefined);
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(PrizeViewModel);
expect(result[0].id).toBe('prize-1');
@@ -201,7 +201,7 @@ describe('PaymentService', () => {
await service.getPrizes('league-1', 'season-1');
expect(mockApiClient.getPrizes).toHaveBeenCalledWith('league-1', 'season-1');
expect(mockApiClient.getPrizes).toHaveBeenCalledWith({ leagueId: 'league-1', seasonId: 'season-1' });
});
});
@@ -232,9 +232,9 @@ describe('PaymentService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith('user-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith({ leagueId: 'league-1' });
expect(result).toBeInstanceOf(WalletViewModel);
expect(result.id).toBe('wallet-1');
expect(result.balance).toBe(1000);

View File

@@ -31,8 +31,9 @@ export class PaymentService {
/**
* Get all payments with optional filters
*/
async getPayments(leagueId?: string, driverId?: string): Promise<PaymentViewModel[]> {
const dto = await this.apiClient.getPayments(leagueId, driverId);
async getPayments(leagueId?: string, payerId?: string): Promise<PaymentViewModel[]> {
const query = leagueId || payerId ? { leagueId, payerId } : undefined;
const dto = await this.apiClient.getPayments(query);
return dto.payments.map((payment: PaymentDTO) => new PaymentViewModel(payment));
}
@@ -60,8 +61,8 @@ export class PaymentService {
/**
* Get membership fees for a league
*/
async getMembershipFees(leagueId: string): Promise<MembershipFeeViewModel | null> {
const dto = await this.apiClient.getMembershipFees(leagueId);
async getMembershipFees(leagueId: string, driverId?: string): Promise<MembershipFeeViewModel | null> {
const dto = await this.apiClient.getMembershipFees({ leagueId, driverId });
return dto.fee ? new MembershipFeeViewModel(dto.fee) : null;
}
@@ -69,22 +70,23 @@ export class PaymentService {
* Get prizes with optional filters
*/
async getPrizes(leagueId?: string, seasonId?: string): Promise<PrizeViewModel[]> {
const dto = await this.apiClient.getPrizes(leagueId, seasonId);
const query = leagueId || seasonId ? { leagueId, seasonId } : undefined;
const dto = await this.apiClient.getPrizes(query);
return dto.prizes.map((prize: PrizeDto) => new PrizeViewModel(prize));
}
/**
* Get wallet for a driver
* Get wallet for a league
*/
async getWallet(driverId: string): Promise<WalletViewModel> {
const dto = await this.apiClient.getWallet(driverId);
async getWallet(leagueId: string): Promise<WalletViewModel> {
const dto = await this.apiClient.getWallet({ leagueId });
return new WalletViewModel({ ...dto.wallet, transactions: dto.transactions });
}
/**
* Get payment history for a user (driver)
*/
async getPaymentHistory(driverId: string): Promise<PaymentViewModel[]> {
return await this.getPayments(undefined, driverId);
async getPaymentHistory(payerId: string): Promise<PaymentViewModel[]> {
return await this.getPayments(undefined, payerId);
}
}

View File

@@ -42,9 +42,9 @@ describe('WalletService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith('user-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith({ leagueId: 'league-1' });
expect(result).toBeInstanceOf(WalletViewModel);
expect(result.id).toBe('wallet-1');
expect(result.balance).toBe(1000);
@@ -69,7 +69,7 @@ describe('WalletService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(result.transactions).toHaveLength(0);
});