test apps api

This commit is contained in:
2025-12-23 23:14:51 +01:00
parent 16cd572c63
commit efcdbd17f2
71 changed files with 3924 additions and 913 deletions

View File

@@ -12,6 +12,8 @@ import type { Logger } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import type { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
import { Money } from '@core/racing/domain/value-objects/Money';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
@@ -110,20 +112,20 @@ describe('SponsorService', () => {
const outputPort = {
entityType: 'season',
entityId: 'season-1',
tiers: [
{ name: 'Gold', price: 500, benefits: ['Main slot'] },
],
tiers: [{ name: 'Gold', price: { amount: 500, currency: 'USD' }, benefits: ['Main slot'] }],
};
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.ok(outputPort));
getSponsorshipPricingUseCase.execute.mockImplementation(async () => {
getEntitySponsorshipPricingPresenter.present(outputPort as any);
return Result.ok(undefined);
});
const result = await service.getEntitySponsorshipPricing();
expect(result).toEqual({
entityType: 'season',
entityId: 'season-1',
pricing: [
{ id: 'Gold', level: 'Gold', price: 500, currency: 'USD' },
],
pricing: [{ id: 'Gold', level: 'Gold', price: 500, currency: 'USD' }],
});
});
@@ -142,13 +144,32 @@ describe('SponsorService', () => {
describe('getSponsors', () => {
it('returns sponsors on success', async () => {
const sponsors = [{ id: 's1', name: 'S1', contactEmail: 's1@test', createdAt: new Date() }];
const outputPort = { sponsors };
getSponsorsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
const sponsors = [
Sponsor.create({
id: 'sponsor-1',
name: 'S1',
contactEmail: 's1@test.com',
createdAt: new Date('2024-01-01T00:00:00Z'),
}),
];
getSponsorsUseCase.execute.mockImplementation(async () => {
getSponsorsPresenter.present(sponsors);
return Result.ok(undefined);
});
const result = await service.getSponsors();
expect(result).toEqual({ sponsors });
expect(result).toEqual({
sponsors: [
{
id: 'sponsor-1',
name: 'S1',
contactEmail: 's1@test.com',
createdAt: new Date('2024-01-01T00:00:00Z'),
},
],
});
});
it('returns empty list on error', async () => {
@@ -163,18 +184,28 @@ describe('SponsorService', () => {
describe('createSponsor', () => {
it('returns created sponsor on success', async () => {
const input: CreateSponsorInputDTO = { name: 'Test', contactEmail: 'test@example.com' };
const sponsor = {
id: 's1',
const sponsor = Sponsor.create({
id: 'sponsor-1',
name: 'Test',
contactEmail: 'test@example.com',
createdAt: new Date(),
};
const outputPort = { sponsor };
createSponsorUseCase.execute.mockResolvedValue(Result.ok(outputPort));
createdAt: new Date('2024-01-01T00:00:00Z'),
});
createSponsorUseCase.execute.mockImplementation(async () => {
createSponsorPresenter.present(sponsor);
return Result.ok(undefined);
});
const result = await service.createSponsor(input);
expect(result).toEqual({ sponsor });
expect(result).toEqual({
sponsor: {
id: 'sponsor-1',
name: 'Test',
contactEmail: 'test@example.com',
createdAt: new Date('2024-01-01T00:00:00Z'),
},
});
});
it('throws on error', async () => {
@@ -185,6 +216,20 @@ describe('SponsorService', () => {
await expect(service.createSponsor(input)).rejects.toThrow('Invalid');
});
it('throws using error.message when details.message is missing', async () => {
const input: CreateSponsorInputDTO = { name: 'Test', contactEmail: 'test@example.com' };
createSponsorUseCase.execute.mockResolvedValue(Result.err({ code: 'VALIDATION_ERROR', message: 'Boom' } as any));
await expect(service.createSponsor(input)).rejects.toThrow('Boom');
});
it('throws default message when details.message and message are missing', async () => {
const input: CreateSponsorInputDTO = { name: 'Test', contactEmail: 'test@example.com' };
createSponsorUseCase.execute.mockResolvedValue(Result.err({ code: 'VALIDATION_ERROR' } as any));
await expect(service.createSponsor(input)).rejects.toThrow('Failed to create sponsor');
});
});
describe('getSponsorDashboard', () => {
@@ -206,15 +251,38 @@ describe('SponsorService', () => {
sponsoredLeagues: [],
investment: {
activeSponsorships: 0,
totalInvestment: 0,
totalInvestment: Money.create(0, 'USD'),
costPerThousandViews: 0,
},
};
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.ok(outputPort));
getSponsorDashboardUseCase.execute.mockImplementation(async () => {
getSponsorDashboardPresenter.present(outputPort as any);
return Result.ok(undefined);
});
const result = await service.getSponsorDashboard(params);
expect(result).toEqual(outputPort);
expect(result).toEqual({
sponsorId: 's1',
sponsorName: 'S1',
metrics: outputPort.metrics,
sponsoredLeagues: [],
investment: {
activeSponsorships: 0,
totalInvestment: 0,
costPerThousandViews: 0,
},
sponsorships: {
leagues: [],
teams: [],
drivers: [],
races: [],
platform: [],
},
recentActivity: [],
upcomingRenewals: [],
});
});
it('throws on error', async () => {
@@ -229,6 +297,28 @@ describe('SponsorService', () => {
it('returns sponsorships on success', async () => {
const params: GetSponsorSponsorshipsInput = { sponsorId: 's1' };
const outputPort = {
sponsor: Sponsor.create({
id: 's1',
name: 'S1',
contactEmail: 's1@example.com',
}),
sponsorships: [],
summary: {
totalSponsorships: 0,
activeSponsorships: 0,
totalInvestment: Money.create(0, 'USD'),
totalPlatformFees: Money.create(0, 'USD'),
},
};
getSponsorSponsorshipsUseCase.execute.mockImplementation(async () => {
getSponsorSponsorshipsPresenter.present(outputPort as any);
return Result.ok(undefined);
});
const result = await service.getSponsorSponsorships(params);
expect(result).toEqual({
sponsorId: 's1',
sponsorName: 'S1',
sponsorships: [],
@@ -239,39 +329,44 @@ describe('SponsorService', () => {
totalPlatformFees: 0,
currency: 'USD',
},
};
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
const result = await service.getSponsorSponsorships(params);
expect(result).toEqual(outputPort);
});
});
it('throws on error', async () => {
const params: GetSponsorSponsorshipsInput = { sponsorId: 's1' };
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(
Result.err({ code: 'REPOSITORY_ERROR' }),
);
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
await expect(service.getSponsorSponsorships(params)).rejects.toThrow('Sponsor sponsorships not found');
await expect(service.getSponsorSponsorships(params)).rejects.toThrow(
'Sponsor sponsorships not found',
);
});
});
describe('getSponsor', () => {
it('returns sponsor when found', async () => {
const sponsorId = 's1';
const sponsor = { id: sponsorId, name: 'S1' };
const output = { sponsor };
getSponsorUseCase.execute.mockResolvedValue(Result.ok(output));
const output = { sponsor: { id: sponsorId, name: 'S1' } };
getSponsorUseCase.execute.mockImplementation(async () => {
getSponsorPresenter.present(output);
return Result.ok(undefined);
});
const result = await service.getSponsor(sponsorId);
expect(result).toEqual({ sponsor });
expect(result).toEqual(output);
});
it('throws when not found', async () => {
const sponsorId = 's1';
getSponsorUseCase.execute.mockResolvedValue(Result.ok(null));
getSponsorUseCase.execute.mockResolvedValue(Result.err({ code: 'SPONSOR_NOT_FOUND' }));
await expect(service.getSponsor(sponsorId)).rejects.toThrow('Sponsor not found');
});
it('throws when viewModel is missing even if use case succeeds', async () => {
const sponsorId = 's1';
getSponsorUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.getSponsor(sponsorId)).rejects.toThrow('Sponsor not found');
});
@@ -286,7 +381,11 @@ describe('SponsorService', () => {
requests: [],
totalCount: 0,
};
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
getPendingSponsorshipRequestsUseCase.execute.mockImplementation(async () => {
getPendingSponsorshipRequestsPresenter.present(outputPort as any);
return Result.ok(undefined);
});
const result = await service.getPendingSponsorshipRequests(params);
@@ -295,9 +394,7 @@ describe('SponsorService', () => {
it('returns empty result on error', async () => {
const params = { entityType: 'season' as const, entityId: 'season-1' };
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(
Result.err({ code: 'REPOSITORY_ERROR' }),
);
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
const result = await service.getPendingSponsorshipRequests(params);
@@ -308,6 +405,13 @@ describe('SponsorService', () => {
totalCount: 0,
});
});
it('throws when presenter viewModel is missing on success', async () => {
const params = { entityType: 'season' as const, entityId: 'season-1' };
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.getPendingSponsorshipRequests(params)).rejects.toThrow('Pending sponsorship requests not found');
});
});
describe('SponsorshipRequest', () => {
@@ -322,7 +426,11 @@ describe('SponsorService', () => {
platformFee: 10,
netAmount: 90,
};
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(outputPort));
acceptSponsorshipRequestUseCase.execute.mockImplementation(async () => {
acceptSponsorshipRequestPresenter.present(outputPort as any);
return Result.ok(undefined);
});
const result = await service.acceptSponsorshipRequest(requestId, respondedBy);
@@ -336,7 +444,19 @@ describe('SponsorService', () => {
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
);
await expect(service.acceptSponsorshipRequest(requestId, respondedBy)).rejects.toThrow('Accept sponsorship request failed');
await expect(service.acceptSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Accept sponsorship request failed',
);
});
it('throws when presenter viewModel is missing on success', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.acceptSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Accept sponsorship request failed',
);
});
});
@@ -351,13 +471,38 @@ describe('SponsorService', () => {
respondedAt: new Date(),
rejectionReason: reason,
};
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
rejectSponsorshipRequestUseCase.execute.mockImplementation(async () => {
rejectSponsorshipRequestPresenter.present(output as any);
return Result.ok(undefined);
});
const result = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
expect(result).toEqual(output);
});
it('passes no reason when reason is undefined', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
rejectSponsorshipRequestUseCase.execute.mockImplementation(async (input: any) => {
expect(input).toEqual({ requestId, respondedBy });
rejectSponsorshipRequestPresenter.present({
requestId,
status: 'rejected' as const,
respondedAt: new Date(),
rejectionReason: '',
} as any);
return Result.ok(undefined);
});
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).resolves.toMatchObject({
requestId,
status: 'rejected',
});
});
it('throws on error', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
@@ -365,7 +510,19 @@ describe('SponsorService', () => {
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
);
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).rejects.toThrow('Reject sponsorship request failed');
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Reject sponsorship request failed',
);
});
it('throws when presenter viewModel is missing on success', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Reject sponsorship request failed',
);
});
});
@@ -395,6 +552,11 @@ describe('SponsorService', () => {
expect(result.invoices).toBeInstanceOf(Array);
expect(result.stats).toBeDefined();
});
it('throws on error', async () => {
getSponsorBillingUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' } as any));
await expect(service.getSponsorBilling('s1')).rejects.toThrow('Sponsor billing not found');
});
});
describe('getAvailableLeagues', () => {