import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; import { PluginsPage } from "./PluginsPage"; import pluginsPageSource from "./PluginsPage.tsx?raw"; import type { MarketplacePluginResponse } from "../api/types"; const marketplacePlugin: MarketplacePluginResponse = { id: "game.example", name: "Example Server", description: "Development plugin", version: "0.1.0", serverType: "example", serverDisplayName: "Example Server", supportedOs: ["linux", "darwin"], manifestRef: "artifact://manifests/game.example/0.1.0", createFormSchemaRef: "schemas/create-form.schema.json", capabilities: ["process.install", "process.start", "logs.read"], declaredPermissions: ["server.read", "server.logs.read", "ai.invoke"], permissions: { ai: true, logs: true, files: false, jobs: true, artifacts: false }, lifecycleActions: { install: "actions/install.json", start: "actions/start.json", stop: "actions/stop.json" }, bridgeActions: ["server.instances.read", "logs.query", "ai.invoke"], pages: [{ key: "logs", title: "Logs", path: "/logs", permissions: ["server.logs.read"], bridgeActions: ["logs.query"] }], tags: ["example"], aiPurposes: ["logs.diagnose"], productionLifecycle: { operations: ["install", "enable", "disable", "upgrade", "rollback", "retire", "dependency-check"], dependencyPolicy: "optional" }, runtimeProfiles: { dllExtensions: [{ key: "scum-simple-rcon-ue4ss", displayName: "SCUM Simple RCON UE4SS DLL", kind: "ue4ss-dll", activation: "server-start", version: "0.1.0-unpublished", releaseState: "unpublished", releaseHost: "cdn.npc0.com", releaseFilename: "scum_simple_rcon_ue4s.dll", supportedTargets: [{ os: "windows", arch: "amd64" }], updateOnStart: true }] }, status: "installed", source: "platform-registry" }; describe("PluginsPage", () => { it("renders the loading state before API data arrives", () => { const html = renderToStaticMarkup(); expect(html).toContain("插件市场"); expect(html).toContain("page-summary-chip"); expect(html).not.toContain("metric-card"); expect(html).toContain("正在加载插件市场"); }); it("renders API error state without falling back in production state", () => { const html = renderToStaticMarkup(); expect(html).toContain("插件市场加载失败"); expect(html).toContain("backend unavailable"); expect(html).not.toContain("本地演示数据仅用于前端开发"); }); it("renders API-backed plugin detail and state actions without unsafe fragments", () => { const html = renderToStaticMarkup( ); expect(html).toContain("Example Server"); expect(html).toContain("平台 API"); expect(html).toContain("logs.query"); expect(html).toContain("logs.diagnose"); expect(html).toContain("安装"); expect(html).toContain("启用"); expect(html).toContain("停用"); expect(html).toContain("SCUM Simple RCON UE4SS DLL"); expect(html).toContain("启动前自动校验和更新"); expect(html).toContain("运行:目标服务端受监管启动"); expect(html).toContain("Linux 启动前拒绝"); expect(html).toContain('role="dialog"'); expect(html).not.toContain("billing"); expect(html).not.toContain("/Users/"); expect(html).not.toContain("unix://"); expect(html).not.toContain("Bearer "); expect(html).not.toContain("sk-"); expect(html).not.toContain("password="); expect(html).not.toContain("apiKeyRef"); expect(html).not.toContain("ue4ss/Mods/"); }); it("keeps standalone fallback visibly isolated", () => { const html = renderToStaticMarkup( ); expect(html).toContain("本地演示数据"); expect(html).toContain("本地演示数据仅用于前端开发"); }); it("does not open a plugin detail pane until a plugin is selected", () => { const html = renderToStaticMarkup(); expect(html).toContain("Example Server"); expect(html).not.toContain('role="dialog"'); expect(html).not.toContain("manifest validated"); }); it("keeps state actions confirmed, permission-gated, and detail retryable", () => { expect(pluginsPageSource).toContain("ConfirmDialog"); expect(pluginsPageSource).toContain("retryDetail"); expect(pluginsPageSource).toContain("当前账号为只读模式"); expect(pluginsPageSource).toContain("平台会返回持久状态"); expect(pluginsPageSource).toContain("UE4SS DLL 声明"); expect(pluginsPageSource).toContain("actionPending !== null"); expect(pluginsPageSource).toContain("operations?.begin"); expect(pluginsPageSource).toContain("operations?.succeed"); expect(pluginsPageSource).toContain("operations?.fail"); }); });