Files
memegoat/backend/src/contents/contents.service.spec.ts
Mathis HERRIOT 38adbb6e77 feat(media): add public URL generation for media files and improve S3 integration
Introduce `getPublicUrl` in `S3Service` for generating public URLs. Replace custom file URL generation logic across services with the new method. Add media controller for file streaming and update related tests. Adjust frontend to display user roles instead of email in the sidebar. Update environment schema to include optional `API_URL`. Fix help page contact email.
2026-01-14 23:13:28 +01:00

151 lines
4.3 KiB
TypeScript

jest.mock("uuid", () => ({
v4: jest.fn(() => "mocked-uuid"),
}));
import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { BadRequestException } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Test, TestingModule } from "@nestjs/testing";
import { MediaService } from "../media/media.service";
import { S3Service } from "../s3/s3.service";
import { ContentsService } from "./contents.service";
import { ContentsRepository } from "./repositories/contents.repository";
describe("ContentsService", () => {
let service: ContentsService;
let s3Service: S3Service;
let mediaService: MediaService;
const mockContentsRepository = {
findAll: jest.fn(),
count: jest.fn(),
create: jest.fn(),
incrementViews: jest.fn(),
incrementUsage: jest.fn(),
softDelete: jest.fn(),
findOne: jest.fn(),
findBySlug: jest.fn(),
};
const mockS3Service = {
getUploadUrl: jest.fn(),
uploadFile: jest.fn(),
getPublicUrl: jest.fn(),
};
const mockMediaService = {
scanFile: jest.fn(),
processImage: jest.fn(),
processVideo: jest.fn(),
};
const mockConfigService = {
get: jest.fn(),
};
const mockCacheManager = {
clear: jest.fn(),
del: jest.fn(),
};
beforeEach(async () => {
jest.clearAllMocks();
const module: TestingModule = await Test.createTestingModule({
providers: [
ContentsService,
{ provide: ContentsRepository, useValue: mockContentsRepository },
{ provide: S3Service, useValue: mockS3Service },
{ provide: MediaService, useValue: mockMediaService },
{ provide: ConfigService, useValue: mockConfigService },
{ provide: CACHE_MANAGER, useValue: mockCacheManager },
],
}).compile();
service = module.get<ContentsService>(ContentsService);
s3Service = module.get<S3Service>(S3Service);
mediaService = module.get<MediaService>(MediaService);
});
it("should be defined", () => {
expect(service).toBeDefined();
});
describe("getUploadUrl", () => {
it("should return an upload URL", async () => {
mockS3Service.getUploadUrl.mockResolvedValue("http://s3/url");
const result = await service.getUploadUrl("user1", "test.png");
expect(result).toHaveProperty("url", "http://s3/url");
expect(result).toHaveProperty("key");
expect(result.key).toContain("uploads/user1/");
});
});
describe("uploadAndProcess", () => {
const file = {
buffer: Buffer.from("test"),
originalname: "test.png",
mimetype: "image/png",
size: 1000,
} as Express.Multer.File;
it("should upload and process an image", async () => {
mockConfigService.get.mockReturnValue(1024); // max size
mockMediaService.scanFile.mockResolvedValue({ isInfected: false });
mockMediaService.processImage.mockResolvedValue({
buffer: Buffer.from("processed"),
extension: "webp",
mimeType: "image/webp",
size: 500,
});
mockContentsRepository.findBySlug.mockResolvedValue(null);
mockContentsRepository.create.mockResolvedValue({ id: "content-id" });
const result = await service.uploadAndProcess("user1", file, {
title: "Meme",
type: "meme",
});
expect(mediaService.scanFile).toHaveBeenCalled();
expect(mediaService.processImage).toHaveBeenCalled();
expect(s3Service.uploadFile).toHaveBeenCalled();
expect(result).toEqual({ id: "content-id" });
});
it("should throw if file is infected", async () => {
mockConfigService.get.mockReturnValue(1024);
mockMediaService.scanFile.mockResolvedValue({
isInfected: true,
virusName: "Eicar",
});
await expect(
service.uploadAndProcess("user1", file, { title: "X", type: "meme" }),
).rejects.toThrow(BadRequestException);
});
});
describe("findAll", () => {
it("should return contents and total count", async () => {
mockContentsRepository.count.mockResolvedValue(10);
mockContentsRepository.findAll.mockResolvedValue([{ id: "1" }]);
const result = await service.findAll({ limit: 10, offset: 0 });
expect(result.totalCount).toBe(10);
expect(result.data).toHaveLength(1);
});
});
describe("incrementViews", () => {
it("should increment views", async () => {
mockContentsRepository.incrementViews.mockResolvedValue([
{ id: "1", views: 1 },
]);
const result = await service.incrementViews("1");
expect(mockContentsRepository.incrementViews).toHaveBeenCalledWith("1");
expect(result[0].views).toBe(1);
});
});
});