// Shared mocks/fixtures for AgentDetailView.*.test.tsx — see FN-4088 import { createElement } from "react"; import { vi } from "vitest"; import type { AgentCapability, AgentDetail } from "../../api"; type ApiModule = typeof import("../../api"); type SseModule = typeof import("../../sse-bus"); export const mockFetchAgent = vi.fn(); export const mockFetchAgents = vi.fn(); export const mockUpdateAgent = vi.fn(); export const mockUpdateAgentState = vi.fn(); export const mockDeleteAgent = vi.fn(); export const mockFetchAgentChildren = vi.fn(); export const mockFetchAgentRunLogs = vi.fn(); export const mockFetchAgentRuns = vi.fn(); export const mockFetchAgentRunDetail = vi.fn(); export const mockFetchAgentPromptSizes = vi.fn(); export const mockFetchAgentTasks = vi.fn(); export const mockFetchChainOfCommand = vi.fn(); export const mockFetchAgentBudgetStatus = vi.fn(); export const mockResetAgentBudget = vi.fn(); export const mockUpdateAgentInstructions = vi.fn(); export const mockUpdateAgentSoul = vi.fn(); export const mockUpdateAgentMemory = vi.fn(); export const mockFetchAgentMemoryFiles = vi.fn(); export const mockFetchAgentMemoryFile = vi.fn(); export const mockSaveAgentMemoryFile = vi.fn(); export const mockFetchWorkspaceFileContent = vi.fn(); export const mockSaveWorkspaceFileContent = vi.fn(); export const mockFetchDiscoveredSkills = vi.fn(); export const mockFetchSkillContent = vi.fn(); export const mockFetchModels = vi.fn(); export const mockFetchPluginRuntimes = vi.fn(); export const mockFetchAgentLogsWithMeta = vi.fn(); export const mockFetchAgentMailbox = vi.fn(); export const mockMarkMessageRead = vi.fn(); export const mockStartAgentRun = vi.fn(); export const mockUpgradeAgentHeartbeatProcedure = vi.fn(); export const mockUpdateGlobalSettings = vi.fn(); export const mockFetchCompanies = vi.fn(); export const mockFetchSettingsByScope = vi.fn(); export const mockSubscribeSse = vi.fn(); export const mockConfirm = vi.fn(); export const MOCK_SKILLS = [ { id: "skill-1", name: "Skill One", path: "/path/skill-1", relativePath: "skills/skill-1", enabled: true, metadata: { source: "*", scope: "user" as const, origin: "top-level" as const } }, { id: "skill-2", name: "Skill Two", path: "/path/skill-2", relativePath: "skills/skill-2", enabled: true, metadata: { source: "*", scope: "user" as const, origin: "top-level" as const } }, ]; vi.mock("../../api", () => ({ fetchAgent: (...args: Parameters) => mockFetchAgent(...args), fetchAgents: (...args: Parameters) => mockFetchAgents(...args), updateAgent: (...args: Parameters) => mockUpdateAgent(...args), updateAgentState: (...args: Parameters) => mockUpdateAgentState(...args), deleteAgent: (...args: Parameters) => mockDeleteAgent(...args), fetchAgentLogs: vi.fn(), fetchAgentLogsWithMeta: (...args: Parameters) => mockFetchAgentLogsWithMeta(...args), fetchAgentMailbox: (...args: Parameters) => mockFetchAgentMailbox(...args), markMessageRead: (...args: Parameters) => mockMarkMessageRead(...args), fetchAgentRunLogs: (...args: Parameters) => mockFetchAgentRunLogs(...args), fetchAgentChildren: (...args: Parameters) => mockFetchAgentChildren(...args), fetchAgentRuns: (...args: Parameters) => mockFetchAgentRuns(...args), fetchAgentRunDetail: (...args: Parameters) => mockFetchAgentRunDetail(...args), fetchAgentPromptSizes: (...args: Parameters) => mockFetchAgentPromptSizes(...args), startAgentRun: (...args: Parameters) => mockStartAgentRun(...args), stopAgentRun: vi.fn(), updateAgentInstructions: (...args: Parameters) => mockUpdateAgentInstructions(...args), updateAgentSoul: (...args: Parameters) => mockUpdateAgentSoul(...args), updateAgentMemory: (...args: Parameters) => mockUpdateAgentMemory(...args), fetchAgentMemoryFiles: (...args: Parameters) => mockFetchAgentMemoryFiles(...args), fetchAgentMemoryFile: (...args: Parameters) => mockFetchAgentMemoryFile(...args), saveAgentMemoryFile: (...args: Parameters) => mockSaveAgentMemoryFile(...args), fetchAgentTasks: (...args: Parameters) => mockFetchAgentTasks(...args), fetchChainOfCommand: (...args: Parameters) => mockFetchChainOfCommand(...args), fetchAgentBudgetStatus: (...args: Parameters) => mockFetchAgentBudgetStatus(...args), resetAgentBudget: (...args: Parameters) => mockResetAgentBudget(...args), fetchWorkspaceFileContent: (...args: Parameters) => mockFetchWorkspaceFileContent(...args), saveWorkspaceFileContent: (...args: Parameters) => mockSaveWorkspaceFileContent(...args), fetchDiscoveredSkills: (...args: Parameters) => mockFetchDiscoveredSkills(...args), fetchSkillContent: (...args: Parameters) => mockFetchSkillContent(...args), fetchModels: (...args: Parameters) => mockFetchModels(...args), fetchPluginRuntimes: (...args: Parameters) => mockFetchPluginRuntimes(...args), upgradeAgentHeartbeatProcedure: (...args: Parameters) => mockUpgradeAgentHeartbeatProcedure(...args), updateGlobalSettings: (...args: Parameters) => mockUpdateGlobalSettings(...args), fetchCompanies: (...args: Parameters) => mockFetchCompanies(...args), fetchSettingsByScope: (...args: Parameters) => mockFetchSettingsByScope(...args), uploadAgentAvatar: vi.fn(), deleteAgentAvatar: vi.fn(), })); vi.mock("../AgentLogViewer", () => ({ AgentLogViewer: ({ entries }: { entries: Array<{ text: string; detail?: string }> }) => createElement( "div", { "data-testid": "agent-log-viewer" }, ...entries.map((e, i) => createElement( "div", { key: i }, createElement("span", null, e.text), e.detail ? createElement( "button", { type: "button", "data-testid": "tool-detail-toggle", "aria-expanded": "false" }, "Show output", ) : null, )), ), })); vi.mock("../CustomModelDropdown", () => ({ CustomModelDropdown: ({ models, value, onChange, disabled, label, placeholder, id, favoriteProviders = [], favoriteModels = [] }: { models: Array<{ provider: string; id: string }>; value: string; onChange: (v: string) => void; disabled?: boolean; label: string; placeholder?: string; id?: string; favoriteProviders?: string[]; onToggleFavorite?: (provider: string) => void; favoriteModels?: string[]; onToggleModelFavorite?: (modelId: string) => void; }) => { const selectId = id ?? "custom-model-dropdown"; return createElement( "div", { "data-testid": "custom-model-dropdown", "data-favorite-providers": favoriteProviders.join(","), "data-favorite-models": favoriteModels.join(","), }, createElement("label", { htmlFor: selectId }, label), createElement( "select", { id: selectId, "aria-label": label, value, disabled, onChange: (e: Event) => onChange((e.target as HTMLSelectElement).value), }, createElement("option", { value: "" }, placeholder ?? "Use default"), ...models.map((model) => { const modelValue = `${model.provider}/${model.id}`; return createElement("option", { key: modelValue, value: modelValue }, modelValue); }), ), ); }, })); vi.mock("../SkillMultiselect", () => ({ SkillMultiselect: ({ value, onChange, id: _id }: { value: string[]; onChange: (v: string[]) => void; id?: string }) => createElement( "div", { "data-testid": "skill-multiselect" }, createElement("span", { "data-testid": "skill-multiselect-value" }, JSON.stringify(value)), createElement("button", { "data-testid": "add-skill-test", onClick: () => onChange([...value, "test-skill"]) }, "Add Test Skill"), createElement("button", { "data-testid": "remove-skill-test", onClick: () => onChange(value.filter((s) => s !== "test-skill")) }, "Remove Test Skill"), ), })); vi.mock("../ExperimentalAgentOnboardingModal", () => ({ ExperimentalAgentOnboardingModal: ({ isOpen, mode, existingAgentConfig, onUseDraft, onClose }: { isOpen: boolean; mode?: "create" | "edit"; existingAgentConfig?: Record; onUseDraft: (summary: any) => void; onClose: () => void; }) => (isOpen ? createElement( "div", { "data-testid": "mock-ai-interview-modal" }, createElement("span", { "data-testid": "mock-ai-interview-mode" }, mode), createElement( "button", { type: "button", onClick: () => onUseDraft({ name: "Interviewed Agent", role: "reviewer", title: "Draft Title", icon: "🧠", reportsTo: "agent-002", instructionsText: "Updated instructions", soul: "Updated soul", memory: "Updated memory", skills: ["skill-1"], thinkingLevel: "high", maxTurns: 12, model: "openai/gpt-4o", }), }, "Apply Draft", ), createElement("button", { type: "button", onClick: onClose }, "Close Modal"), createElement("pre", { "data-testid": "mock-ai-existing-config" }, JSON.stringify(existingAgentConfig ?? {})), ) : null), })); vi.mock("../../sse-bus", () => ({ subscribeSse: (...args: Parameters) => mockSubscribeSse(...args), })); vi.mock("../../hooks/useConfirm", () => ({ useConfirm: () => ({ confirm: mockConfirm }), })); export const createMockAgent = (overrides: Partial = {}): AgentDetail => ({ id: "agent-001", name: "Test Agent", role: "executor" as AgentCapability, state: "active", taskId: "FN-001", createdAt: "2024-01-01T00:00:00.000Z", updatedAt: "2024-01-01T00:00:00.000Z", lastHeartbeatAt: "2024-01-01T00:05:00.000Z", metadata: {}, runtimeConfig: overrides.runtimeConfig, heartbeatHistory: [], activeRun: { id: "run-001", agentId: "agent-001", startedAt: "2024-01-01T00:00:00.000Z", endedAt: null, status: "active", }, completedRuns: [ { id: "run-002", agentId: "agent-001", startedAt: "2023-12-31T00:00:00.000Z", endedAt: "2023-12-31T00:05:00.000Z", status: "completed", }, ], ...overrides, }) as AgentDetail; export function setupAgentDetailMocks() { vi.clearAllMocks(); mockConfirm.mockReset(); mockConfirm.mockResolvedValue(true); mockSubscribeSse.mockReset(); mockSubscribeSse.mockReturnValue(vi.fn()); const mockAgent = createMockAgent(); mockFetchAgent.mockResolvedValue(mockAgent); mockStartAgentRun.mockResolvedValue({ id: "run-003" } as any); mockFetchAgents.mockResolvedValue([ { id: "agent-001", name: "Test Agent", role: "executor", state: "active", metadata: {} }, { id: "agent-002", name: "Manager Agent", role: "reviewer", state: "active", metadata: {} }, { id: "agent-003", name: "Director Agent", role: "triage", state: "active", metadata: {} }, ] as any); mockUpdateAgentState.mockResolvedValue(createMockAgent({ state: "paused" })); mockDeleteAgent.mockResolvedValue(undefined); mockUpdateAgent.mockResolvedValue(createMockAgent() as any); mockFetchAgentRuns.mockResolvedValue([ ...(mockAgent.activeRun ? [mockAgent.activeRun] : []), ...mockAgent.completedRuns, ]); mockFetchAgentRunLogs.mockResolvedValue([]); mockFetchAgentRunDetail.mockResolvedValue(mockAgent.completedRuns[0]); mockFetchAgentPromptSizes.mockResolvedValue([]); mockFetchAgentChildren.mockResolvedValue([]); mockFetchAgentTasks.mockResolvedValue([]); mockFetchChainOfCommand.mockResolvedValue([mockAgent]); mockFetchAgentLogsWithMeta.mockResolvedValue({ entries: [], total: 0, hasMore: false }); mockFetchAgentMailbox.mockResolvedValue({ ownerId: "agent-001", ownerType: "agent", unreadCount: 0, messages: [], inbox: [], outbox: [], }); mockMarkMessageRead.mockResolvedValue({ id: "msg-default", fromId: "dashboard", fromType: "user", toId: "agent-001", toType: "agent", content: "", type: "user-to-agent", read: true, createdAt: "2024-01-01T00:00:00.000Z", updatedAt: "2024-01-01T00:00:00.000Z", } as any); mockStartAgentRun.mockResolvedValue({ id: "run-003" } as any); mockFetchAgentBudgetStatus.mockResolvedValue({ agentId: "agent-001", currentUsage: 0, budgetLimit: null, usagePercent: null, thresholdPercent: null, isOverBudget: false, isOverThreshold: false, lastResetAt: null, nextResetAt: null, }); mockResetAgentBudget.mockResolvedValue(undefined); mockFetchWorkspaceFileContent.mockResolvedValue({ content: "", mtime: "2024-01-01T00:00:00.000Z", size: 0 }); mockSaveWorkspaceFileContent.mockResolvedValue({ success: true, mtime: "2024-01-01T00:00:00.000Z", size: 0 }); mockUpdateAgentInstructions.mockResolvedValue({} as any); mockFetchAgentMemoryFiles.mockResolvedValue({ files: [ { path: ".fusion/agent-memory/agent-001/MEMORY.md", label: "MEMORY.md", layer: "long-term", size: 12, updatedAt: "2024-01-01T00:00:00.000Z", }, ], } as any); mockFetchAgentMemoryFile.mockResolvedValue({ path: ".fusion/agent-memory/agent-001/MEMORY.md", content: "", } as any); mockSaveAgentMemoryFile.mockResolvedValue({ success: true } as any); mockFetchDiscoveredSkills.mockResolvedValue(MOCK_SKILLS); mockFetchSkillContent.mockResolvedValue({ name: "Skill", skillMd: "# Skill", files: [] }); mockFetchModels.mockResolvedValue({ models: [ { provider: "openai", id: "gpt-4o", name: "gpt-4o", reasoning: false, contextWindow: 128000 }, { provider: "anthropic", id: "claude-3-7-sonnet", name: "claude-3-7-sonnet", reasoning: true, contextWindow: 200000 }, ], favoriteProviders: [], favoriteModels: [], }); mockFetchPluginRuntimes.mockResolvedValue([ { pluginId: "fusion-plugin-openclaw-runtime", runtimeId: "openclaw", name: "OpenClaw", description: "OpenClaw runtime", version: "1.0.0" }, { pluginId: "fusion-plugin-hermes-runtime", runtimeId: "hermes", name: "Hermes", description: "Hermes runtime", version: "1.1.0" }, ]); mockUpgradeAgentHeartbeatProcedure.mockResolvedValue({ heartbeatProcedurePath: ".fusion/agents/agent-001/HEARTBEAT.md", procedureFileSeeded: true, }); mockUpdateGlobalSettings.mockResolvedValue({} as any); mockFetchCompanies.mockResolvedValue({ companies: [] }); mockFetchSettingsByScope.mockResolvedValue({ global: {}, project: {} } as any); }