refactor(scum): remove legacy projection workflows
This commit is contained in:
@@ -7,122 +7,31 @@ import { renderPluginPage } from "../examples/scum-server-plugin/page-bundle/ind
|
||||
import { configurationCatalog, validateConfigPatch } from "../examples/scum-server-plugin/features/schemas.js";
|
||||
|
||||
const pageSource = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../examples/scum-server-plugin/features/page.ts"), "utf8");
|
||||
const projectionData = {
|
||||
players: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", userProfileId: "profile-1", displayName: "Mira", squadName: "Wolves", online: true, famePoints: 42, normalBalance: 1000, goldBalance: 3, position: { x: 10, y: 20, z: 3, hasCoordinates: true }, freshness: { status: "fresh" } }],
|
||||
squads: [{ squadId: "squad-1", name: "Wolves", memberCount: 3, leaderProfileId: "profile-1", freshness: { status: "fresh" } }],
|
||||
members: [{ gamePlayerId: "steam-1", displayName: "Mira", squadId: "squad-1", rank: "Leader", freshness: { status: "fresh" } }],
|
||||
vehicles: [{ vehicleId: "veh-1", label: "Laika", position: { subjectType: "vehicle", subjectId: "veh-1", x: 400, y: 200, z: 0, hasCoordinates: true }, freshness: { status: "fresh" } }],
|
||||
flags: [{ flagId: "flag-1", ownerSquadId: "squad-1", ownershipConfidence: "verified", position: { subjectType: "flag", subjectId: "flag-1", x: 100, y: 80, z: 0, hasCoordinates: true }, freshness: { status: "fresh" } }],
|
||||
positions: [{ subjectType: "player", subjectId: "steam-1", gamePlayerId: "steam-1", x: 10, y: 20, z: 3, hasCoordinates: true, freshness: { status: "fresh" } }]
|
||||
};
|
||||
|
||||
describe("SCUM plugin feature module", () => {
|
||||
it("owns runtime allowlists without a version gate", () => {
|
||||
expect(configurationCatalog.map((field) => field.key)).toContain("welcome-message");
|
||||
expect(validateConfigPatch({ reason: "adjust capacity", idempotencyKey: "cfg-1", changes: [{ key: "max-players", value: "129" }] })).toContain("超出允许范围");
|
||||
expect(validateConfigPatch({ reason: "adjust capacity", idempotencyKey: "cfg-2", changes: [{ key: "unknown", value: "1" }] })).toContain("受控目录");
|
||||
});
|
||||
|
||||
it("renders local user management without projection or fake-write controls", () => {
|
||||
const view = renderAndCollect();
|
||||
it("keeps the five management pages free of legacy snapshot reads and fake controls", () => {
|
||||
for (const pageKey of ["players", "squads", "live-map", "gifts", "workflows"]) {
|
||||
const view = renderAndCollect(pageKey);
|
||||
expect(view.texts.join("\n")).toContain("不会读取遗留快照");
|
||||
}
|
||||
for (const removed of ["listSCUM", "map-local-board", "Fame +100", "starter-pack", "855", "Workflow", "投影"]) expect(pageSource).not.toContain(removed);
|
||||
});
|
||||
|
||||
it("falls legacy routes back to user management", () => {
|
||||
const view = renderAndCollect("workflows");
|
||||
expect(view.nodes).toContain("section:用户管理");
|
||||
expect(view.texts.join("\n")).toContain("登录日志和已验证同步结果");
|
||||
expect(view.texts).toContain("本地数据通道可读");
|
||||
expect(view.buttons.find((button) => button.label === "重试本地读取")?.disabled).toBe(false);
|
||||
expect(view.texts).toContain("Mira");
|
||||
expect(view.texts.join("\n")).toContain("Steam 76561198000000001");
|
||||
expect(view.texts.join("\n")).toContain("Profile profile-1");
|
||||
expect(view.texts.join("\n")).toContain("Fame 42");
|
||||
expect(view.buttons.map((button) => button.label)).not.toEqual(expect.arrayContaining(["Fame +100", "现金 +1000", "855 审批"]));
|
||||
for (const removedText of ["ServerSettings.ini", "Game.ini", "配置表单", "键值视图", "原文模式", "读取文件", "提交写入"]) expect(view.texts.join("\n")).not.toContain(removedText);
|
||||
});
|
||||
|
||||
it("does not invent fake players when local records are empty", () => {
|
||||
const view = renderAndCollect({ data: { ...projectionData, players: [], positions: [] } });
|
||||
expect(view.texts.join("\n")).toContain("暂无玩家记录");
|
||||
expect(view.texts.join("\n")).toContain("登录日志或已完成的本地同步");
|
||||
expect(view.texts).not.toContain("Mira");
|
||||
expect(pageSource).not.toContain("fallbackFiles");
|
||||
expect(pageSource).not.toContain("samplePlayers");
|
||||
});
|
||||
|
||||
it("renders squad and flag governance from local records", () => {
|
||||
const view = renderAndCollect({ pageKey: "squads", pageTitle: "队伍管理" });
|
||||
expect(view.nodes).toContain("section:队伍管理");
|
||||
expect(view.texts).toContain("队伍");
|
||||
expect(view.texts).toContain("成员 / 旗帜");
|
||||
expect(view.texts).toContain("Wolves");
|
||||
expect(view.texts.join("\n")).toContain("成员 3");
|
||||
expect(view.texts.join("\n")).toContain("verified");
|
||||
});
|
||||
|
||||
it("renders realtime map overlays without sample coordinates or arbitrary fallback points", () => {
|
||||
const view = renderAndCollect({ pageKey: "live-map", pageTitle: "实时地图" });
|
||||
expect(view.nodes).toContain("section:实时地图");
|
||||
expect(view.texts).toContain("地图覆盖物");
|
||||
expect(view.texts.join("\n")).toContain("坐标点");
|
||||
expect(view.texts.join("\n")).toContain("X 10 / Y 20 / Z 3");
|
||||
expect(pageSource).toContain("map-local-board");
|
||||
expect(pageSource).not.toContain("sampleCoordinates");
|
||||
});
|
||||
|
||||
it("renders gift management without hard-coded delivery actions", () => {
|
||||
const gifts = renderAndCollect({ pageKey: "gifts", pageTitle: "礼包管理" });
|
||||
expect(gifts.nodes).toContain("section:礼包管理");
|
||||
expect(gifts.texts.join("\n")).toContain("本地礼包接口");
|
||||
expect(gifts.buttons.map((button) => button.label)).not.toEqual(expect.arrayContaining(["创建礼包发放", "发送通知"]));
|
||||
expect(pageSource).not.toContain("starter-pack");
|
||||
});
|
||||
|
||||
it("falls legacy workflow routes back to user management", () => {
|
||||
const legacy = renderAndCollect({ pageKey: "workflows" });
|
||||
expect(legacy.nodes).toContain("section:用户管理");
|
||||
expect(legacy.texts.join("\n")).not.toContain("scum.world-refresh");
|
||||
});
|
||||
|
||||
it("loads local SCUM resources without write or workflow workspace actions", () => {
|
||||
expect(pageSource).toContain("listSCUMPlayers");
|
||||
expect(pageSource).not.toContain("createSCUMOperation");
|
||||
expect(pageSource).not.toContain("createSCUMWorkflow");
|
||||
expect(pageSource).not.toContain("getFileSnapshot");
|
||||
expect(pageSource).not.toContain("requestFile");
|
||||
expect(pageSource).not.toContain("writeFile");
|
||||
expect(pageSource).not.toContain("setInterval");
|
||||
});
|
||||
});
|
||||
|
||||
function renderAndCollect(options: { data?: typeof projectionData; permissions?: string[]; pageKey?: string; pageTitle?: string } = {}) {
|
||||
const nodes: string[] = [];
|
||||
const texts: string[] = [];
|
||||
const buttons: Array<{ label: string; disabled: boolean }> = [];
|
||||
const collectText = (value: unknown): void => { if (typeof value === "string") texts.push(value); else if (Array.isArray(value)) value.forEach(collectText); else if (value && typeof value === "object" && "children" in value) collectText((value as { children?: unknown }).children); };
|
||||
let stateCall = 0;
|
||||
const react = {
|
||||
createElement: (type: unknown, props: Record<string, unknown> | null, ...children: unknown[]) => {
|
||||
if (typeof type === "string") nodes.push(`${type}:${String(props?.["aria-label"] ?? "")}`);
|
||||
children.forEach(collectText);
|
||||
if (type === "button") buttons.push({ label: String(children[0]), disabled: Boolean(props?.disabled) });
|
||||
return { type, props, children };
|
||||
},
|
||||
useEffect: () => undefined,
|
||||
useState: <T,>(initial: T | (() => T)): [T, (next: T | ((previous: T) => T)) => void] => {
|
||||
stateCall += 1;
|
||||
if (stateCall === 1) return [{ status: "ready", data: options.data ?? projectionData } as T, () => undefined];
|
||||
return [typeof initial === "function" ? (initial as () => T)() : initial, () => undefined];
|
||||
}
|
||||
};
|
||||
renderPluginPage(react, {
|
||||
page: { key: options.pageKey ?? "players", title: options.pageTitle ?? "用户管理" },
|
||||
context: { serverInstanceId: "server-1", permissions: options.permissions ?? ["server.game-client.read", "server.game-client.command", "server.game-client.maintenance"] },
|
||||
availability: { available: true, features: [{ key: "player.intelligence", available: true }] },
|
||||
workspaceActions: {
|
||||
listSCUMPlayers: async () => ({ items: projectionData.players, count: projectionData.players.length }),
|
||||
listSCUMSquads: async () => ({ items: projectionData.squads, count: projectionData.squads.length }),
|
||||
listSCUMSquadMembers: async () => ({ items: projectionData.members, count: projectionData.members.length }),
|
||||
listSCUMVehicles: async () => ({ items: projectionData.vehicles, count: projectionData.vehicles.length }),
|
||||
listSCUMFlags: async () => ({ items: projectionData.flags, count: projectionData.flags.length }),
|
||||
listSCUMPositions: async () => ({ items: projectionData.positions, count: projectionData.positions.length })
|
||||
}
|
||||
});
|
||||
return { nodes, texts, buttons };
|
||||
function renderAndCollect(pageKey: string) {
|
||||
const nodes: string[] = []; const texts: string[] = [];
|
||||
const collect = (value: unknown): void => { if (typeof value === "string") texts.push(value); else if (Array.isArray(value)) value.forEach(collect); else if (value && typeof value === "object" && "children" in value) collect((value as { children?: unknown }).children); };
|
||||
const react = { createElement: (type: unknown, props: Record<string, unknown> | null, ...children: unknown[]) => { if (typeof type === "string") nodes.push(`${type}:${String(props?.["aria-label"] ?? "")}`); children.forEach(collect); return { type, props, children }; } };
|
||||
renderPluginPage(react, { page: { key: pageKey, title: pageKey === "squads" ? "队伍管理" : pageKey === "live-map" ? "实时地图" : pageKey === "gifts" ? "礼包管理" : "用户管理" }, context: { serverInstanceId: "server-1", permissions: ["server.game-client.read"] }, availability: { available: false, reason: "等待当前服务器完成兼容性验证。" } });
|
||||
return { nodes, texts };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user