import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";
import SettingsPage from "@/app/(app)/settings/page";
import { renderWithQueryClient } from "./test-utils";
const ADMIN_USER = {
id: "user-1",
email: "admin@example.com",
display_name: "Admin",
timezone: "America/New_York",
is_active: true,
is_admin: true,
auth_mode: "jwt",
};
function systemStatusBody(isLocalhost: boolean, authMode: "local" | "jwt") {
return {
app_env: "development",
auth_mode: authMode,
llm_provider: "mock",
search_provider: "mock",
sms_enabled: false,
sms_provider: "twilio",
ninjapear_configured: false,
ninjapear_credit_balance: null,
ninjapear_estimated_credits_per_company: null,
is_localhost: isLocalhost,
turnstile_site_key: null,
components: [],
};
}
/** Covers every endpoint SettingsPage's admin-gated boxes touch on mount -
* empty-list/no-op responses for everything except /system/status, which
* each test configures to drive the local-vs-remote branch under test. */
function mockFetchImplementation(isLocalhost: boolean, authMode: "local" | "jwt" = "jwt") {
return vi.fn().mockImplementation((url: string, init?: RequestInit) => {
const path = url.replace("http://localhost:8000", "");
const ok = (json: unknown, status = 200) =>
Promise.resolve({ ok: true, status, json: async () => json });
if (path === "/api/v1/auth/me") return ok(ADMIN_USER);
if (path === "/api/v1/system/status") return ok(systemStatusBody(isLocalhost, authMode));
if (path === "/api/v1/notification-destinations") return ok([]);
if (path === "/api/v1/companies") return ok([]);
if (path === "/api/v1/system/logs") return ok([]);
if (path === "/api/v1/user-api-keys") return ok([]);
if (path === "/api/v1/system/secrets") return ok([]);
if (path === "/api/v1/auth/security-events") return ok([]);
if (path === "/api/v1/admin/ip-bans") return ok([]);
if (path === "/api/v1/admin/unban-requests") return ok([]);
if (path === "/api/v1/db-viewer/session" && init?.method === "POST") {
return ok({ token: "mock-bootstrap-token" });
}
return Promise.resolve({ ok: false, status: 404, json: async () => ({ detail: "not found" }) });
});
}
beforeEach(() => {
vi.stubEnv("NEXT_PUBLIC_DB_VIEWER_URL", "https://db.ciagent.org");
});
describe("Settings - Database viewer box", () => {
it("links straight to the local Adminer instance for the local-dev bypass account", async () => {
vi.stubGlobal("fetch", mockFetchImplementation(true, "local"));
renderWithQueryClient();
const link = await screen.findByRole("link", { name: /open database viewer/i });
expect(link).toHaveAttribute("href", "http://localhost:8081");
expect(link).toHaveAttribute("target", "_blank");
});
it("mints a session token and opens the configured remote viewer URL for a real admin", async () => {
vi.stubGlobal("fetch", mockFetchImplementation(false, "jwt"));
const openSpy = vi.spyOn(window, "open").mockImplementation(() => null);
const user = userEvent.setup();
renderWithQueryClient();
const button = await screen.findByRole("button", { name: /open database viewer/i });
await user.click(button);
await waitFor(() => {
expect(openSpy).toHaveBeenCalledWith(
"https://db.ciagent.org/_auth?token=mock-bootstrap-token",
"_blank",
"noopener,noreferrer",
);
});
});
it("shows a not-configured message when NEXT_PUBLIC_DB_VIEWER_URL is unset for a remote admin", async () => {
vi.stubEnv("NEXT_PUBLIC_DB_VIEWER_URL", "");
vi.stubGlobal("fetch", mockFetchImplementation(false, "jwt"));
renderWithQueryClient();
expect(await screen.findByText(/not configured for this deployment/i)).toBeInTheDocument();
expect(screen.queryByRole("button", { name: /open database viewer/i })).not.toBeInTheDocument();
});
});