Files
boss/tests/device-detail-capabilities-route.test.ts
2026-04-06 14:09:46 +08:00

100 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm } from "node:fs/promises";
let runtimeRoot = "";
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let writeState: (typeof import("../src/lib/boss-data"))["writeState"];
let applyProjectConflictDecision: (typeof import("../src/lib/boss-data"))["applyProjectConflictDecision"];
let getDeviceWorkspaceView: (typeof import("../src/lib/boss-projections"))["getDeviceWorkspaceView"];
let buildDeviceWorkspaceDetailCards: (typeof import("../src/components/app-ui"))["buildDeviceWorkspaceDetailCards"];
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-device-detail-route-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [data, projections, ui] = await Promise.all([
import("../src/lib/boss-data.ts"),
import("../src/lib/boss-projections.ts"),
import("../src/components/app-ui.tsx"),
]);
readState = data.readState;
writeState = data.writeState;
applyProjectConflictDecision = data.applyProjectConflictDecision;
getDeviceWorkspaceView = projections.getDeviceWorkspaceView;
buildDeviceWorkspaceDetailCards = ui.buildDeviceWorkspaceDetailCards;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
test("device detail exposes gui cli capability state and preferred execution mode", async () => {
await setup();
const state = await readState();
const workspace = getDeviceWorkspaceView(state, "mac-studio");
const cards = buildDeviceWorkspaceDetailCards(workspace);
assert.equal(cards.capabilities.title, "执行能力");
assert.equal(cards.capabilities.items.gui, "GUI已连接");
assert.equal(cards.capabilities.items.cli, "CLI已连接");
assert.equal(cards.capabilities.items.preferredExecutionMode, "默认执行模式CLI");
});
test("device detail exposes folder and project conflict skeleton from workspace policy", async () => {
await setup();
const state = await readState();
state.projectExecutionPolicies = [
{
deviceId: "mac-studio",
folderKey: "mac-studio:boss",
projectId: "thread-ui",
allowPolicy: "allow_always",
conflictState: "warning",
updatedAt: "2026-04-06T12:00:00.000Z",
},
];
await writeState(state);
const workspace = getDeviceWorkspaceView(await readState(), "mac-studio");
const cards = buildDeviceWorkspaceDetailCards(workspace);
assert.equal(cards.conflicts.title, "异常项目 / 文件夹冲突");
assert.equal(cards.conflicts.headerHint, "已接入,可直接调整");
assert.equal(cards.conflicts.items.device, "设备Mac Studio");
assert.equal(cards.conflicts.items.folderKey, "文件夹mac-studio:boss");
assert.equal(cards.conflicts.items.projectId, "项目thread-ui");
assert.equal(cards.conflicts.items.allowPolicy, "当前策略:永久放行");
assert.equal(cards.conflicts.items.conflictState, "冲突态:存在并行风险");
});
test("device detail conflict card keeps project-scoped actions on the active folder only", async () => {
await setup();
await applyProjectConflictDecision({
deviceId: "mac-studio",
folderKey: "mac-studio:boss",
projectId: "thread-ui",
decision: "allow_once",
});
const workspace = getDeviceWorkspaceView(await readState(), "mac-studio");
const cards = buildDeviceWorkspaceDetailCards(workspace);
assert.equal(cards.conflicts.headerHint, "已接入,可直接调整");
assert.equal(cards.conflicts.items.allowPolicy, "当前策略:允许本次");
assert.equal(cards.conflicts.items.conflictState, "冲突态:存在并行风险");
assert.deepEqual(cards.conflicts.actions, ["禁止", "允许本次", "永久放行"]);
assert.equal(cards.conflicts.scopeLabel, "仅作用于当前异常项目 / 文件夹");
});