Files
fusion/packages/dashboard/src/__tests__/routes-agent-export.test.ts
Fusion 19d62b41f5 refactor(FN-2162): rename kb-agent identifiers to fn-agent
- Rename core loader, dashboard server chat/planning routes, and frontend agent IDs/storage keys from kb-agent to fn-agent naming
- Update dashboard hooks and components (agent list, chat view, quick chat) to use the new fn agent key prefixes consistently
- Refresh engine, dashboard, core, and CLI tests/mocks to remove remaining kb-agent route and temp prefix references
- Update storage/gap-analysis docs to reflect fn agent key names and add a @gsxdsm/fusion patch changeset for the rename
2026-04-19 20:48:14 -07:00

157 lines
4.6 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { EventEmitter } from "node:events";
import { mkdtempSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { request } from "../test-request.js";
const mockInit = vi.fn().mockResolvedValue(undefined);
const mockListAgents = vi.fn().mockResolvedValue([]);
const mockExportAgentsToDirectory = vi.fn();
const mockChatStoreInit = vi.fn().mockResolvedValue(undefined);
vi.mock("@fusion/core", () => {
return {
AgentStore: class MockAgentStore {
init = mockInit;
listAgents = mockListAgents;
},
ChatStore: class MockChatStore {
init = mockChatStoreInit;
},
exportAgentsToDirectory: (...args: unknown[]) => mockExportAgentsToDirectory(...args),
};
});
class MockStore extends EventEmitter {
getRootDir(): string {
return "/tmp/fn-1190-test";
}
getFusionDir(): string {
return "/tmp/fn-1190-test/.fusion";
}
getDatabase() {
return {
exec: vi.fn(),
prepare: vi.fn().mockReturnValue({
run: vi.fn().mockReturnValue({ changes: 0 }),
get: vi.fn(),
all: vi.fn().mockReturnValue([]),
}),
};
}
}
async function postExport(app: Parameters<typeof request>[0], body: unknown) {
return request(app, "POST", "/api/agents/export", JSON.stringify(body), {
"content-type": "application/json",
});
}
describe("POST /api/agents/export", () => {
let store: MockStore;
let app: ReturnType<typeof import("../server.js").createServer>;
let testDir: string;
beforeEach(async () => {
vi.clearAllMocks();
testDir = mkdtempSync(join(tmpdir(), "fn-agent-export-route-"));
mockInit.mockResolvedValue(undefined);
mockListAgents.mockResolvedValue([
{
id: "agent-1",
name: "CEO",
role: "executor",
state: "idle",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
metadata: {},
},
{
id: "agent-2",
name: "Reviewer",
role: "reviewer",
state: "idle",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
metadata: {},
},
]);
mockExportAgentsToDirectory.mockResolvedValue({
outputDir: join(testDir, "export"),
agentsExported: 2,
skillsExported: 1,
filesWritten: [join(testDir, "export", "COMPANY.md")],
errors: [],
});
store = new MockStore();
const { createServer } = await import("../server.js");
app = createServer(store as any);
});
afterEach(() => {
vi.restoreAllMocks();
rmSync(testDir, { recursive: true, force: true });
});
it("exports all agents when agentIds is omitted", async () => {
const response = await postExport(app, {});
expect(response.status).toBe(200);
expect(mockExportAgentsToDirectory).toHaveBeenCalledTimes(1);
const [agentsArg, outputDirArg] = mockExportAgentsToDirectory.mock.calls[0] ?? [];
expect(agentsArg).toHaveLength(2);
expect(typeof outputDirArg).toBe("string");
const body = response.body as any;
expect(body.agentsExported).toBe(2);
expect(body.skillsExported).toBe(1);
});
it("exports only requested agent IDs", async () => {
const response = await postExport(app, { agentIds: ["agent-2"] });
expect(response.status).toBe(200);
const [agentsArg] = mockExportAgentsToDirectory.mock.calls[0] ?? [];
expect(agentsArg).toHaveLength(1);
expect(agentsArg[0]?.id).toBe("agent-2");
});
it("passes custom company options and output directory", async () => {
const customOutputDir = join(testDir, "custom-output");
const response = await postExport(app, {
companyName: "Acme AI",
companySlug: "acme-ai",
outputDir: customOutputDir,
});
expect(response.status).toBe(200);
const [, outputDirArg, optionsArg] = mockExportAgentsToDirectory.mock.calls[0] ?? [];
expect(outputDirArg).toBe(customOutputDir);
expect(optionsArg).toEqual({ companyName: "Acme AI", companySlug: "acme-ai" });
});
it("returns 400 when no agents are available", async () => {
mockListAgents.mockResolvedValue([]);
const response = await postExport(app, {});
expect(response.status).toBe(400);
expect((response.body as any).error).toContain("No agents found to export");
});
it("returns 400 for invalid outputDir type", async () => {
const response = await postExport(app, { outputDir: 123 });
expect(response.status).toBe(400);
expect((response.body as any).error).toContain("outputDir must be a string");
});
});