- Added `lint:fix` scripts for backend, frontend, and documentation. - Enabled `biome check --write` for unsafe fixes in backend scripts. - Fixed imports, formatting, and logging for improved code clarity. - Adjusted service unit tests for better readability and maintainability.
115 lines
3.4 KiB
TypeScript
115 lines
3.4 KiB
TypeScript
import { UnauthorizedException } from "@nestjs/common";
|
|
import { ConfigService } from "@nestjs/config";
|
|
import { Test, TestingModule } from "@nestjs/testing";
|
|
import { UsersService } from "../users/users.service";
|
|
import { BootstrapService } from "./bootstrap.service";
|
|
import { RbacService } from "./rbac.service";
|
|
|
|
describe("BootstrapService", () => {
|
|
let service: BootstrapService;
|
|
let rbacService: RbacService;
|
|
let _usersService: UsersService;
|
|
|
|
const mockRbacService = {
|
|
countAdmins: jest.fn(),
|
|
assignRoleToUser: jest.fn(),
|
|
};
|
|
|
|
const mockUsersService = {
|
|
findPublicProfile: jest.fn(),
|
|
};
|
|
|
|
const mockConfigService = {
|
|
get: jest.fn(),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
jest.clearAllMocks();
|
|
const module: TestingModule = await Test.createTestingModule({
|
|
providers: [
|
|
BootstrapService,
|
|
{ provide: RbacService, useValue: mockRbacService },
|
|
{ provide: UsersService, useValue: mockUsersService },
|
|
{ provide: ConfigService, useValue: mockConfigService },
|
|
],
|
|
}).compile();
|
|
|
|
service = module.get<BootstrapService>(BootstrapService);
|
|
rbacService = module.get<RbacService>(RbacService);
|
|
_usersService = module.get<UsersService>(UsersService);
|
|
});
|
|
|
|
it("should be defined", () => {
|
|
expect(service).toBeDefined();
|
|
});
|
|
|
|
describe("onApplicationBootstrap", () => {
|
|
it("should generate a token if no admin exists", async () => {
|
|
mockRbacService.countAdmins.mockResolvedValue(0);
|
|
const generateTokenSpy = jest.spyOn(
|
|
service as any,
|
|
"generateBootstrapToken",
|
|
);
|
|
|
|
await service.onApplicationBootstrap();
|
|
|
|
expect(rbacService.countAdmins).toHaveBeenCalled();
|
|
expect(generateTokenSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should not generate a token if admin exists", async () => {
|
|
mockRbacService.countAdmins.mockResolvedValue(1);
|
|
const generateTokenSpy = jest.spyOn(
|
|
service as any,
|
|
"generateBootstrapToken",
|
|
);
|
|
|
|
await service.onApplicationBootstrap();
|
|
|
|
expect(rbacService.countAdmins).toHaveBeenCalled();
|
|
expect(generateTokenSpy).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("consumeToken", () => {
|
|
it("should throw UnauthorizedException if token is invalid", async () => {
|
|
mockRbacService.countAdmins.mockResolvedValue(0);
|
|
await service.onApplicationBootstrap();
|
|
|
|
await expect(service.consumeToken("wrong-token", "user1")).rejects.toThrow(
|
|
UnauthorizedException,
|
|
);
|
|
});
|
|
|
|
it("should throw UnauthorizedException if user not found", async () => {
|
|
mockRbacService.countAdmins.mockResolvedValue(0);
|
|
await service.onApplicationBootstrap();
|
|
const token = (service as any).bootstrapToken;
|
|
|
|
mockUsersService.findPublicProfile.mockResolvedValue(null);
|
|
|
|
await expect(service.consumeToken(token, "user1")).rejects.toThrow(
|
|
UnauthorizedException,
|
|
);
|
|
});
|
|
|
|
it("should assign admin role and invalidate token on success", async () => {
|
|
mockRbacService.countAdmins.mockResolvedValue(0);
|
|
await service.onApplicationBootstrap();
|
|
const token = (service as any).bootstrapToken;
|
|
|
|
const mockUser = { uuid: "user-uuid", username: "user1" };
|
|
mockUsersService.findPublicProfile.mockResolvedValue(mockUser);
|
|
|
|
const result = await service.consumeToken(token, "user1");
|
|
|
|
expect(rbacService.assignRoleToUser).toHaveBeenCalledWith(
|
|
"user-uuid",
|
|
"admin",
|
|
);
|
|
expect((service as any).bootstrapToken).toBeNull();
|
|
expect(result.message).toContain("user1 is now an administrator");
|
|
});
|
|
});
|
|
});
|