code quality
Some checks failed
CI / lint-typecheck (pull_request) Failing after 12s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped

This commit is contained in:
2026-01-26 02:27:37 +01:00
parent bf2c0fdb0c
commit afef777961
23 changed files with 565 additions and 134 deletions

View File

@@ -1,13 +1,17 @@
/**
* Application Use Case Tests: CloseAdminVoteSessionUseCase
*
*
* Tests for closing admin vote sessions and generating rating events
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
import { CloseAdminVoteSessionUseCase } from './CloseAdminVoteSessionUseCase';
import { RatingEventFactory } from '../../domain/services/RatingEventFactory';
import { RatingSnapshotCalculator } from '../../domain/services/RatingSnapshotCalculator';
import { AdminVoteSessionRepository } from '../../domain/repositories/AdminVoteSessionRepository';
import { RatingEventRepository } from '../../domain/repositories/RatingEventRepository';
import { UserRatingRepository } from '../../domain/repositories/UserRatingRepository';
import { AdminVoteSession, AdminVoteOutcome } from '../../domain/entities/AdminVoteSession';
// Mock repositories
const createMockRepositories = () => ({
@@ -51,14 +55,14 @@ describe('CloseAdminVoteSessionUseCase', () => {
beforeEach(() => {
mockRepositories = createMockRepositories();
useCase = new CloseAdminVoteSessionUseCase(
mockRepositories.adminVoteSessionRepository,
mockRepositories.ratingEventRepository,
mockRepositories.userRatingRepository
mockRepositories.adminVoteSessionRepository as unknown as AdminVoteSessionRepository,
mockRepositories.ratingEventRepository as unknown as RatingEventRepository,
mockRepositories.userRatingRepository as unknown as UserRatingRepository
);
vi.clearAllMocks();
// Default mock for RatingEventFactory.createFromVote to return an empty array
// to avoid "events is not iterable" error in tests that don't explicitly mock it
(RatingEventFactory.createFromVote as any).mockReturnValue([]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([]);
});
describe('Input validation', () => {
@@ -84,7 +88,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should accept valid input', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -144,7 +157,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should find session by ID when provided', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -186,7 +208,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Admin ownership validation', () => {
it('should reject when admin does not own the session', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'different-admin',
startDate: new Date('2026-01-01'),
@@ -227,7 +258,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should accept when admin owns the session', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -269,7 +309,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Session closure validation', () => {
it('should reject when session is already closed', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -310,7 +359,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should accept when session is not closed', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -352,7 +410,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Voting window validation', () => {
it('should reject when trying to close outside voting window', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -388,7 +455,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
constructor() {
super('2026-02-02');
}
} as any;
} as unknown as typeof Date;
const result = await useCase.execute({
voteSessionId: 'session-123',
@@ -404,7 +471,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should accept when trying to close within voting window', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -440,7 +516,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
constructor() {
super('2026-01-15T12:00:00');
}
} as any;
} as unknown as typeof Date;
const result = await useCase.execute({
voteSessionId: 'session-123',
@@ -457,7 +533,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Session closure', () => {
it('should call close method on session', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -497,7 +582,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should save closed session', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -537,7 +631,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should return outcome in success response', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -585,7 +688,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Rating event creation', () => {
it('should create rating events when outcome is positive', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -616,7 +728,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
const mockEvent = { id: 'event-123' };
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
await useCase.execute({
voteSessionId: 'session-123',
@@ -635,7 +747,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should create rating events when outcome is negative', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -666,7 +787,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
const mockEvent = { id: 'event-123' };
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
await useCase.execute({
voteSessionId: 'session-123',
@@ -685,7 +806,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should not create rating events when outcome is tie', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -726,7 +856,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should save created rating events', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -758,7 +897,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
const mockEvent1 = { id: 'event-123' };
const mockEvent2 = { id: 'event-124' };
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent1, mockEvent2]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent1, mockEvent2]);
await useCase.execute({
voteSessionId: 'session-123',
@@ -772,7 +911,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should return eventsCreated count', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -804,7 +952,7 @@ describe('CloseAdminVoteSessionUseCase', () => {
const mockEvent1 = { id: 'event-123' };
const mockEvent2 = { id: 'event-124' };
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent1, mockEvent2]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent1, mockEvent2]);
const result = await useCase.execute({
voteSessionId: 'session-123',
@@ -818,7 +966,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Snapshot recalculation', () => {
it('should recalculate snapshot when events are created', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -849,13 +1006,13 @@ describe('CloseAdminVoteSessionUseCase', () => {
mockRepositories.adminVoteSessionRepository.findById.mockResolvedValue(mockSession);
const mockEvent = { id: 'event-123' };
(RatingEventFactory.createFromVote as any).mockReturnValue([mockEvent]);
(RatingEventFactory.createFromVote as unknown as Mock).mockReturnValue([mockEvent]);
const mockAllEvents = [{ id: 'event-1' }, { id: 'event-2' }];
mockRepositories.ratingEventRepository.getAllByUserId.mockResolvedValue(mockAllEvents);
const mockSnapshot = { userId: 'admin-123', overallReputation: 75 };
(RatingSnapshotCalculator.calculate as any).mockReturnValue(mockSnapshot);
(RatingSnapshotCalculator.calculate as unknown as Mock).mockReturnValue(mockSnapshot);
await useCase.execute({
voteSessionId: 'session-123',
@@ -869,7 +1026,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should not recalculate snapshot when no events are created (tie)', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -937,7 +1103,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
it('should handle save errors gracefully', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),
@@ -981,7 +1156,16 @@ describe('CloseAdminVoteSessionUseCase', () => {
describe('Return values', () => {
it('should return voteSessionId in success response', async () => {
const futureDate = new Date('2026-02-01');
const mockSession: any = {
const mockSession: {
id: string;
adminId: string;
startDate: Date;
endDate: Date;
_closed: boolean;
_outcome?: AdminVoteOutcome;
close: Mock;
closed: boolean;
} = {
id: 'session-123',
adminId: 'admin-123',
startDate: new Date('2026-01-01'),