Files
stack/apps/api/src/onboarding/onboarding.service.spec.ts
Jason Woltje dc7e0c805c
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
feat(api): onboarding API (MS22-P1e) (#612)
Co-authored-by: Jason Woltje <jason@diversecanvas.com>
Co-committed-by: Jason Woltje <jason@diversecanvas.com>
2026-03-01 15:43:43 +00:00

207 lines
5.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { hash } from "bcryptjs";
import { OnboardingService } from "./onboarding.service";
import { PrismaService } from "../prisma/prisma.service";
import { CryptoService } from "../crypto/crypto.service";
vi.mock("bcryptjs", () => ({
hash: vi.fn(),
}));
describe("OnboardingService", () => {
let service: OnboardingService;
const mockPrismaService = {
systemConfig: {
findUnique: vi.fn(),
upsert: vi.fn(),
},
breakglassUser: {
count: vi.fn(),
create: vi.fn(),
findFirst: vi.fn(),
},
llmProvider: {
create: vi.fn(),
},
};
const mockCryptoService = {
encrypt: vi.fn(),
};
beforeEach(() => {
vi.clearAllMocks();
service = new OnboardingService(
mockPrismaService as unknown as PrismaService,
mockCryptoService as unknown as CryptoService
);
});
it("isCompleted returns false when no config exists", async () => {
mockPrismaService.systemConfig.findUnique.mockResolvedValue(null);
await expect(service.isCompleted()).resolves.toBe(false);
expect(mockPrismaService.systemConfig.findUnique).toHaveBeenCalledWith({
where: { key: "onboarding.completed" },
});
});
it("isCompleted returns true when completed", async () => {
mockPrismaService.systemConfig.findUnique.mockResolvedValue({
id: "cfg-1",
key: "onboarding.completed",
value: "true",
encrypted: false,
updatedAt: new Date(),
});
await expect(service.isCompleted()).resolves.toBe(true);
});
it("createBreakglassUser hashes password and creates record", async () => {
const mockedHash = vi.mocked(hash);
mockedHash.mockResolvedValue("hashed-password");
mockPrismaService.breakglassUser.count.mockResolvedValue(0);
mockPrismaService.breakglassUser.create.mockResolvedValue({
id: "breakglass-1",
username: "admin",
});
const result = await service.createBreakglassUser("admin", "supersecret123");
expect(mockedHash).toHaveBeenCalledWith("supersecret123", 12);
expect(mockPrismaService.breakglassUser.create).toHaveBeenCalledWith({
data: {
username: "admin",
passwordHash: "hashed-password",
},
select: {
id: true,
username: true,
},
});
expect(result).toEqual({ id: "breakglass-1", username: "admin" });
});
it("createBreakglassUser rejects if user already exists", async () => {
mockPrismaService.breakglassUser.count.mockResolvedValue(1);
await expect(service.createBreakglassUser("admin", "supersecret123")).rejects.toThrow(
"Breakglass user already exists"
);
});
it("configureOidc encrypts secret and saves to SystemConfig", async () => {
mockCryptoService.encrypt.mockReturnValue("enc:oidc-secret");
mockPrismaService.systemConfig.upsert.mockResolvedValue({
id: "cfg",
key: "oidc.clientSecret",
value: "enc:oidc-secret",
encrypted: true,
updatedAt: new Date(),
});
await service.configureOidc("https://auth.example.com", "client-id", "client-secret");
expect(mockCryptoService.encrypt).toHaveBeenCalledWith("client-secret");
expect(mockPrismaService.systemConfig.upsert).toHaveBeenCalledTimes(3);
expect(mockPrismaService.systemConfig.upsert).toHaveBeenCalledWith({
where: { key: "oidc.issuerUrl" },
create: {
key: "oidc.issuerUrl",
value: "https://auth.example.com",
encrypted: false,
},
update: {
value: "https://auth.example.com",
encrypted: false,
},
});
expect(mockPrismaService.systemConfig.upsert).toHaveBeenCalledWith({
where: { key: "oidc.clientId" },
create: {
key: "oidc.clientId",
value: "client-id",
encrypted: false,
},
update: {
value: "client-id",
encrypted: false,
},
});
expect(mockPrismaService.systemConfig.upsert).toHaveBeenCalledWith({
where: { key: "oidc.clientSecret" },
create: {
key: "oidc.clientSecret",
value: "enc:oidc-secret",
encrypted: true,
},
update: {
value: "enc:oidc-secret",
encrypted: true,
},
});
});
it("addProvider encrypts apiKey and creates LlmProvider", async () => {
mockCryptoService.encrypt.mockReturnValue("enc:api-key");
mockPrismaService.llmProvider.create.mockResolvedValue({
id: "provider-1",
});
const result = await service.addProvider("breakglass-1", {
name: "my-openai",
displayName: "OpenAI",
type: "openai",
baseUrl: "https://api.openai.com/v1",
apiKey: "sk-test",
models: [{ id: "gpt-4o-mini", name: "GPT-4o Mini" }],
});
expect(mockCryptoService.encrypt).toHaveBeenCalledWith("sk-test");
expect(mockPrismaService.llmProvider.create).toHaveBeenCalledWith({
data: {
userId: "breakglass-1",
name: "my-openai",
displayName: "OpenAI",
type: "openai",
baseUrl: "https://api.openai.com/v1",
apiKey: "enc:api-key",
models: [{ id: "gpt-4o-mini", name: "GPT-4o Mini" }],
},
select: {
id: true,
},
});
expect(result).toEqual({ id: "provider-1" });
});
it("complete sets SystemConfig flag", async () => {
mockPrismaService.systemConfig.upsert.mockResolvedValue({
id: "cfg-1",
key: "onboarding.completed",
value: "true",
encrypted: false,
updatedAt: new Date(),
});
await service.complete();
expect(mockPrismaService.systemConfig.upsert).toHaveBeenCalledWith({
where: { key: "onboarding.completed" },
create: {
key: "onboarding.completed",
value: "true",
encrypted: false,
},
update: {
value: "true",
encrypted: false,
},
});
});
});