import { cleanup, render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { http, HttpResponse } from "msw"; import { server } from "./test/msw"; import { App } from "./App"; beforeEach(() => { window.__THOTHII_CONFIG__ = { shell: { mode: "full", defaultLocale: "en" } }; }); afterEach(() => { cleanup(); delete window.__THOTHII_CONFIG__; document.querySelector(".omics-language-select")?.remove(); document.documentElement.removeAttribute("data-bs-theme"); }); function registerAuthenticatedShell(mode: "local" | "upstream") { server.use( http.get("/api/auth/config", () => HttpResponse.json({ mode, localLogin: mode === "local", oidcLogin: false, })), http.get("/api/me", () => HttpResponse.json({ issuer: mode === "local" ? "local" : "portal", subject: "portal-user", displayName: "Portal user", roles: ["user"], permissions: ["session.use"], isAdmin: false, csrfToken: mode === "local" ? "c".repeat(43) : null, session: null, })), http.get("/api/settings", () => HttpResponse.json({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "medium", })), http.get("/api/workspaces", () => HttpResponse.json([])), http.get("/api/models", () => HttpResponse.json({ models: [] })), http.get("/api/sessions", () => HttpResponse.json([])), http.get("/api/workspace-registry/status", () => HttpResponse.json({ branch: "main", ahead: 0, behind: 0, degraded: false, })), ); } test("local authentication renders the standalone logout control", async () => { registerAuthenticatedShell("local"); render(); expect(await screen.findByRole("button", { name: "Session" })).toBeInTheDocument(); expect(screen.getByText("Portal user")).toBeInTheDocument(); await userEvent.click(within(screen.getByRole("banner", { name: "Application header" })).getByRole("button", { name: "Portal user" })); expect(await screen.findByRole("menuitem", { name: "Log out" })).toBeInTheDocument(); }); test("trusted upstream authentication keeps identity but omits ThothII logout", async () => { delete window.__THOTHII_CONFIG__; const select = document.createElement("select"); select.className = "omics-language-select"; select.dataset.lang = "en"; document.body.append(select); document.documentElement.setAttribute("data-bs-theme", "light"); registerAuthenticatedShell("upstream"); render(); expect(await screen.findByText("Portal user")).toBeInTheDocument(); expect(screen.queryByRole("button", { name: "Log out" })).not.toBeInTheDocument(); }); test("a local login always enters the core activity", async () => { let signedIn = false; localStorage.setItem("thothii:app-navigation", JSON.stringify({ surface: "database-management", panel: null, })); server.use( http.get("/api/auth/config", () => HttpResponse.json({ mode: "local", localLogin: true, oidcLogin: false, })), http.get("/api/me", () => signedIn ? HttpResponse.json({ issuer: "local", subject: "admin-user", displayName: "Admin user", roles: ["admin"], permissions: ["session.use", "database.manage"], isAdmin: true, csrfToken: "c".repeat(43), session: null, }) : new HttpResponse(null, { status: 401 })), http.post("/api/auth/local/login", () => { signedIn = true; return HttpResponse.json({}); }), http.get("/api/settings", () => HttpResponse.json({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "medium", })), http.get("/api/workspaces", () => HttpResponse.json([])), http.get("/api/models", () => HttpResponse.json({ models: [] })), http.get("/api/sessions", () => HttpResponse.json([])), http.get("/api/workspace-registry/status", () => HttpResponse.json({ branch: "main", ahead: 0, behind: 0, degraded: false, })), ); render(); await screen.findByRole("heading", { name: /sign in to thothii/i }); await userEvent.type(screen.getByLabelText(/username/i), "admin"); await userEvent.type(screen.getByLabelText(/^password$/i), "correct-password"); await userEvent.click(screen.getByRole("button", { name: /sign in/i })); expect(await screen.findByRole("button", { name: "Session" })) .toHaveAttribute("aria-current", "page"); expect(screen.queryByRole("main", { name: "Database management" })).not.toBeInTheDocument(); });