import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; import { HomePage } from "./HomePage"; import { MaintenancePage } from "./MaintenancePage"; import { PluginsPage } from "./PluginsPage"; import { ProfileSettingsPage } from "./ProfileSettingsPage"; import { ServerDetailPage } from "./ServerDetailPage"; import { ServersPage } from "./ServersPage"; import { UsersPage } from "./UsersPage"; import runtimeTaskProgressSource from "../components/RuntimeTaskProgress.tsx?raw"; import serverDeploymentWorkflowSource from "../components/ServerDeploymentWorkflow.tsx?raw"; import serversPageSource from "./ServersPage.tsx?raw"; import serverDetailPageSource from "./ServerDetailPage.tsx?raw"; import type { PageComponentProps } from "../contracts/page"; import { capabilitiesForRoles, type CurrentUserView } from "../contracts/workspace"; import type { OperationTracker } from "../stores/operations"; import type { UserResponse } from "../api/types"; const adminUser: CurrentUserView = { id: "user-admin", displayName: "Operator", status: "active", roles: ["platformAdmin"], capabilities: capabilitiesForRoles(["platformAdmin"]), profile: {}, source: "local" }; const noopOperations: OperationTracker = { operations: [], begin: () => "op-test", update: () => undefined, succeed: () => undefined, fail: () => undefined, isPending: () => false }; const reviewUser: UserResponse = { id: "user-reviewer", displayName: "Plugin Reviewer", email: "reviewer@example.test", status: "pending", roles: ["server-admin"], profile: { contactNote: "needs approval" }, createdAt: "2026-07-03T00:00:00Z", updatedAt: "2026-07-03T00:00:00Z" }; function pageProps(params: PageComponentProps["params"] = {}): PageComponentProps { return { session: adminUser, params, operations: noopOperations, onNavigate: () => undefined, onLogout: async () => undefined, onProfileSave: async () => adminUser, onThemePreferenceSave: async () => ({ userId: adminUser.id, paletteId: "mecha-black", backgroundPresetId: "mecha-grid", persistence: "api", updatedAt: "2026-07-03T00:00:00Z" }) }; } describe("first-party console pages", () => { it("renders the platform overview with first-screen health modules", () => { const html = renderToStaticMarkup(); expect(html).toContain("平台概览"); expect(html).toContain("资源负载"); expect(html).toContain("游戏类型分布"); expect(html).toContain("最近运营信号"); expect(html).not.toContain("sk-"); }); it("keeps unavailable overview modules visible instead of claiming an empty healthy state", () => { const html = renderToStaticMarkup( ); expect(html).toContain("4 个模块不可用"); expect(html).toContain("资源指标不可用"); expect(html).toContain("审计信号不可用"); expect(html).toContain("AI 提供商信号不可用"); expect(html).toContain("server.lifecycle.start"); expect(html).not.toContain("暂无异常信号"); }); it("explains read-only overview access when the session cannot create servers", () => { const readOnlySession: CurrentUserView = { ...adminUser, roles: ["serverAdmin"], capabilities: ["platform.overview.read", "servers.read"] }; const html = renderToStaticMarkup( ); expect(html).toContain("没有创建服务器的权限"); expect(html).toContain("前往服务器管理"); }); it("renders the server list workspace with search and status filters", () => { const html = renderToStaticMarkup(); expect(html).toContain("服务器管理"); expect(html).toContain("搜索服务器"); expect(html).toContain("在线"); expect(html).toContain("离线"); expect(html).not.toContain("run socket"); expect(html).not.toContain("/Users/"); }); it("keeps server metrics unavailable and runtime commands permission-gated", () => { expect(serversPageSource).toContain("metricsUnavailable"); expect(serversPageSource).toContain("指标不可用"); expect(serversPageSource).toContain("canManageServers"); expect(serversPageSource).toContain("当前账号没有运行操作权限"); expect(serversPageSource).toContain("failedJobs"); expect(serversPageSource).toContain("refreshMetrics"); expect(serversPageSource).toContain("onClick={() => void refreshMetrics()}"); }); it("exposes run key reset from the compact server list danger menu", () => { expect(serversPageSource).toContain("reset-run-key"); expect(serversPageSource).toContain("重置 run 密钥"); expect(serversPageSource).toContain("runtimeKeyResetStages"); expect(serversPageSource).toContain("platformApiClient.resetRunKey"); expect(serversPageSource).toContain("旧 run 会话已失效"); }); it("uses a staged deployment workflow for create and edit without exposing protected inputs", () => { expect(serversPageSource).toContain(" { expect(serversPageSource).toContain('aria-haspopup="menu"'); expect(serversPageSource).toContain("createPortal"); expect(serversPageSource).toContain("runtime-action-popover"); expect(serversPageSource).not.toContain("runtime-action-menu"); expect(serversPageSource).not.toContain(" { const deleteHandlerSource = serversPageSource.split("async function handleDeleteServer")[1]?.split("function openRunTargetSelection")[0] ?? ""; expect(serversPageSource).toContain("deleteServerInstance(deleteConfirmation.serverInstanceId, { password: deletePassword })"); expect(serversPageSource).toContain("serverDeleteConfirmation(card.instance)"); expect(serversPageSource).toContain("serverDeleteDisabledReason(session, card.instance)"); expect(serversPageSource).toContain("危险操作"); expect(serversPageSource).toContain("删除服务器"); expect(serversPageSource).toContain("请输入当前登录密码"); expect(serversPageSource).toContain("canOpenActions"); expect(deleteHandlerSource).toContain("await refresh();"); expect(deleteHandlerSource).not.toContain("onNavigate"); expect(serverDetailPageSource).not.toContain("deleteServerInstance"); expect(serverDetailPageSource).not.toContain("serverDeleteConfirmation"); }); it("surfaces runtime actions through progress dialogs with build stages", () => { const generateRunSource = serversPageSource.split("async function generateRunForTarget")[1]?.split("async function handleQuickRuntimeAction")[0] ?? ""; expect(serversPageSource).toContain("RuntimeTaskProgressDialog"); expect(serversPageSource).toContain("选择生成平台"); expect(serversPageSource).toContain("runTargetSelection"); expect(serversPageSource).toContain("runtimeRunBuildStages"); expect(serversPageSource).toContain("requireQuickRuntimeActionAvailable(instance.id, action)"); expect(serversPageSource).toContain("该操作不可用"); expect(generateRunSource.indexOf("runtimeTask.runTrackedTask")).toBeLessThan(generateRunSource.indexOf('await requireQuickRuntimeActionAvailable(instance.id, "generate-run")')); expect(serverDetailPageSource).toContain("RuntimeTaskProgressDialog"); expect(serverDetailPageSource).toContain("runtimeRunBuildStages"); expect(runtimeTaskProgressSource).toContain("runtimeBuildStages"); expect(runtimeTaskProgressSource).toContain("runtimeRunBuildStages"); expect(runtimeTaskProgressSource).toContain("进度展示"); expect(runtimeTaskProgressSource).toContain("activeStepLabel"); expect(runtimeTaskProgressSource).toContain("平台正在执行当前阶段"); expect(runtimeTaskProgressSource).toContain("拉取 run 更新"); expect(runtimeTaskProgressSource).toContain("检测构建环境"); expect(runtimeTaskProgressSource).toContain("构建中"); expect(runtimeTaskProgressSource).toContain("构建完成"); expect(runtimeTaskProgressSource).toContain("拉取代码"); expect(runtimeTaskProgressSource).toContain("安装环境"); expect(runtimeTaskProgressSource).toContain("编译构建"); expect(runtimeTaskProgressSource).toContain("打包成功"); expect(runtimeTaskProgressSource).toContain("构建成功"); }); it("renders server detail sections for daily operations", () => { const html = renderToStaticMarkup(); expect(html).toContain("返回列表"); expect(html).toContain("概览"); expect(html).toContain("日志"); expect(html).toContain("配置"); expect(html).toContain("插件控制"); expect(html).toContain("AI 助手"); expect(html).toContain("操作历史"); }); it("renders plugin catalog bridge readiness", () => { const html = renderToStaticMarkup(); expect(html).toContain("插件市场"); expect(html).toContain("平台 API"); expect(html).toContain("正在加载插件市场"); expect(html).not.toContain("billing"); }); it("renders user access review context", () => { const html = renderToStaticMarkup(); expect(html).toContain("用户管理"); expect(html).toContain("Plugin Reviewer"); expect(html).toContain("needs approval"); expect(html).toContain("本地开发样例 / 仅查看"); }); it("renders maintenance triage entry points", () => { const html = renderToStaticMarkup(); expect(html).toContain("系统维护"); expect(html).toContain("维护排障入口"); expect(html).toContain("节点详情"); expect(html).toContain("最近失败任务"); expect(html).toContain("审计异常"); }); it("renders profile settings as a full page", () => { const html = renderToStaticMarkup(); expect(html).toContain("个人设置"); expect(html).toContain("个人资料"); expect(html).toContain("界面偏好"); expect(html).not.toContain("role=\"dialog\""); }); it("keeps profile background controls focused on custom uploads", () => { const originalWindow = globalThis.window; Object.defineProperty(globalThis, "window", { configurable: true, value: { localStorage: { getItem: (key: string) => { if (key === "platform-web.theme.palette") { return "magical-girl"; } if (key === "platform-web.theme.backgroundPreset") { return "mecha-grid"; } if (key === "platform-web.theme.background") { return "data:image/png;base64,custom"; } return null; } } } }); try { const html = renderToStaticMarkup(); expect(html).toContain("自定义背景"); expect(html).toContain("上传背景"); expect(html).toContain("移除背景"); expect(html).toContain("当前显示自定义上传背景;移除后回到主题配色背景。"); expect(html).not.toContain("机甲格纳库"); expect(html).not.toContain("粉月魔法阵"); expect(html).not.toContain("备用"); } finally { Object.defineProperty(globalThis, "window", { configurable: true, value: originalWindow }); } }); });