refactor use cases

This commit is contained in:
2026-01-08 15:34:51 +01:00
parent d984ab24a8
commit 52e9a2f6a7
362 changed files with 5192 additions and 8409 deletions

View File

@@ -1,127 +1,98 @@
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { describe, it, expect, vi, type Mock } from 'vitest';
import { UpsertMembershipFeeUseCase, type UpsertMembershipFeeInput } from './UpsertMembershipFeeUseCase';
import type { IMembershipFeeRepository } from '../../domain/repositories/IMembershipFeeRepository';
import { MembershipFeeType, type MembershipFee } from '../../domain/entities/MembershipFee';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import { MembershipFeeType } from '../../domain/entities/MembershipFee';
describe('UpsertMembershipFeeUseCase', () => {
let membershipFeeRepository: {
findByLeagueId: Mock;
create: Mock;
update: Mock;
create: Mock;
};
let output: {
present: Mock;
};
let useCase: UpsertMembershipFeeUseCase;
beforeEach(() => {
membershipFeeRepository = {
findByLeagueId: vi.fn(),
create: vi.fn(),
update: vi.fn(),
};
output = {
present: vi.fn(),
create: vi.fn(),
};
useCase = new UpsertMembershipFeeUseCase(
membershipFeeRepository as unknown as IMembershipFeeRepository,
output as unknown as UseCaseOutputPort<unknown>,
);
});
it('creates a fee when none exists and presents it', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-01T00:00:00.000Z'));
vi.spyOn(Math, 'random').mockReturnValue(0.123456789);
it('updates existing membership fee and returns result', async () => {
const input: UpsertMembershipFeeInput = {
leagueId: 'league-1',
seasonId: 'season-1',
type: MembershipFeeType.MONTHLY,
amount: 50,
};
try {
const input: UpsertMembershipFeeInput = {
leagueId: 'league-1',
type: MembershipFeeType.SEASON,
amount: 100,
};
const existingFee = {
id: 'fee-1',
leagueId: 'league-1',
type: MembershipFeeType.YEARLY,
amount: 100,
enabled: true,
createdAt: new Date(),
updatedAt: new Date(),
};
membershipFeeRepository.findByLeagueId.mockResolvedValue(null);
membershipFeeRepository.create.mockImplementation(async (fee: MembershipFee) => ({ ...fee }));
const updatedFee = {
...existingFee,
type: MembershipFeeType.MONTHLY,
amount: 50,
seasonId: 'season-1',
enabled: true,
updatedAt: new Date(),
};
const result = await useCase.execute(input);
membershipFeeRepository.findByLeagueId.mockResolvedValue(existingFee);
membershipFeeRepository.update.mockResolvedValue(updatedFee);
expect(result.isOk()).toBe(true);
const result = await useCase.execute(input);
expect(membershipFeeRepository.create).toHaveBeenCalledWith(
expect.objectContaining({
id: expect.stringMatching(/^fee-1735689600000-[a-z0-9]{9}$/),
leagueId: 'league-1',
type: MembershipFeeType.SEASON,
amount: 100,
enabled: true,
createdAt: new Date('2025-01-01T00:00:00.000Z'),
updatedAt: new Date('2025-01-01T00:00:00.000Z'),
}),
);
const createdFee = (output.present.mock.calls[0]?.[0] as { fee: MembershipFee }).fee;
expect(createdFee.enabled).toBe(true);
expect(createdFee.amount).toBe(100);
} finally {
vi.useRealTimers();
expect(result.isOk()).toBe(true);
expect(membershipFeeRepository.findByLeagueId).toHaveBeenCalledWith('league-1');
expect(membershipFeeRepository.update).toHaveBeenCalled();
if (result.isOk()) {
expect(result.value.fee).toEqual(updatedFee);
}
});
it('updates an existing fee and sets enabled=false when amount is 0', async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-02T00:00:00.000Z'));
it('creates new membership fee and returns result', async () => {
const input: UpsertMembershipFeeInput = {
leagueId: 'league-1',
type: MembershipFeeType.MONTHLY,
amount: 50,
};
try {
const input: UpsertMembershipFeeInput = {
leagueId: 'league-1',
seasonId: 'season-2',
type: MembershipFeeType.MONTHLY,
amount: 0,
};
membershipFeeRepository.findByLeagueId.mockResolvedValue(null);
const existingFee: MembershipFee = {
id: 'fee-1',
leagueId: 'league-1',
seasonId: 'season-1',
type: MembershipFeeType.SEASON,
amount: 100,
enabled: true,
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-01T00:00:00.000Z'),
};
const createdFee = {
id: 'fee-new',
leagueId: 'league-1',
type: MembershipFeeType.MONTHLY,
amount: 50,
enabled: true,
createdAt: new Date(),
updatedAt: new Date(),
};
membershipFeeRepository.findByLeagueId.mockResolvedValue(existingFee);
membershipFeeRepository.update.mockImplementation(async (fee: MembershipFee) => ({ ...fee }));
membershipFeeRepository.create.mockResolvedValue(createdFee);
const result = await useCase.execute(input);
const result = await useCase.execute(input);
expect(result.isOk()).toBe(true);
expect(membershipFeeRepository.update).toHaveBeenCalledWith(
expect.objectContaining({
id: 'fee-1',
leagueId: 'league-1',
seasonId: 'season-2',
type: MembershipFeeType.MONTHLY,
amount: 0,
enabled: false,
updatedAt: new Date('2025-01-02T00:00:00.000Z'),
}),
);
const updatedFee = (output.present.mock.calls[0]?.[0] as { fee: MembershipFee }).fee;
expect(updatedFee.enabled).toBe(false);
expect(updatedFee.amount).toBe(0);
expect(updatedFee.seasonId).toBe('season-2');
expect(updatedFee.type).toBe(MembershipFeeType.MONTHLY);
} finally {
vi.useRealTimers();
expect(result.isOk()).toBe(true);
expect(membershipFeeRepository.findByLeagueId).toHaveBeenCalledWith('league-1');
expect(membershipFeeRepository.create).toHaveBeenCalled();
if (result.isOk()) {
expect(result.value.fee).toEqual(createdFee);
}
});
});