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); rbacService = module.get(RbacService); _usersService = module.get(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"); }); }); });