Files
memegoat/backend/src/media/media.service.spec.ts
Mathis HERRIOT df9a6c6f36 refactor: update test mocks to use addOutputOptions for consistency
- Replaced `outputOptions` with `addOutputOptions` in media service spec test to align with updated FFmpeg strategy.
2026-01-28 14:59:40 +01:00

133 lines
4.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(),
addOutputOptions: 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"));
});
});
describe("scanFile", () => {
it("should return false if clamav not initialized", async () => {
const result = await service.scanFile(Buffer.from(""), "test.txt");
expect(result.isInfected).toBe(false);
});
it("should handle virus detection", async () => {
// Mock private property to simulate initialized clamscan
(service as any).isClamAvInitialized = true;
(service as any).clamscan = {
scanStream: jest.fn().mockResolvedValue({
isInfected: true,
viruses: ["Eicar-Test-Signature"],
}),
};
const result = await service.scanFile(Buffer.from(""), "test.txt");
expect(result.isInfected).toBe(true);
expect(result.virusName).toBe("Eicar-Test-Signature");
});
it("should handle scan error", async () => {
(service as any).isClamAvInitialized = true;
(service as any).clamscan = {
scanStream: jest.fn().mockRejectedValue(new Error("Scan failed")),
};
await expect(
service.scanFile(Buffer.from(""), "test.txt"),
).rejects.toThrow();
});
});
});