Files
gridpilot.gg/core/racing/application/use-cases/GetSponsorDashboardUseCase.test.ts
2025-12-23 15:38:50 +01:00

171 lines
5.8 KiB
TypeScript

import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import {
GetSponsorDashboardUseCase,
type GetSponsorDashboardInput,
type GetSponsorDashboardResult,
type GetSponsorDashboardErrorCode,
} from './GetSponsorDashboardUseCase';
import { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
import { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
import { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
import { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
import { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
import { IRaceRepository } from '../../domain/repositories/IRaceRepository';
import { Sponsor } from '../../domain/entities/sponsor/Sponsor';
import { SeasonSponsorship } from '../../domain/entities/season/SeasonSponsorship';
import { Season } from '../../domain/entities/season/Season';
import { League } from '../../domain/entities/League';
import { Money } from '../../domain/value-objects/Money';
import type { UseCaseOutputPort } from '@core/shared/application';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
describe('GetSponsorDashboardUseCase', () => {
let useCase: GetSponsorDashboardUseCase;
let sponsorRepository: {
findById: Mock;
};
let seasonSponsorshipRepository: {
findBySponsorId: Mock;
};
let seasonRepository: {
findById: Mock;
};
let leagueRepository: {
findById: Mock;
};
let leagueMembershipRepository: {
getLeagueMembers: Mock;
};
let raceRepository: {
findByLeagueId: Mock;
};
let output: UseCaseOutputPort<GetSponsorDashboardResult> & { present: Mock };
beforeEach(() => {
sponsorRepository = {
findById: vi.fn(),
};
seasonSponsorshipRepository = {
findBySponsorId: vi.fn(),
};
seasonRepository = {
findById: vi.fn(),
};
leagueRepository = {
findById: vi.fn(),
};
leagueMembershipRepository = {
getLeagueMembers: vi.fn(),
};
raceRepository = {
findByLeagueId: vi.fn(),
};
output = {
present: vi.fn(),
} as unknown as UseCaseOutputPort<GetSponsorDashboardResult> & { present: Mock };
useCase = new GetSponsorDashboardUseCase(
sponsorRepository as unknown as ISponsorRepository,
seasonSponsorshipRepository as unknown as ISeasonSponsorshipRepository,
seasonRepository as unknown as ISeasonRepository,
leagueRepository as unknown as ILeagueRepository,
leagueMembershipRepository as unknown as ILeagueMembershipRepository,
raceRepository as unknown as IRaceRepository,
output,
);
});
it('should present sponsor dashboard for existing sponsor', async () => {
const sponsorId = 'sponsor-1';
const sponsor = Sponsor.create({
id: sponsorId,
name: 'Test Sponsor',
contactEmail: 'test@example.com',
});
const sponsorship = SeasonSponsorship.create({
id: 'sponsorship-1',
sponsorId,
seasonId: 'season-1',
tier: 'main',
pricing: Money.create(10000, 'USD'),
});
const season = Season.create({
id: 'season-1',
leagueId: 'league-1',
gameId: 'game-1',
name: 'Season 1',
status: 'active',
});
const league = League.create({
id: 'league-1',
name: 'Test League',
description: 'Test',
ownerId: 'owner-1',
});
const memberships = [{ driverId: 'driver-1' }];
const races = [{ id: 'race-1', status: 'completed' }];
sponsorRepository.findById.mockResolvedValue(sponsor);
seasonSponsorshipRepository.findBySponsorId.mockResolvedValue([sponsorship]);
seasonRepository.findById.mockResolvedValue(season);
leagueRepository.findById.mockResolvedValue(league);
leagueMembershipRepository.getLeagueMembers.mockResolvedValue(memberships);
raceRepository.findByLeagueId.mockResolvedValue(races);
const input: GetSponsorDashboardInput = { sponsorId };
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
expect(result.unwrap()).toBeUndefined();
expect(output.present).toHaveBeenCalledTimes(1);
const dashboardRaw = (output.present as Mock).mock.calls[0]?.[0];
expect(dashboardRaw).toBeDefined();
const dashboard = dashboardRaw as GetSponsorDashboardResult;
expect(dashboard).toBeDefined();
expect(dashboard.sponsorId).toBe(sponsorId);
expect(dashboard.metrics.impressions).toBe(100); // 1 completed race * 1 driver * 100
expect(dashboard.investment.totalInvestment.amount).toBe(10000);
expect(dashboard.investment.totalInvestment.currency).toBe('USD');
});
it('should return error when sponsor does not exist', async () => {
const sponsorId = 'sponsor-1';
sponsorRepository.findById.mockResolvedValue(null);
const input: GetSponsorDashboardInput = { sponsorId };
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
GetSponsorDashboardErrorCode,
{ message: string }
>;
expect(error.code).toBe('SPONSOR_NOT_FOUND');
expect(error.details.message).toBe('Sponsor not found');
expect(output.present).not.toHaveBeenCalled();
});
it('should return error on repository failure', async () => {
const sponsorId = 'sponsor-1';
sponsorRepository.findById.mockRejectedValue(new Error('DB error'));
const input: GetSponsorDashboardInput = { sponsorId };
const result = await useCase.execute(input);
expect(result.isErr()).toBe(true);
const error = result.unwrapErr() as ApplicationErrorCode<
GetSponsorDashboardErrorCode,
{ message: string }
>;
expect(error.code).toBe('REPOSITORY_ERROR');
expect(error.details.message).toBe('DB error');
expect(output.present).not.toHaveBeenCalled();
});
});