test(reports): add unit tests for ReportsController and ReportsRepository with mocked dependencies
This commit is contained in:
150
backend/src/users/repositories/users.repository.spec.ts
Normal file
150
backend/src/users/repositories/users.repository.spec.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { DatabaseService } from "../../database/database.service";
|
||||
import { UsersRepository } from "./users.repository";
|
||||
|
||||
describe("UsersRepository", () => {
|
||||
let repository: UsersRepository;
|
||||
let _databaseService: DatabaseService;
|
||||
|
||||
const mockDb = {
|
||||
insert: jest.fn().mockReturnThis(),
|
||||
values: jest.fn().mockReturnThis(),
|
||||
returning: jest.fn().mockResolvedValue([{ uuid: "u1" }]),
|
||||
select: jest.fn().mockReturnThis(),
|
||||
from: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
limit: jest.fn().mockReturnThis(),
|
||||
offset: jest.fn().mockReturnThis(),
|
||||
update: jest.fn().mockReturnThis(),
|
||||
set: jest.fn().mockReturnThis(),
|
||||
delete: jest.fn().mockReturnThis(),
|
||||
transaction: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
UsersRepository,
|
||||
{
|
||||
provide: DatabaseService,
|
||||
useValue: { db: mockDb },
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
repository = module.get<UsersRepository>(UsersRepository);
|
||||
_databaseService = module.get<DatabaseService>(DatabaseService);
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(repository).toBeDefined();
|
||||
});
|
||||
|
||||
describe("create", () => {
|
||||
it("should insert a user", async () => {
|
||||
const data = {
|
||||
username: "u",
|
||||
email: "e",
|
||||
passwordHash: "p",
|
||||
emailHash: "eh",
|
||||
};
|
||||
await repository.create(data);
|
||||
expect(mockDb.insert).toHaveBeenCalled();
|
||||
expect(mockDb.values).toHaveBeenCalledWith(data);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findByEmailHash", () => {
|
||||
it("should select user by email hash", async () => {
|
||||
mockDb.limit.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
const result = await repository.findByEmailHash("hash");
|
||||
expect(result.uuid).toBe("u1");
|
||||
expect(mockDb.select).toHaveBeenCalled();
|
||||
expect(mockDb.where).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("findOneWithPrivateData", () => {
|
||||
it("should select user with private data", async () => {
|
||||
mockDb.limit.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
const result = await repository.findOneWithPrivateData("u1");
|
||||
expect(result.uuid).toBe("u1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("countAll", () => {
|
||||
it("should return count", async () => {
|
||||
mockDb.from.mockResolvedValueOnce([{ count: 5 }]);
|
||||
const result = await repository.countAll();
|
||||
expect(result).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findAll", () => {
|
||||
it("should select users with limit and offset", async () => {
|
||||
mockDb.offset.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
const result = await repository.findAll(10, 0);
|
||||
expect(result[0].uuid).toBe("u1");
|
||||
expect(mockDb.limit).toHaveBeenCalledWith(10);
|
||||
expect(mockDb.offset).toHaveBeenCalledWith(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findByUsername", () => {
|
||||
it("should find by username", async () => {
|
||||
mockDb.limit.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
const result = await repository.findByUsername("u");
|
||||
expect(result.uuid).toBe("u1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("update", () => {
|
||||
it("should update user", async () => {
|
||||
mockDb.returning.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
await repository.update("u1", { displayName: "New" });
|
||||
expect(mockDb.update).toHaveBeenCalled();
|
||||
expect(mockDb.set).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getTwoFactorSecret", () => {
|
||||
it("should return secret", async () => {
|
||||
mockDb.limit.mockResolvedValueOnce([{ secret: "s" }]);
|
||||
const result = await repository.getTwoFactorSecret("u1");
|
||||
expect(result).toBe("s");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUserContents", () => {
|
||||
it("should return contents", async () => {
|
||||
mockDb.where.mockResolvedValueOnce([{ id: "c1" }]);
|
||||
const result = await repository.getUserContents("u1");
|
||||
expect(result[0].id).toBe("c1");
|
||||
});
|
||||
});
|
||||
|
||||
describe("softDeleteUserAndContents", () => {
|
||||
it("should run transaction", async () => {
|
||||
const mockTx = {
|
||||
update: jest.fn().mockReturnThis(),
|
||||
set: jest.fn().mockReturnThis(),
|
||||
where: jest.fn().mockReturnThis(),
|
||||
returning: jest.fn().mockResolvedValue([{ uuid: "u1" }]),
|
||||
};
|
||||
mockDb.transaction.mockImplementation(async (cb) => cb(mockTx));
|
||||
|
||||
const result = await repository.softDeleteUserAndContents("u1");
|
||||
expect(result[0].uuid).toBe("u1");
|
||||
expect(mockTx.update).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("purgeDeleted", () => {
|
||||
it("should delete old deleted users", async () => {
|
||||
mockDb.returning.mockResolvedValueOnce([{ uuid: "u1" }]);
|
||||
const _result = await repository.purgeDeleted(new Date());
|
||||
expect(mockDb.delete).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
192
backend/src/users/users.controller.spec.ts
Normal file
192
backend/src/users/users.controller.spec.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
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 { AuthService } from "../auth/auth.service";
|
||||
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||
import { RolesGuard } from "../auth/guards/roles.guard";
|
||||
import { AuthenticatedRequest } from "../common/interfaces/request.interface";
|
||||
import { UsersController } from "./users.controller";
|
||||
import { UsersService } from "./users.service";
|
||||
|
||||
describe("UsersController", () => {
|
||||
let controller: UsersController;
|
||||
let usersService: UsersService;
|
||||
let authService: AuthService;
|
||||
|
||||
const mockUsersService = {
|
||||
findAll: jest.fn(),
|
||||
findPublicProfile: jest.fn(),
|
||||
findOneWithPrivateData: jest.fn(),
|
||||
exportUserData: jest.fn(),
|
||||
update: jest.fn(),
|
||||
updateAvatar: jest.fn(),
|
||||
updateConsent: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
};
|
||||
|
||||
const mockAuthService = {
|
||||
generateTwoFactorSecret: jest.fn(),
|
||||
enableTwoFactor: jest.fn(),
|
||||
disableTwoFactor: jest.fn(),
|
||||
};
|
||||
|
||||
const mockCacheManager = {
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UsersController],
|
||||
providers: [
|
||||
{ provide: UsersService, useValue: mockUsersService },
|
||||
{ provide: AuthService, useValue: mockAuthService },
|
||||
{ provide: CACHE_MANAGER, useValue: mockCacheManager },
|
||||
],
|
||||
})
|
||||
.overrideGuard(AuthGuard)
|
||||
.useValue({ canActivate: () => true })
|
||||
.overrideGuard(RolesGuard)
|
||||
.useValue({ canActivate: () => true })
|
||||
.compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
usersService = module.get<UsersService>(UsersService);
|
||||
authService = module.get<AuthService>(AuthService);
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
|
||||
describe("findAll", () => {
|
||||
it("should call usersService.findAll", async () => {
|
||||
await controller.findAll(10, 0);
|
||||
expect(usersService.findAll).toHaveBeenCalledWith(10, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findPublicProfile", () => {
|
||||
it("should call usersService.findPublicProfile", async () => {
|
||||
await controller.findPublicProfile("testuser");
|
||||
expect(usersService.findPublicProfile).toHaveBeenCalledWith("testuser");
|
||||
});
|
||||
});
|
||||
|
||||
describe("findMe", () => {
|
||||
it("should call usersService.findOneWithPrivateData", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.findMe(req);
|
||||
expect(usersService.findOneWithPrivateData).toHaveBeenCalledWith(
|
||||
"user-uuid",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("exportMe", () => {
|
||||
it("should call usersService.exportUserData", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.exportMe(req);
|
||||
expect(usersService.exportUserData).toHaveBeenCalledWith("user-uuid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateMe", () => {
|
||||
it("should call usersService.update", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
const dto = { displayName: "New Name" };
|
||||
await controller.updateMe(req, dto);
|
||||
expect(usersService.update).toHaveBeenCalledWith("user-uuid", dto);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateAvatar", () => {
|
||||
it("should call usersService.updateAvatar", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
const file = {} as Express.Multer.File;
|
||||
await controller.updateAvatar(req, file);
|
||||
expect(usersService.updateAvatar).toHaveBeenCalledWith("user-uuid", file);
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateConsent", () => {
|
||||
it("should call usersService.updateConsent", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
const dto = { termsVersion: "1.0", privacyVersion: "1.0" };
|
||||
await controller.updateConsent(req, dto);
|
||||
expect(usersService.updateConsent).toHaveBeenCalledWith(
|
||||
"user-uuid",
|
||||
"1.0",
|
||||
"1.0",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeMe", () => {
|
||||
it("should call usersService.remove", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.removeMe(req);
|
||||
expect(usersService.remove).toHaveBeenCalledWith("user-uuid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeAdmin", () => {
|
||||
it("should call usersService.remove", async () => {
|
||||
await controller.removeAdmin("target-uuid");
|
||||
expect(usersService.remove).toHaveBeenCalledWith("target-uuid");
|
||||
});
|
||||
});
|
||||
|
||||
describe("setup2fa", () => {
|
||||
it("should call authService.generateTwoFactorSecret", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.setup2fa(req);
|
||||
expect(authService.generateTwoFactorSecret).toHaveBeenCalledWith(
|
||||
"user-uuid",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("enable2fa", () => {
|
||||
it("should call authService.enableTwoFactor", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.enable2fa(req, "token123");
|
||||
expect(authService.enableTwoFactor).toHaveBeenCalledWith(
|
||||
"user-uuid",
|
||||
"token123",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("disable2fa", () => {
|
||||
it("should call authService.disableTwoFactor", async () => {
|
||||
const req = { user: { sub: "user-uuid" } } as AuthenticatedRequest;
|
||||
await controller.disable2fa(req, "token123");
|
||||
expect(authService.disableTwoFactor).toHaveBeenCalledWith(
|
||||
"user-uuid",
|
||||
"token123",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user