Files
CapaKraken/packages/api/src/__tests__/settings-procedure-support.test.ts
T

194 lines
5.2 KiB
TypeScript

import { DEFAULT_OPENAI_MODEL, SystemRole } from "@capakraken/shared";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const {
createAuditEntry,
testSmtpConnection,
generateGeminiImage,
parseGeminiError,
} = vi.hoisted(() => ({
createAuditEntry: vi.fn(),
testSmtpConnection: vi.fn(),
generateGeminiImage: vi.fn(),
parseGeminiError: vi.fn((error: unknown) => `parsed:${String(error)}`),
}));
vi.mock("../lib/audit.js", () => ({
createAuditEntry,
}));
vi.mock("../lib/email.js", () => ({
testSmtpConnection,
}));
vi.mock("../gemini-client.js", () => ({
generateGeminiImage,
parseGeminiError,
}));
import {
clearStoredRuntimeSecrets,
getAiConfiguredStatus,
getSystemSettingsView,
testSettingsGeminiConnection,
testSettingsSmtpConnection,
updateSystemSettings,
} from "../router/settings-procedure-support.js";
function createAdminContext(db: Record<string, unknown>) {
return {
db: db as never,
dbUser: {
id: "admin_1",
systemRole: SystemRole.ADMIN,
permissionOverrides: null,
},
};
}
describe("settings procedure support", () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.unstubAllEnvs();
});
it("builds the system settings view model from db and runtime state", async () => {
vi.stubEnv("OPENAI_API_KEY", "env-openai-key");
vi.stubEnv("SMTP_PASSWORD", "env-smtp-password");
const result = await getSystemSettingsView(createAdminContext({
systemSettings: {
findUnique: vi.fn().mockResolvedValue({
aiProvider: "openai",
azureOpenAiApiKey: null,
smtpPassword: null,
}),
},
}));
expect(result.hasApiKey).toBe(true);
expect(result.hasSmtpPassword).toBe(true);
expect(result.aiProvider).toBe("openai");
expect(result.defaultSummaryPrompt).toBeTypeOf("string");
});
it("updates settings without persisting incoming secret fields and writes an audit entry", async () => {
const findUnique = vi.fn().mockResolvedValue({
id: "singleton",
aiProvider: "azure",
azureOpenAiApiKey: "secret",
});
const upsert = vi.fn().mockResolvedValue({});
const result = await updateSystemSettings(createAdminContext({
systemSettings: {
findUnique,
upsert,
},
}), {
aiProvider: "openai",
azureOpenAiDeployment: DEFAULT_OPENAI_MODEL,
azureOpenAiApiKey: "should-be-ignored",
smtpPassword: "also-ignored",
});
expect(result).toEqual({
ok: true,
ignoredSecretFields: ["azureOpenAiApiKey", "smtpPassword"],
secretStorageMode: "environment-only",
});
expect(upsert).toHaveBeenCalledWith({
where: { id: "singleton" },
create: {
id: "singleton",
aiProvider: "openai",
azureOpenAiDeployment: DEFAULT_OPENAI_MODEL,
},
update: {
aiProvider: "openai",
azureOpenAiDeployment: DEFAULT_OPENAI_MODEL,
},
});
expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({
entityType: "SystemSettings",
action: "UPDATE",
after: expect.objectContaining({
aiProvider: "openai",
azureOpenAiDeployment: DEFAULT_OPENAI_MODEL,
}),
}));
});
it("clears only legacy runtime secrets that are still stored", async () => {
const update = vi.fn().mockResolvedValue({});
const result = await clearStoredRuntimeSecrets(createAdminContext({
systemSettings: {
findUnique: vi.fn().mockResolvedValue({
azureOpenAiApiKey: "db-key",
azureDalleApiKey: null,
geminiApiKey: "db-gemini",
smtpPassword: null,
anonymizationSeed: "seed",
}),
update,
},
}));
expect(result).toEqual({
ok: true,
clearedFields: ["azureOpenAiApiKey", "geminiApiKey", "anonymizationSeed"],
});
expect(update).toHaveBeenCalledWith({
where: { id: "singleton" },
data: {
azureOpenAiApiKey: null,
geminiApiKey: null,
anonymizationSeed: null,
},
});
});
it("tests smtp and gemini connections with audited outcomes", async () => {
testSmtpConnection.mockResolvedValue({ ok: true });
generateGeminiImage.mockResolvedValue("data:image/png;base64,abc123");
const db = {
systemSettings: {
findUnique: vi.fn().mockResolvedValue({
geminiApiKey: "gem-key",
geminiModel: "gem-model",
}),
},
};
const ctx = createAdminContext(db);
expect(await testSettingsSmtpConnection(ctx)).toEqual({ ok: true });
expect(await testSettingsGeminiConnection(ctx)).toEqual({
ok: true,
model: "gem-model",
preview: "data:image/png;base64,abc123...",
});
expect(createAuditEntry).toHaveBeenCalledTimes(2);
});
it("reads the ai configured status from runtime-resolved settings", async () => {
vi.stubEnv("OPENAI_API_KEY", "env-openai-key");
const result = await getAiConfiguredStatus(createAdminContext({
systemSettings: {
findUnique: vi.fn().mockResolvedValue({
aiProvider: "openai",
azureOpenAiDeployment: DEFAULT_OPENAI_MODEL,
azureOpenAiApiKey: null,
}),
},
}));
expect(result).toEqual({ configured: true });
});
});