Files
memegoat/backend/src/media/media.service.spec.ts
Mathis HERRIOT 514bd354bf feat: add modular services and repositories for improved code organization
Introduce repository pattern across multiple services, including `favorites`, `tags`, `sessions`, `reports`, `auth`, and more. Decouple crypto functionalities into modular services like `HashingService`, `JwtService`, and `EncryptionService`. Improve testability and maintainability by simplifying dependencies and consolidating utility logic.
2026-01-14 12:11:39 +01:00

100 lines
3.1 KiB
TypeScript

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>(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"));
});
});
});