189 lines
7.0 KiB
TypeScript
189 lines
7.0 KiB
TypeScript
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 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(<HomePage {...pageProps()} />);
|
|
|
|
expect(html).toContain("平台概览");
|
|
expect(html).toContain("资源负载");
|
|
expect(html).toContain("游戏类型分布");
|
|
expect(html).toContain("最近运营信号");
|
|
expect(html).not.toContain("sk-");
|
|
});
|
|
|
|
it("renders the server list workspace with search and status filters", () => {
|
|
const html = renderToStaticMarkup(<ServersPage {...pageProps()} />);
|
|
|
|
expect(html).toContain("服务器管理");
|
|
expect(html).toContain("搜索服务器");
|
|
expect(html).toContain("在线");
|
|
expect(html).toContain("离线");
|
|
expect(html).not.toContain("run socket");
|
|
expect(html).not.toContain("/Users/");
|
|
});
|
|
|
|
it("renders server runtime actions as a compact popover trigger instead of an in-card details stack", () => {
|
|
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("<details");
|
|
});
|
|
|
|
it("surfaces runtime actions through progress dialogs with build stages", () => {
|
|
expect(serversPageSource).toContain("RuntimeTaskProgressDialog");
|
|
expect(serverDetailPageSource).toContain("RuntimeTaskProgressDialog");
|
|
expect(runtimeTaskProgressSource).toContain("runtimeBuildStages");
|
|
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(<ServerDetailPage {...pageProps({ serverId: "server-example-1" })} />);
|
|
|
|
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(<PluginsPage />);
|
|
|
|
expect(html).toContain("插件市场");
|
|
expect(html).toContain("平台 API");
|
|
expect(html).toContain("正在加载插件市场");
|
|
expect(html).not.toContain("billing");
|
|
});
|
|
|
|
it("renders user access review context", () => {
|
|
const html = renderToStaticMarkup(<UsersPage {...pageProps()} initialState={{ users: [reviewUser], loading: false, source: "local-development" }} />);
|
|
|
|
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(<MaintenancePage {...pageProps()} />);
|
|
|
|
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(<ProfileSettingsPage {...pageProps()} />);
|
|
|
|
expect(html).toContain("个人设置");
|
|
expect(html).toContain("个人资料");
|
|
expect(html).toContain("界面偏好");
|
|
expect(html).not.toContain("role=\"dialog\"");
|
|
});
|
|
|
|
it("labels uploaded profile backgrounds as active and built-in presets as fallback", () => {
|
|
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(<ProfileSettingsPage {...pageProps()} />);
|
|
|
|
expect(html).toContain("自定义背景");
|
|
expect(html).toContain("机甲格纳库");
|
|
expect(html).toContain("备用");
|
|
expect(html).toContain("当前显示自定义上传背景;机甲格纳库 仅作为移除上传后的备用桌面。");
|
|
expect(html).toContain('aria-pressed="false"');
|
|
} finally {
|
|
Object.defineProperty(globalThis, "window", {
|
|
configurable: true,
|
|
value: originalWindow
|
|
});
|
|
}
|
|
});
|
|
});
|