test: add comprehensive unit tests for core services

Added unit tests for the `api-keys`, `auth`, `categories`, `contents`, `favorites`, `media`, and `purge` services to improve test coverage and ensure core functionality integrity.
This commit is contained in:
Mathis HERRIOT
2026-01-08 16:22:23 +01:00
parent cc2823db7d
commit 399bdab86c
13 changed files with 1502 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
import { createHash } from "node:crypto";
import { Test, TestingModule } from "@nestjs/testing";
import { DatabaseService } from "../database/database.service";
import { apiKeys } from "../database/schemas";
import { ApiKeysService } from "./api-keys.service";
describe("ApiKeysService", () => {
let service: ApiKeysService;
const mockDb = {
insert: jest.fn(),
values: jest.fn(),
select: jest.fn(),
from: jest.fn(),
where: jest.fn(),
limit: jest.fn(),
update: jest.fn(),
set: jest.fn(),
returning: jest.fn(),
};
beforeEach(async () => {
jest.clearAllMocks();
mockDb.insert.mockReturnThis();
mockDb.values.mockResolvedValue(undefined);
mockDb.select.mockReturnThis();
mockDb.from.mockReturnThis();
mockDb.where.mockReturnThis();
mockDb.limit.mockReturnThis();
mockDb.update.mockReturnThis();
mockDb.set.mockReturnThis();
mockDb.returning.mockResolvedValue([]);
// Default for findAll which is awaited on where()
mockDb.where.mockImplementation(() => {
const chain = {
returning: jest.fn().mockResolvedValue([]),
};
return Object.assign(Promise.resolve([]), chain);
});
const module: TestingModule = await Test.createTestingModule({
providers: [
ApiKeysService,
{
provide: DatabaseService,
useValue: {
db: mockDb,
},
},
],
}).compile();
service = module.get<ApiKeysService>(ApiKeysService);
});
it("should be defined", () => {
expect(service).toBeDefined();
});
describe("create", () => {
it("should create an API key", async () => {
const userId = "user-id";
const name = "Test Key";
const expiresAt = new Date();
const result = await service.create(userId, name, expiresAt);
expect(mockDb.insert).toHaveBeenCalledWith(apiKeys);
expect(mockDb.values).toHaveBeenCalledWith(
expect.objectContaining({
userId,
name,
prefix: "mg_live_",
expiresAt,
}),
);
expect(result).toHaveProperty("key");
expect(result.name).toBe(name);
expect(result.expiresAt).toBe(expiresAt);
expect(result.key).toMatch(/^mg_live_/);
});
});
describe("findAll", () => {
it("should find all API keys for a user", async () => {
const userId = "user-id";
const expectedKeys = [{ id: "1", name: "Key 1" }];
(mockDb.where as jest.Mock).mockResolvedValue(expectedKeys);
const result = await service.findAll(userId);
expect(mockDb.select).toHaveBeenCalled();
expect(mockDb.from).toHaveBeenCalledWith(apiKeys);
expect(result).toEqual(expectedKeys);
});
});
describe("revoke", () => {
it("should revoke an API key", async () => {
const userId = "user-id";
const keyId = "key-id";
const expectedResult = [{ id: keyId, isActive: false }];
mockDb.where.mockReturnValue({
returning: jest.fn().mockResolvedValue(expectedResult),
});
const result = await service.revoke(userId, keyId);
expect(mockDb.update).toHaveBeenCalledWith(apiKeys);
expect(mockDb.set).toHaveBeenCalledWith(
expect.objectContaining({ isActive: false }),
);
expect(result).toEqual(expectedResult);
});
});
describe("validateKey", () => {
it("should validate a valid API key", async () => {
const key = "mg_live_testkey";
const keyHash = createHash("sha256").update(key).digest("hex");
const apiKey = { id: "1", keyHash, isActive: true, expiresAt: null };
(mockDb.limit as jest.Mock).mockResolvedValue([apiKey]);
(mockDb.where as jest.Mock).mockResolvedValue([apiKey]); // For the update later if needed, but here it's for select
// We need to be careful with chaining mockDb.where is used in both select and update
const mockSelect = {
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
limit: jest.fn().mockResolvedValue([apiKey]),
};
const mockUpdate = {
set: jest.fn().mockReturnThis(),
where: jest.fn().mockResolvedValue(undefined),
};
(mockDb.select as jest.Mock).mockReturnValue(mockSelect);
(mockDb.update as jest.Mock).mockReturnValue(mockUpdate);
const result = await service.validateKey(key);
expect(result).toEqual(apiKey);
expect(mockDb.select).toHaveBeenCalled();
expect(mockDb.update).toHaveBeenCalledWith(apiKeys);
});
it("should return null for invalid API key", async () => {
(mockDb.select as jest.Mock).mockReturnValue({
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
limit: jest.fn().mockResolvedValue([]),
});
const result = await service.validateKey("invalid-key");
expect(result).toBeNull();
});
it("should return null for expired API key", async () => {
const key = "mg_live_testkey";
const expiredDate = new Date();
expiredDate.setFullYear(expiredDate.getFullYear() - 1);
const apiKey = { id: "1", isActive: true, expiresAt: expiredDate };
(mockDb.select as jest.Mock).mockReturnValue({
from: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
limit: jest.fn().mockResolvedValue([apiKey]),
});
const result = await service.validateKey(key);
expect(result).toBeNull();
});
});
});