resolve todos in website

This commit is contained in:
2025-12-20 12:55:07 +01:00
parent 20588e1c0b
commit 92be9d2e1b
56 changed files with 2476 additions and 78 deletions

View File

@@ -0,0 +1,97 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { DeleteMediaUseCase } from './DeleteMediaUseCase';
import type { IMediaRepository } from '../../domain/repositories/IMediaRepository';
import type { MediaStoragePort } from '../ports/MediaStoragePort';
import type { IDeleteMediaPresenter } from '../presenters/IDeleteMediaPresenter';
import type { Logger } from '@core/shared/application';
import { Media } from '../../domain/entities/Media';
import { MediaUrl } from '../../domain/value-objects/MediaUrl';
describe('DeleteMediaUseCase', () => {
let mediaRepo: {
findById: Mock;
delete: Mock;
};
let mediaStorage: {
deleteMedia: Mock;
};
let logger: Logger;
let presenter: IDeleteMediaPresenter & { result?: any };
let useCase: DeleteMediaUseCase;
beforeEach(() => {
mediaRepo = {
findById: vi.fn(),
delete: vi.fn(),
} as unknown as IMediaRepository as any;
mediaStorage = {
deleteMedia: vi.fn(),
} as unknown as MediaStoragePort as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
} as unknown as Logger;
presenter = {
present: vi.fn((result) => {
(presenter as any).result = result;
}),
} as unknown as IDeleteMediaPresenter & { result?: any };
useCase = new DeleteMediaUseCase(
mediaRepo as unknown as IMediaRepository,
mediaStorage as unknown as MediaStoragePort,
logger,
);
});
it('returns error result when media is not found', async () => {
mediaRepo.findById.mockResolvedValue(null);
await useCase.execute({ mediaId: 'missing' }, presenter);
expect(mediaRepo.findById).toHaveBeenCalledWith('missing');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Media not found',
});
});
it('deletes media from storage and repository on success', async () => {
const media = Media.create({
id: 'media-1',
filename: 'file.png',
originalName: 'file.png',
mimeType: 'image/png',
size: 123,
url: MediaUrl.create('https://example.com/file.png'),
type: 'image',
uploadedBy: 'user-1',
});
mediaRepo.findById.mockResolvedValue(media);
await useCase.execute({ mediaId: 'media-1' }, presenter);
expect(mediaRepo.findById).toHaveBeenCalledWith('media-1');
expect(mediaStorage.deleteMedia).toHaveBeenCalledWith(media.url.value);
expect(mediaRepo.delete).toHaveBeenCalledWith('media-1');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({ success: true });
});
it('handles errors and presents failure result', async () => {
mediaRepo.findById.mockRejectedValue(new Error('DB error'));
await useCase.execute({ mediaId: 'media-1' }, presenter);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Internal error occurred while deleting media',
});
});
});

View File

@@ -0,0 +1,93 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetAvatarUseCase } from './GetAvatarUseCase';
import type { IAvatarRepository } from '../../domain/repositories/IAvatarRepository';
import type { IGetAvatarPresenter } from '../presenters/IGetAvatarPresenter';
import type { Logger } from '@core/shared/application';
import { Avatar } from '../../domain/entities/Avatar';
import { MediaUrl } from '../../domain/value-objects/MediaUrl';
interface TestPresenter extends IGetAvatarPresenter {
result?: any;
}
describe('GetAvatarUseCase', () => {
let avatarRepo: {
findActiveByDriverId: Mock;
save: Mock;
};
let logger: Logger;
let presenter: TestPresenter;
let useCase: GetAvatarUseCase;
beforeEach(() => {
avatarRepo = {
findActiveByDriverId: vi.fn(),
save: vi.fn(),
} as unknown as IAvatarRepository as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
} as unknown as Logger;
presenter = {
present: vi.fn((result) => {
presenter.result = result;
}),
} as unknown as TestPresenter;
useCase = new GetAvatarUseCase(
avatarRepo as unknown as IAvatarRepository,
logger,
);
});
it('presents error when no avatar exists for driver', async () => {
avatarRepo.findActiveByDriverId.mockResolvedValue(null);
await useCase.execute({ driverId: 'driver-1' }, presenter);
expect(avatarRepo.findActiveByDriverId).toHaveBeenCalledWith('driver-1');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Avatar not found',
});
});
it('presents avatar details when avatar exists', async () => {
const avatar = Avatar.create({
id: 'avatar-1',
driverId: 'driver-1',
mediaUrl: MediaUrl.create('https://example.com/avatar.png'),
});
avatarRepo.findActiveByDriverId.mockResolvedValue(avatar);
await useCase.execute({ driverId: 'driver-1' }, presenter);
expect(avatarRepo.findActiveByDriverId).toHaveBeenCalledWith('driver-1');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: true,
avatar: {
id: avatar.id,
driverId: avatar.driverId,
mediaUrl: avatar.mediaUrl.value,
selectedAt: avatar.selectedAt,
},
});
});
it('handles errors by logging and presenting failure', async () => {
avatarRepo.findActiveByDriverId.mockRejectedValue(new Error('DB error'));
await useCase.execute({ driverId: 'driver-1' }, presenter);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Internal error occurred while retrieving avatar',
});
});
});

View File

@@ -0,0 +1,102 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetMediaUseCase } from './GetMediaUseCase';
import type { IMediaRepository } from '../../domain/repositories/IMediaRepository';
import type { IGetMediaPresenter } from '../presenters/IGetMediaPresenter';
import type { Logger } from '@core/shared/application';
import { Media } from '../../domain/entities/Media';
import { MediaUrl } from '../../domain/value-objects/MediaUrl';
interface TestPresenter extends IGetMediaPresenter {
result?: any;
}
describe('GetMediaUseCase', () => {
let mediaRepo: {
findById: Mock;
};
let logger: Logger;
let presenter: TestPresenter;
let useCase: GetMediaUseCase;
beforeEach(() => {
mediaRepo = {
findById: vi.fn(),
} as unknown as IMediaRepository as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
} as unknown as Logger;
presenter = {
present: vi.fn((result) => {
presenter.result = result;
}),
} as unknown as TestPresenter;
useCase = new GetMediaUseCase(
mediaRepo as unknown as IMediaRepository,
logger,
);
});
it('presents error when media is not found', async () => {
mediaRepo.findById.mockResolvedValue(null);
await useCase.execute({ mediaId: 'missing' }, presenter);
expect(mediaRepo.findById).toHaveBeenCalledWith('missing');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Media not found',
});
});
it('presents media details when media exists', async () => {
const media = Media.create({
id: 'media-1',
filename: 'file.png',
originalName: 'file.png',
mimeType: 'image/png',
size: 123,
url: MediaUrl.create('https://example.com/file.png'),
type: 'image',
uploadedBy: 'user-1',
});
mediaRepo.findById.mockResolvedValue(media);
await useCase.execute({ mediaId: 'media-1' }, presenter);
expect(mediaRepo.findById).toHaveBeenCalledWith('media-1');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: true,
media: {
id: media.id,
filename: media.filename,
originalName: media.originalName,
mimeType: media.mimeType,
size: media.size,
url: media.url.value,
type: media.type,
uploadedBy: media.uploadedBy,
uploadedAt: media.uploadedAt,
metadata: media.metadata,
},
});
});
it('handles errors by logging and presenting failure', async () => {
mediaRepo.findById.mockRejectedValue(new Error('DB error'));
await useCase.execute({ mediaId: 'media-1' }, presenter);
expect((logger.error as unknown as Mock)).toHaveBeenCalled();
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Internal error occurred while retrieving media',
});
});
});

View File

@@ -0,0 +1,126 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { RequestAvatarGenerationUseCase } from './RequestAvatarGenerationUseCase';
import type { IAvatarGenerationRepository } from '../../domain/repositories/IAvatarGenerationRepository';
import type { FaceValidationPort } from '../ports/FaceValidationPort';
import type { AvatarGenerationPort } from '../ports/AvatarGenerationPort';
import type { Logger } from '@core/shared/application';
import { AvatarGenerationRequest } from '../../domain/entities/AvatarGenerationRequest';
import type { RequestAvatarGenerationInput } from './RequestAvatarGenerationUseCase';
describe('RequestAvatarGenerationUseCase', () => {
let avatarRepo: {
save: Mock;
findById: Mock;
};
let faceValidation: {
validateFacePhoto: Mock;
};
let avatarGeneration: {
generateAvatars: Mock;
};
let logger: Logger;
let useCase: RequestAvatarGenerationUseCase;
beforeEach(() => {
avatarRepo = {
save: vi.fn(),
findById: vi.fn(),
} as unknown as IAvatarGenerationRepository as any;
faceValidation = {
validateFacePhoto: vi.fn(),
} as unknown as FaceValidationPort as any;
avatarGeneration = {
generateAvatars: vi.fn(),
} as unknown as AvatarGenerationPort as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
} as unknown as Logger;
useCase = new RequestAvatarGenerationUseCase(
avatarRepo as unknown as IAvatarGenerationRepository,
faceValidation as unknown as FaceValidationPort,
avatarGeneration as unknown as AvatarGenerationPort,
logger,
);
});
const createPresenter = () => {
const presenter: { present: Mock; result?: any } = {
present: vi.fn((result) => {
presenter.result = result;
}),
result: undefined,
};
return presenter;
};
it('fails when face validation fails', async () => {
const input: RequestAvatarGenerationInput = {
userId: 'user-1',
facePhotoData: 'photo-data',
suitColor: 'red',
style: 'realistic',
};
const presenter = createPresenter();
faceValidation.validateFacePhoto.mockResolvedValue({
isValid: false,
hasFace: false,
faceCount: 0,
errorMessage: 'No face detected',
});
await useCase.execute(input, presenter as any);
expect((presenter.present as Mock)).toHaveBeenCalledWith({
requestId: expect.any(String),
status: 'failed',
errorMessage: 'No face detected',
});
});
it('completes request and returns avatar URLs on success', async () => {
const input: RequestAvatarGenerationInput = {
userId: 'user-1',
facePhotoData: 'photo-data',
suitColor: 'red',
style: 'realistic',
};
const presenter = createPresenter();
faceValidation.validateFacePhoto.mockResolvedValue({
isValid: true,
hasFace: true,
faceCount: 1,
});
avatarGeneration.generateAvatars.mockResolvedValue({
success: true,
avatars: [
{ url: 'https://example.com/avatar1.png' },
{ url: 'https://example.com/avatar2.png' },
],
});
await useCase.execute(input, presenter as any);
expect(faceValidation.validateFacePhoto).toHaveBeenCalled();
expect(avatarGeneration.generateAvatars).toHaveBeenCalled();
expect((presenter.present as Mock)).toHaveBeenCalledWith({
requestId: expect.any(String),
status: 'completed',
avatarUrls: [
'https://example.com/avatar1.png',
'https://example.com/avatar2.png',
],
});
});
});

View File

@@ -0,0 +1,76 @@
import { describe, it, expect, vi, type Mock } from 'vitest';
import { SelectAvatarUseCase } from './SelectAvatarUseCase';
import type { IAvatarGenerationRepository } from '../../domain/repositories/IAvatarGenerationRepository';
import type { ISelectAvatarPresenter } from '../presenters/ISelectAvatarPresenter';
import type { Logger } from '@core/shared/application';
import { AvatarGenerationRequest } from '../../domain/entities/AvatarGenerationRequest';
interface TestPresenter extends ISelectAvatarPresenter {
result?: any;
}
describe('SelectAvatarUseCase', () => {
let avatarRepo: {
findById: Mock;
save: Mock;
};
let logger: Logger;
let presenter: TestPresenter;
let useCase: SelectAvatarUseCase;
beforeEach(() => {
avatarRepo = {
findById: vi.fn(),
save: vi.fn(),
} as unknown as IAvatarGenerationRepository as any;
logger = {
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
} as unknown as Logger;
presenter = {
present: vi.fn((result) => {
presenter.result = result;
}),
} as unknown as TestPresenter;
useCase = new SelectAvatarUseCase(
avatarRepo as unknown as IAvatarGenerationRepository,
logger,
);
});
it('returns error when request is not found', async () => {
avatarRepo.findById.mockResolvedValue(null);
await useCase.execute({ requestId: 'req-1', selectedIndex: 0 }, presenter);
expect(avatarRepo.findById).toHaveBeenCalledWith('req-1');
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Avatar generation request not found',
});
});
it('returns error when request is not completed', async () => {
const request = AvatarGenerationRequest.create({
id: 'req-1',
userId: 'user-1',
facePhotoUrl: 'photo',
suitColor: 'red',
style: 'realistic',
});
avatarRepo.findById.mockResolvedValue(request);
await useCase.execute({ requestId: 'req-1', selectedIndex: 0 }, presenter);
expect((presenter.present as unknown as Mock)).toHaveBeenCalledWith({
success: false,
errorMessage: 'Avatar generation is not completed yet',
});
});
});