import * as fs from "node:fs/promises"; import { BadRequestException, Logger } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { Test, TestingModule } from "@nestjs/testing"; import ffmpeg from "fluent-ffmpeg"; import sharp from "sharp"; import { MediaService } from "./media.service"; import { ImageProcessorStrategy } from "./strategies/image-processor.strategy"; import { VideoProcessorStrategy } from "./strategies/video-processor.strategy"; jest.mock("sharp"); jest.mock("fluent-ffmpeg"); jest.mock("node:fs/promises"); jest.mock("uuid", () => ({ v4: () => "mock-uuid" })); describe("MediaService", () => { let service: MediaService; const mockSharp = { metadata: jest.fn().mockResolvedValue({ width: 100, height: 100 }), webp: jest.fn().mockReturnThis(), toBuffer: jest.fn().mockResolvedValue(Buffer.from("processed")), }; beforeEach(async () => { jest.clearAllMocks(); jest.spyOn(Logger.prototype, "error").mockImplementation(() => {}); jest.spyOn(Logger.prototype, "warn").mockImplementation(() => {}); (sharp as unknown as jest.Mock).mockReturnValue(mockSharp); const module: TestingModule = await Test.createTestingModule({ providers: [ MediaService, ImageProcessorStrategy, VideoProcessorStrategy, { provide: ConfigService, useValue: { get: jest.fn((key) => { if (key === "CLAMAV_HOST") return "localhost"; if (key === "CLAMAV_PORT") return 3310; }), }, }, ], }).compile(); service = module.get(MediaService); }); it("should be defined", () => { expect(service).toBeDefined(); }); describe("processImage", () => { it("should process an image to webp", async () => { const result = await service.processImage(Buffer.from("input"), "webp"); expect(result.extension).toBe("webp"); expect(result.buffer).toEqual(Buffer.from("processed")); expect(mockSharp.webp).toHaveBeenCalled(); }); it("should throw BadRequestException on error", async () => { mockSharp.toBuffer.mockRejectedValue(new Error("Sharp error")); await expect(service.processImage(Buffer.from("input"))).rejects.toThrow( BadRequestException, ); }); }); describe("processVideo", () => { it("should process a video", async () => { const mockFfmpegCommand = { toFormat: jest.fn().mockReturnThis(), videoCodec: jest.fn().mockReturnThis(), audioCodec: jest.fn().mockReturnThis(), outputOptions: jest.fn().mockReturnThis(), on: jest.fn().mockImplementation(function (event, cb) { if (event === "end") setTimeout(cb, 0); return this; }), save: jest.fn().mockReturnThis(), }; (ffmpeg as unknown as jest.Mock).mockReturnValue(mockFfmpegCommand); (fs.readFile as jest.Mock).mockResolvedValue(Buffer.from("processed-video")); (fs.writeFile as jest.Mock).mockResolvedValue(undefined); (fs.unlink as jest.Mock).mockResolvedValue(undefined); const result = await service.processVideo( Buffer.from("video-input"), "webm", ); expect(result.extension).toBe("webm"); expect(result.buffer).toEqual(Buffer.from("processed-video")); }); }); });