/** * Tests for server/seed.ts * * Strategy: mock `./db` so getDb() returns a fake Drizzle-like object, * then assert that seedDefaults() inserts exactly the right agents * (or skips when agents already exist). */ import { describe, it, expect, vi, beforeEach } from "vitest"; import { DEFAULT_AGENTS, seedDefaults } from "./seed"; // ─── Mock getDb ─────────────────────────────────────────────────────────────── const mockInsert = vi.fn(); const mockSelect = vi.fn(); vi.mock("./db", () => ({ getDb: vi.fn(), })); import { getDb } from "./db"; // Helper: build a minimal fake db that tracks inserts and returns a given count function makeFakeDb(existingAgentCount: number) { const insertValues = vi.fn().mockResolvedValue([{ insertId: 1 }]); const insertInto = vi.fn().mockReturnValue({ values: insertValues }); // select().from(). → [{ value: count }] const fromFn = vi.fn().mockResolvedValue([{ value: existingAgentCount }]); const selectFn = vi.fn().mockReturnValue({ from: fromFn }); return { insert: insertInto, select: selectFn, _insertValues: insertValues, _fromFn: fromFn, }; } // ─── Tests ──────────────────────────────────────────────────────────────────── describe("DEFAULT_AGENTS", () => { it("should contain exactly 6 default agents", () => { expect(DEFAULT_AGENTS).toHaveLength(6); }); it("should have exactly one orchestrator agent", () => { const orchestrators = DEFAULT_AGENTS.filter((a) => a.isOrchestrator); expect(orchestrators).toHaveLength(1); expect(orchestrators[0].name).toBe("GoClaw Orchestrator"); }); it("should mark all agents as system agents", () => { const nonSystem = DEFAULT_AGENTS.filter((a) => !a.isSystem); expect(nonSystem).toHaveLength(0); }); it("should have unique roles", () => { const roles = DEFAULT_AGENTS.map((a) => a.role); const uniqueRoles = new Set(roles); expect(uniqueRoles.size).toBe(roles.length); }); it("each agent should have allowedTools array", () => { for (const agent of DEFAULT_AGENTS) { expect(Array.isArray(agent.allowedTools)).toBe(true); expect(agent.allowedTools.length).toBeGreaterThan(0); } }); it("orchestrator should have the most tools", () => { const orch = DEFAULT_AGENTS.find((a) => a.isOrchestrator)!; const maxTools = Math.max(...DEFAULT_AGENTS.map((a) => a.allowedTools.length)); expect(orch.allowedTools.length).toBe(maxTools); }); it("each agent should have a non-empty systemPrompt", () => { for (const agent of DEFAULT_AGENTS) { expect(agent.systemPrompt.trim().length).toBeGreaterThan(50); } }); it("each agent should have valid temperature (0-1 as string)", () => { for (const agent of DEFAULT_AGENTS) { const temp = parseFloat(agent.temperature); expect(temp).toBeGreaterThanOrEqual(0); expect(temp).toBeLessThanOrEqual(1); } }); it("each agent should have maxTokens > 0", () => { for (const agent of DEFAULT_AGENTS) { expect(agent.maxTokens).toBeGreaterThan(0); } }); it("orchestrator should have the highest maxTokens", () => { const orch = DEFAULT_AGENTS.find((a) => a.isOrchestrator)!; const maxTok = Math.max(...DEFAULT_AGENTS.map((a) => a.maxTokens)); expect(orch.maxTokens).toBe(maxTok); }); it("each agent should have seeded metadata flag", () => { for (const agent of DEFAULT_AGENTS) { expect(agent.metadata.seeded).toBe(true); } }); }); describe("seedDefaults()", () => { beforeEach(() => { vi.clearAllMocks(); }); it("should skip seeding when DB is unavailable", async () => { vi.mocked(getDb).mockResolvedValue(null as any); await expect(seedDefaults()).resolves.toBeUndefined(); // No inserts should happen expect(mockInsert).not.toHaveBeenCalled(); }); it("should skip seeding when agents already exist", async () => { const fakeDb = makeFakeDb(3); // 3 agents already exist vi.mocked(getDb).mockResolvedValue(fakeDb as any); await seedDefaults(); // select was called to check count expect(fakeDb.select).toHaveBeenCalled(); // insert was NOT called expect(fakeDb.insert).not.toHaveBeenCalled(); }); it("should insert all default agents when table is empty", async () => { const fakeDb = makeFakeDb(0); // empty table vi.mocked(getDb).mockResolvedValue(fakeDb as any); await seedDefaults(); // insert should be called once per agent expect(fakeDb.insert).toHaveBeenCalledTimes(DEFAULT_AGENTS.length); expect(fakeDb._insertValues).toHaveBeenCalledTimes(DEFAULT_AGENTS.length); }); it("should insert orchestrator agent with isOrchestrator=true", async () => { const fakeDb = makeFakeDb(0); vi.mocked(getDb).mockResolvedValue(fakeDb as any); await seedDefaults(); // Find the call that inserted the orchestrator const calls = fakeDb._insertValues.mock.calls; const orchCall = calls.find((call: any[]) => call[0]?.isOrchestrator === true); expect(orchCall).toBeDefined(); expect(orchCall![0].isSystem).toBe(true); expect(orchCall![0].name).toBe("GoClaw Orchestrator"); }); it("should insert all agents with isSystem=true", async () => { const fakeDb = makeFakeDb(0); vi.mocked(getDb).mockResolvedValue(fakeDb as any); await seedDefaults(); const calls = fakeDb._insertValues.mock.calls; for (const call of calls) { expect(call[0].isSystem).toBe(true); } }); it("should be idempotent — second call with existing data does nothing", async () => { // First call: empty DB → seeds const fakeDb1 = makeFakeDb(0); vi.mocked(getDb).mockResolvedValue(fakeDb1 as any); await seedDefaults(); expect(fakeDb1.insert).toHaveBeenCalledTimes(DEFAULT_AGENTS.length); // Second call: DB now has agents → skips const fakeDb2 = makeFakeDb(DEFAULT_AGENTS.length); vi.mocked(getDb).mockResolvedValue(fakeDb2 as any); await seedDefaults(); expect(fakeDb2.insert).not.toHaveBeenCalled(); }); it("should not throw when DB insert fails — just log error", async () => { const fakeDb = makeFakeDb(0); // Make insert throw fakeDb._insertValues.mockRejectedValue(new Error("DB error")); vi.mocked(getDb).mockResolvedValue(fakeDb as any); // Should not throw await expect(seedDefaults()).resolves.toBeUndefined(); }); });