From 05a56ff87d37763a2fef72b3a973f884ff3e3be2 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:46:06 +0100 Subject: [PATCH] test(categories): add unit tests for CategoriesController and CategoriesRepository with mocked dependencies --- .../categories/categories.controller.spec.ts | 105 ++++++++++++++++++ .../categories.repository.spec.ts | 78 +++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 backend/src/categories/categories.controller.spec.ts create mode 100644 backend/src/categories/repositories/categories.repository.spec.ts diff --git a/backend/src/categories/categories.controller.spec.ts b/backend/src/categories/categories.controller.spec.ts new file mode 100644 index 0000000..f646a07 --- /dev/null +++ b/backend/src/categories/categories.controller.spec.ts @@ -0,0 +1,105 @@ +jest.mock("uuid", () => ({ + v4: jest.fn(() => "mocked-uuid"), +})); + +jest.mock("@noble/post-quantum/ml-kem.js", () => ({ + ml_kem768: { + keygen: jest.fn(), + encapsulate: jest.fn(), + decapsulate: jest.fn(), + }, +})); + +jest.mock("jose", () => ({ + SignJWT: jest.fn().mockReturnValue({ + setProtectedHeader: jest.fn().mockReturnThis(), + setIssuedAt: jest.fn().mockReturnThis(), + setExpirationTime: jest.fn().mockReturnThis(), + sign: jest.fn().mockResolvedValue("mocked-jwt"), + }), + jwtVerify: jest.fn(), +})); + +import { CACHE_MANAGER } from "@nestjs/cache-manager"; +import { Test, TestingModule } from "@nestjs/testing"; +import { AuthGuard } from "../auth/guards/auth.guard"; +import { RolesGuard } from "../auth/guards/roles.guard"; +import { CategoriesController } from "./categories.controller"; +import { CategoriesService } from "./categories.service"; + +describe("CategoriesController", () => { + let controller: CategoriesController; + let service: CategoriesService; + + const mockCategoriesService = { + findAll: jest.fn(), + findOne: jest.fn(), + create: jest.fn(), + update: jest.fn(), + remove: jest.fn(), + }; + + const mockCacheManager = { + get: jest.fn(), + set: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [CategoriesController], + providers: [ + { provide: CategoriesService, useValue: mockCategoriesService }, + { provide: CACHE_MANAGER, useValue: mockCacheManager }, + ], + }) + .overrideGuard(AuthGuard) + .useValue({ canActivate: () => true }) + .overrideGuard(RolesGuard) + .useValue({ canActivate: () => true }) + .compile(); + + controller = module.get(CategoriesController); + service = module.get(CategoriesService); + }); + + it("should be defined", () => { + expect(controller).toBeDefined(); + }); + + describe("findAll", () => { + it("should call service.findAll", async () => { + await controller.findAll(); + expect(service.findAll).toHaveBeenCalled(); + }); + }); + + describe("findOne", () => { + it("should call service.findOne", async () => { + await controller.findOne("1"); + expect(service.findOne).toHaveBeenCalledWith("1"); + }); + }); + + describe("create", () => { + it("should call service.create", async () => { + const dto = { name: "Cat", slug: "cat" }; + await controller.create(dto); + expect(service.create).toHaveBeenCalledWith(dto); + }); + }); + + describe("update", () => { + it("should call service.update", async () => { + const dto = { name: "New Name" }; + await controller.update("1", dto); + expect(service.update).toHaveBeenCalledWith("1", dto); + }); + }); + + describe("remove", () => { + it("should call service.remove", async () => { + await controller.remove("1"); + expect(service.remove).toHaveBeenCalledWith("1"); + }); + }); +}); diff --git a/backend/src/categories/repositories/categories.repository.spec.ts b/backend/src/categories/repositories/categories.repository.spec.ts new file mode 100644 index 0000000..a89b1b5 --- /dev/null +++ b/backend/src/categories/repositories/categories.repository.spec.ts @@ -0,0 +1,78 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { DatabaseService } from "../../database/database.service"; +import { CategoriesRepository } from "./categories.repository"; + +describe("CategoriesRepository", () => { + let repository: CategoriesRepository; + + const mockDb = { + select: jest.fn().mockReturnThis(), + from: jest.fn().mockReturnThis(), + orderBy: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + limit: jest.fn().mockReturnThis(), + insert: jest.fn().mockReturnThis(), + values: jest.fn().mockReturnThis(), + update: jest.fn().mockReturnThis(), + set: jest.fn().mockReturnThis(), + delete: jest.fn().mockReturnThis(), + returning: jest.fn().mockReturnThis(), + execute: jest.fn(), + }; + + const wrapWithThen = (obj: any) => { + obj.then = function (onFulfilled: any) { + const result = this.execute(); + return Promise.resolve(result).then(onFulfilled); + }; + return obj; + }; + wrapWithThen(mockDb); + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + CategoriesRepository, + { provide: DatabaseService, useValue: { db: mockDb } }, + ], + }).compile(); + + repository = module.get(CategoriesRepository); + }); + + it("should find all", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]); + const result = await repository.findAll(); + expect(result).toHaveLength(1); + }); + + it("should count all", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ count: 5 }]); + const result = await repository.countAll(); + expect(result).toBe(5); + }); + + it("should find one", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]); + const result = await repository.findOne("1"); + expect(result.id).toBe("1"); + }); + + it("should create", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]); + await repository.create({ name: "C", slug: "s" }); + expect(mockDb.insert).toHaveBeenCalled(); + }); + + it("should update", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]); + await repository.update("1", { name: "N", updatedAt: new Date() }); + expect(mockDb.update).toHaveBeenCalled(); + }); + + it("should remove", async () => { + (mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]); + await repository.remove("1"); + expect(mockDb.delete).toHaveBeenCalled(); + }); +});