Files
memegoat/backend/src/contents/contents.service.spec.ts

177 lines
5.3 KiB
TypeScript

jest.mock("uuid", () => ({
v4: jest.fn(() => "mocked-uuid"),
}));
import { BadRequestException } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Test, TestingModule } from "@nestjs/testing";
import { DatabaseService } from "../database/database.service";
import { MediaService } from "../media/media.service";
import { S3Service } from "../s3/s3.service";
import { ContentsService } from "./contents.service";
describe("ContentsService", () => {
let service: ContentsService;
let s3Service: S3Service;
let mediaService: MediaService;
const mockDb = {
select: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
limit: jest.fn().mockReturnThis(),
offset: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
innerJoin: jest.fn().mockReturnThis(),
insert: jest.fn().mockReturnThis(),
values: jest.fn().mockReturnThis(),
update: jest.fn().mockReturnThis(),
set: jest.fn().mockReturnThis(),
returning: jest.fn().mockResolvedValue([]),
onConflictDoNothing: jest.fn().mockReturnThis(),
transaction: jest.fn().mockImplementation((cb) => cb(mockDb)),
execute: jest.fn().mockResolvedValue([]),
};
const mockS3Service = {
getUploadUrl: jest.fn(),
uploadFile: jest.fn(),
};
const mockMediaService = {
scanFile: jest.fn(),
processImage: jest.fn(),
processVideo: jest.fn(),
};
const mockConfigService = {
get: jest.fn(),
};
beforeEach(async () => {
jest.clearAllMocks();
const chain = {
select: jest.fn().mockReturnThis(),
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
limit: jest.fn().mockReturnThis(),
offset: jest.fn().mockReturnThis(),
innerJoin: jest.fn().mockReturnThis(),
insert: jest.fn().mockReturnThis(),
values: jest.fn().mockReturnThis(),
update: jest.fn().mockReturnThis(),
set: jest.fn().mockReturnThis(),
returning: jest.fn().mockReturnThis(),
onConflictDoNothing: jest.fn().mockReturnThis(),
};
const mockImplementation = () => {
return Object.assign(Promise.resolve([]), chain);
};
for (const mock of Object.values(chain)) {
//TODO Fix : TS2774: This condition will always return true since this function is always defined. Did you mean to call it instead?
if (mock.mockReturnValue) {
mock.mockImplementation(mockImplementation);
}
}
Object.assign(mockDb, chain);
const module: TestingModule = await Test.createTestingModule({
providers: [
ContentsService,
{ provide: DatabaseService, useValue: { db: mockDb } },
{ provide: S3Service, useValue: mockS3Service },
{ provide: MediaService, useValue: mockMediaService },
{ provide: ConfigService, useValue: mockConfigService },
],
}).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,
});
mockDb.returning.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 () => {
mockDb.where.mockResolvedValueOnce([{ count: 10 }]); // for count
mockDb.offset.mockResolvedValueOnce([{ id: "1" }]); // for data
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 () => {
mockDb.returning.mockResolvedValue([{ id: "1", views: 1 }]);
const result = await service.incrementViews("1");
expect(mockDb.update).toHaveBeenCalled();
expect(result[0].views).toBe(1);
});
});
});