test(api-keys): add unit tests for ApiKeysController and ApiKeysRepository with mocked dependencies
This commit is contained in:
95
backend/src/api-keys/api-keys.controller.spec.ts
Normal file
95
backend/src/api-keys/api-keys.controller.spec.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
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 { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||||
|
import { AuthenticatedRequest } from "../common/interfaces/request.interface";
|
||||||
|
import { ApiKeysController } from "./api-keys.controller";
|
||||||
|
import { ApiKeysService } from "./api-keys.service";
|
||||||
|
|
||||||
|
describe("ApiKeysController", () => {
|
||||||
|
let controller: ApiKeysController;
|
||||||
|
let service: ApiKeysService;
|
||||||
|
|
||||||
|
const mockApiKeysService = {
|
||||||
|
create: jest.fn(),
|
||||||
|
findAll: jest.fn(),
|
||||||
|
revoke: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [ApiKeysController],
|
||||||
|
providers: [{ provide: ApiKeysService, useValue: mockApiKeysService }],
|
||||||
|
})
|
||||||
|
.overrideGuard(AuthGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<ApiKeysController>(ApiKeysController);
|
||||||
|
service = module.get<ApiKeysService>(ApiKeysService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be defined", () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("create", () => {
|
||||||
|
it("should call service.create", async () => {
|
||||||
|
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||||
|
const dto = { name: "Key Name", expiresAt: "2026-01-20T12:00:00Z" };
|
||||||
|
await controller.create(req, dto);
|
||||||
|
expect(service.create).toHaveBeenCalledWith(
|
||||||
|
"user-uuid",
|
||||||
|
"Key Name",
|
||||||
|
new Date(dto.expiresAt),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call service.create without expiresAt", async () => {
|
||||||
|
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||||
|
const dto = { name: "Key Name" };
|
||||||
|
await controller.create(req, dto);
|
||||||
|
expect(service.create).toHaveBeenCalledWith(
|
||||||
|
"user-uuid",
|
||||||
|
"Key Name",
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("findAll", () => {
|
||||||
|
it("should call service.findAll", async () => {
|
||||||
|
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||||
|
await controller.findAll(req);
|
||||||
|
expect(service.findAll).toHaveBeenCalledWith("user-uuid");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("revoke", () => {
|
||||||
|
it("should call service.revoke", async () => {
|
||||||
|
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||||
|
await controller.revoke(req, "key-id");
|
||||||
|
expect(service.revoke).toHaveBeenCalledWith("user-uuid", "key-id");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
import { DatabaseService } from "../../database/database.service";
|
||||||
|
import { ApiKeysRepository } from "./api-keys.repository";
|
||||||
|
|
||||||
|
describe("ApiKeysRepository", () => {
|
||||||
|
let repository: ApiKeysRepository;
|
||||||
|
let _databaseService: DatabaseService;
|
||||||
|
|
||||||
|
const mockDb = {
|
||||||
|
insert: jest.fn().mockReturnThis(),
|
||||||
|
values: jest.fn().mockReturnThis(),
|
||||||
|
select: jest.fn().mockReturnThis(),
|
||||||
|
from: jest.fn().mockReturnThis(),
|
||||||
|
where: jest.fn().mockReturnThis(),
|
||||||
|
update: jest.fn().mockReturnThis(),
|
||||||
|
set: jest.fn().mockReturnThis(),
|
||||||
|
returning: jest.fn().mockReturnThis(),
|
||||||
|
limit: 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: [
|
||||||
|
ApiKeysRepository,
|
||||||
|
{ provide: DatabaseService, useValue: { db: mockDb } },
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
repository = module.get<ApiKeysRepository>(ApiKeysRepository);
|
||||||
|
_databaseService = module.get<DatabaseService>(DatabaseService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create an api key", async () => {
|
||||||
|
(mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]);
|
||||||
|
await repository.create({
|
||||||
|
userId: "u1",
|
||||||
|
name: "n",
|
||||||
|
prefix: "p",
|
||||||
|
keyHash: "h",
|
||||||
|
});
|
||||||
|
expect(mockDb.insert).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should find all keys for user", async () => {
|
||||||
|
(mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]);
|
||||||
|
const result = await repository.findAll("u1");
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should revoke a key", async () => {
|
||||||
|
(mockDb.execute as jest.Mock).mockResolvedValue([
|
||||||
|
{ id: "1", isActive: false },
|
||||||
|
]);
|
||||||
|
const result = await repository.revoke("u1", "k1");
|
||||||
|
expect(result[0].isActive).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should find active by hash", async () => {
|
||||||
|
(mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]);
|
||||||
|
const result = await repository.findActiveByKeyHash("h");
|
||||||
|
expect(result.id).toBe("1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should update last used", async () => {
|
||||||
|
(mockDb.execute as jest.Mock).mockResolvedValue([{ id: "1" }]);
|
||||||
|
await repository.updateLastUsed("1");
|
||||||
|
expect(mockDb.update).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user