import { Test, TestingModule } from '@nestjs/testing'; import { vi } from 'vitest'; import { MediaController } from './MediaController'; import { MediaService } from './MediaService'; import type { Response } from 'express'; import { RequestAvatarGenerationInputDTO } from './dtos/RequestAvatarGenerationInputDTO'; import { UploadMediaInputDTO } from './dtos/UploadMediaInputDTO'; import { RequestAvatarGenerationOutputDTO } from './dtos/RequestAvatarGenerationOutputDTO'; import { UploadMediaOutputDTO } from './dtos/UploadMediaOutputDTO'; import { GetMediaOutputDTO } from './dtos/GetMediaOutputDTO'; import { DeleteMediaOutputDTO } from './dtos/DeleteMediaOutputDTO'; import { GetAvatarOutputDTO } from './dtos/GetAvatarOutputDTO'; import { UpdateAvatarOutputDTO } from './dtos/UpdateAvatarOutputDTO'; import { UpdateAvatarInputDTO } from './dtos/UpdateAvatarInputDTO'; import type { MulterFile } from './types/MulterFile'; describe('MediaController', () => { let controller: MediaController; let service: MediaService & { requestAvatarGeneration: ReturnType; uploadMedia: ReturnType; getMedia: ReturnType; deleteMedia: ReturnType; getAvatar: ReturnType; updateAvatar: ReturnType; }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [MediaController], providers: [ { provide: MediaService, useValue: { requestAvatarGeneration: vi.fn(), uploadMedia: vi.fn(), getMedia: vi.fn(), deleteMedia: vi.fn(), getAvatar: vi.fn(), updateAvatar: vi.fn(), }, }, ], }).compile(); controller = module.get(MediaController); service = module.get(MediaService) as MediaService & { requestAvatarGeneration: ReturnType; uploadMedia: ReturnType; getMedia: ReturnType; deleteMedia: ReturnType; getAvatar: ReturnType; updateAvatar: ReturnType; }; }); const createMockResponse = (): Response => { const res: Partial = {}; res.status = vi.fn().mockReturnValue(res as Response); res.json = vi.fn().mockReturnValue(res as Response); return res as Response; }; describe('requestAvatarGeneration', () => { it('should request avatar generation and return 201 on success', async () => { const input: RequestAvatarGenerationInputDTO = { userId: 'user-123', facePhotoData: 'photo-data', suitColor: 'red', }; const dto: RequestAvatarGenerationOutputDTO = { success: true, requestId: 'req-123', avatarUrls: ['https://example.com/avatar.png'], }; service.requestAvatarGeneration.mockResolvedValue(dto); const res = createMockResponse(); await controller.requestAvatarGeneration(input, res); expect(service.requestAvatarGeneration).toHaveBeenCalledWith(input); expect(res.status).toHaveBeenCalledWith(201); expect(res.json).toHaveBeenCalledWith(dto); }); it('should return 400 on failure', async () => { const input: RequestAvatarGenerationInputDTO = { userId: 'user-123', facePhotoData: 'photo-data', suitColor: 'red', }; const dto: RequestAvatarGenerationOutputDTO = { success: false, errorMessage: 'Error', }; service.requestAvatarGeneration.mockResolvedValue(dto); const res = createMockResponse(); await controller.requestAvatarGeneration(input, res); expect(service.requestAvatarGeneration).toHaveBeenCalledWith(input); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith(dto); }); }); describe('uploadMedia', () => { it('should upload media and return 201 on success', async () => { const file: MulterFile = { filename: 'file.jpg' } as MulterFile; const input: UploadMediaInputDTO = { type: 'image' } as UploadMediaInputDTO; const dto: UploadMediaOutputDTO = { success: true, mediaId: 'media-123', url: 'https://example.com/file.jpg', }; service.uploadMedia.mockResolvedValue(dto); const res = createMockResponse(); await controller.uploadMedia(file, input, res); expect(service.uploadMedia).toHaveBeenCalledWith({ ...input, file }); expect(res.status).toHaveBeenCalledWith(201); expect(res.json).toHaveBeenCalledWith(dto); }); it('should return 400 when upload fails', async () => { const file: MulterFile = { filename: 'file.jpg' } as MulterFile; const input: UploadMediaInputDTO = { type: 'image' } as UploadMediaInputDTO; const dto: UploadMediaOutputDTO = { success: false, error: 'Upload failed', }; service.uploadMedia.mockResolvedValue(dto); const res = createMockResponse(); await controller.uploadMedia(file, input, res); expect(service.uploadMedia).toHaveBeenCalledWith({ ...input, file }); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith(dto); }); }); describe('getMedia', () => { it('should return media if found', async () => { const mediaId = 'media-123'; const dto: GetMediaOutputDTO = { id: mediaId, url: 'https://example.com/file.jpg', type: 'image', category: 'avatar', uploadedAt: new Date(), size: 123, }; service.getMedia.mockResolvedValue(dto); const res = createMockResponse(); await controller.getMedia(mediaId, res); expect(service.getMedia).toHaveBeenCalledWith(mediaId); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(dto); }); it('should return 404 if not found', async () => { const mediaId = 'media-123'; service.getMedia.mockResolvedValue(null); const res = createMockResponse(); await controller.getMedia(mediaId, res); expect(service.getMedia).toHaveBeenCalledWith(mediaId); expect(res.status).toHaveBeenCalledWith(404); expect(res.json).toHaveBeenCalledWith({ error: 'Media not found' }); }); }); describe('deleteMedia', () => { it('should delete media and return result', async () => { const mediaId = 'media-123'; const dto: DeleteMediaOutputDTO = { success: true, }; service.deleteMedia.mockResolvedValue(dto); const res = createMockResponse(); await controller.deleteMedia(mediaId, res); expect(service.deleteMedia).toHaveBeenCalledWith(mediaId); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(dto); }); }); describe('getAvatar', () => { it('should return avatar if found', async () => { const driverId = 'driver-123'; const dto: GetAvatarOutputDTO = { avatarUrl: 'https://example.com/avatar.png', }; service.getAvatar.mockResolvedValue(dto); const res = createMockResponse(); await controller.getAvatar(driverId, res); expect(service.getAvatar).toHaveBeenCalledWith(driverId); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(dto); }); it('should return 404 when avatar not found', async () => { const driverId = 'driver-123'; service.getAvatar.mockResolvedValue(null); const res = createMockResponse(); await controller.getAvatar(driverId, res); expect(service.getAvatar).toHaveBeenCalledWith(driverId); expect(res.status).toHaveBeenCalledWith(404); expect(res.json).toHaveBeenCalledWith({ error: 'Avatar not found' }); }); }); describe('updateAvatar', () => { it('should update avatar and return result', async () => { const driverId = 'driver-123'; const input: UpdateAvatarInputDTO = { driverId: 'driver-123', avatarUrl: 'https://example.com/new-avatar.png' }; const dto: UpdateAvatarOutputDTO = { success: true, }; service.updateAvatar.mockResolvedValue(dto); const res = createMockResponse(); await controller.updateAvatar(driverId, input, res); expect(service.updateAvatar).toHaveBeenCalledWith(driverId, input); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(dto); }); }); });