Files
boss/tests/device-import-candidate-id-regression.test.ts

142 lines
4.9 KiB
TypeScript

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";
import { NextRequest } from "next/server";
let runtimeRoot = "";
let createAuthSession: (typeof import("../src/lib/boss-data"))["createAuthSession"];
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let deviceHeartbeatRoute: (typeof import("../src/app/api/device-heartbeat/route"))["POST"];
let AUTH_SESSION_COOKIE = "";
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-device-import-candidate-id-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [heartbeatModule, data, auth] = await Promise.all([
import("../src/app/api/device-heartbeat/route.ts"),
import("../src/lib/boss-data.ts"),
import("../src/lib/boss-auth.ts"),
]);
deviceHeartbeatRoute = heartbeatModule.POST;
createAuthSession = data.createAuthSession;
readState = data.readState;
AUTH_SESSION_COOKIE = auth.AUTH_SESSION_COOKIE;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
async function createAuthedSessionCookie() {
const session = await createAuthSession({
account: "krisolo",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
return `${AUTH_SESSION_COOKIE}=${session.sessionToken}`;
}
test("auto-sync import keeps long-prefix project candidates distinct", async () => {
await setup();
const cookie = await createAuthedSessionCookie();
const state = await readState();
state.devices = [
{
id: "mac-studio",
name: "Mac Studio",
avatar: "M",
account: "krisolo",
source: "production",
status: "online",
projects: [],
quota5h: 68,
quota7d: 81,
lastSeenAt: "2026-04-03T10:00:00.000Z",
endpoint: "mac://kris.local",
token: "boss-mac-studio-token",
note: "本机 Codex 主节点",
},
];
const response = await deviceHeartbeatRoute(
new NextRequest("http://127.0.0.1:3000/api/device-heartbeat", {
method: "POST",
headers: {
"content-type": "application/json",
cookie,
},
body: JSON.stringify({
deviceId: "mac-studio",
token: "boss-mac-studio-token",
name: "Mac Studio",
avatar: "M",
account: "krisolo",
status: "online",
quota5h: 68,
quota7d: 81,
projects: [],
endpoint: "mac://kris.local",
projectCandidates: [
{
folderName: "AItoukui",
folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/AItoukui",
threadId: "019d4efb-3485-7b21-86dc-b70d3f4adf68",
threadDisplayName: "拉取代码并验证交接文档和本地启动状态",
codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/AItoukui",
codexThreadRef: "019d4efb-3485-7b21-86dc-b70d3f4adf68",
lastActiveAt: "2026-04-02T20:50:36.000Z",
suggestedImport: true,
},
{
folderName: "500Gcode",
folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode",
threadId: "019d4e19-1d27-77d3-bc54-2a1c80c7431b",
threadDisplayName: "本机运行3.5B模型并搭建Web演示",
codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode",
codexThreadRef: "019d4e19-1d27-77d3-bc54-2a1c80c7431b",
lastActiveAt: "2026-04-02T20:50:36.000Z",
suggestedImport: true,
},
{
folderName: "figma",
folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/figma",
threadId: "019d4e1d-03b8-7610-b427-c4ffd234aed4",
threadDisplayName: "配置Figma账号并启用UI制作Skill",
codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/figma",
codexThreadRef: "019d4e1d-03b8-7610-b427-c4ffd234aed4",
lastActiveAt: "2026-04-02T20:50:36.000Z",
suggestedImport: true,
},
],
}),
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
importDraft?: { candidates: Array<{ candidateId: string }>; appliedProjectNames: string[] };
};
const candidateIds = payload.importDraft?.candidates.map((candidate) => candidate.candidateId) ?? [];
assert.equal(new Set(candidateIds).size, 3);
const nextState = await readState();
const importedProjects = nextState.projects.filter((project) =>
["AItoukui", "500Gcode", "figma"].includes(project.threadMeta.folderName),
);
assert.equal(importedProjects.length, 3);
assert.deepEqual(
importedProjects.map((project) => project.threadMeta.folderName).sort(),
["500Gcode", "AItoukui", "figma"],
);
});