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); s3Service = module.get(S3Service); mediaService = module.get(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); }); }); });