99 lines
4.3 KiB
TypeScript
99 lines
4.3 KiB
TypeScript
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { describe, expect, it } from "vitest";
|
|
import hostSource from "./PluginPageHostPage.tsx?raw";
|
|
|
|
import type { GamePluginResponse } from "../api/types";
|
|
import type { PageComponentProps } from "../contracts/page";
|
|
import { capabilitiesForRoles } from "../contracts/workspace";
|
|
import type { OperationTracker } from "../stores/operations";
|
|
import { PluginPageHostPage } from "./PluginPageHostPage";
|
|
|
|
const operations: OperationTracker = {
|
|
operations: [],
|
|
begin: () => "operation-test",
|
|
update: () => undefined,
|
|
succeed: () => undefined,
|
|
fail: () => undefined,
|
|
isPending: () => false
|
|
};
|
|
|
|
const plugin: GamePluginResponse = {
|
|
id: "game.scum",
|
|
name: "SCUM Server",
|
|
version: "1.0.0",
|
|
serverType: "scum",
|
|
serverDisplayName: "SCUM Server",
|
|
manifestRef: "artifact://manifests/game.scum/1.0.0",
|
|
createFormSchemaRef: "schemas/create-form.schema.json",
|
|
requiredRunCapabilities: [],
|
|
declaredPermissions: ["server.read", "server.logs.read", "server.game-client.read", "server.game-client.command"],
|
|
permissions: { ai: false, logs: true, files: false, jobs: true, artifacts: false, remoteAccess: false },
|
|
lifecycleActions: {},
|
|
bridgeActions: ["server.instances.read", "logs.query"],
|
|
pages: [{
|
|
key: "files-config",
|
|
title: "文件与配置",
|
|
path: "/files-config",
|
|
bundleKey: "scum-server-plugin",
|
|
bundleVersion: "1.0.0",
|
|
bundleIntegritySha256: "sha256:8a4216107e1d7773d42a7e13b6466fd4fcf6e6bb2dc5f5af398fb7f4ea4f623b",
|
|
permissions: ["server.game-client.read", "server.game-client.command", "server.logs.read"],
|
|
bridgeActions: ["server.instances.read", "logs.query"]
|
|
}],
|
|
tags: ["scum"],
|
|
aiPurposes: [],
|
|
productionLifecycle: { operations: ["install", "enable", "disable", "upgrade", "rollback", "retire", "dependency-check"], dependencyPolicy: "required", approvalRequired: ["disable", "rollback", "retire"] },
|
|
gameClientBridge: {
|
|
commands: [{ type: "announcement.send", title: "Send announcement", permission: "server.game-client.command", approvalLevel: "operator", payloadSchemaRef: "schemas/bridge/announcement.json", timeoutSeconds: 30, maxPayloadBytes: 4096 }],
|
|
snapshots: [{ type: "companion.health", schemaVersion: "1", schemaRef: "schemas/bridge/health.json", keepForSeconds: 3600, maxRecords: 24 }],
|
|
commandRetentionSeconds: 86400,
|
|
maxCommands: 1000,
|
|
pages: [{ pageKey: "files-config", commandTypes: ["announcement.send"], snapshotTypes: ["companion.health"] }]
|
|
},
|
|
status: "installed"
|
|
};
|
|
|
|
function props(serverId = "server-1"): PageComponentProps {
|
|
const session = {
|
|
id: "operator-1",
|
|
displayName: "Operator",
|
|
status: "active" as const,
|
|
roles: ["platformAdmin" as const],
|
|
capabilities: capabilitiesForRoles(["platformAdmin"]),
|
|
profile: {},
|
|
source: "local" as const
|
|
};
|
|
return {
|
|
session,
|
|
params: { pluginId: "game.scum", routeKey: "files-config", serverId },
|
|
operations,
|
|
onNavigate: () => undefined,
|
|
onLogout: async () => undefined,
|
|
onProfileSave: async () => session,
|
|
onThemePreferenceSave: async () => ({ userId: session.id, paletteId: "mecha-black", backgroundPresetId: "mecha-grid", persistence: "api", updatedAt: "2026-07-20T00:00:00Z" })
|
|
};
|
|
}
|
|
|
|
describe("PluginPageHostPage", () => {
|
|
it("renders a generic manifest-owned bundle declaration", () => {
|
|
const html = renderToStaticMarkup(<PluginPageHostPage {...props()} initialPlugin={plugin} />);
|
|
expect(html).toContain("文件与配置");
|
|
expect(html).toContain("平台托管上下文");
|
|
expect(html).toContain("scum-server-plugin@1.0.0");
|
|
expect(html).toContain("完整性");
|
|
expect(html).toContain("返回服务器");
|
|
expect(html).not.toMatch(/sessionToken|componentKey|hostPath|dsn|runSocket|credential/i);
|
|
});
|
|
|
|
it("does not mount a bundle without client-side availability validation", () => {
|
|
const html = renderToStaticMarkup(<PluginPageHostPage {...props("")} initialPlugin={plugin} />);
|
|
expect(html).toContain("未绑定服务器");
|
|
expect(html).toContain("正在校验并加载插件页面 bundle");
|
|
});
|
|
|
|
it("remains a manifest-driven host without SCUM component imports or game branches", () => {
|
|
expect(hostSource).toContain("loadPluginPageBundle");
|
|
expect(hostSource).not.toMatch(/ScumFileConfigWorkbench|GamePlayerIntelligencePanel|GameGiftCatalogPanel|ScumMapTrajectoryPanel|game\.scum/);
|
|
});
|
|
});
|