tool-handlers.test.ts•6.91 kB
import { jest, describe, it, expect, beforeEach } from "@jest/globals";
import type { CallToolRequest } from "@modelcontextprotocol/sdk/types.js";
import { handleToolCall } from "../tool-handlers.js";
import type {
  SystempromptPromptResponse,
  SystempromptUserStatusResponse,
  SystempromptBlockResponse,
  SystempromptAgentResponse,
} from "../../types/systemprompt.js";
// Mock the server config
jest.mock("../../config/server-config.js", () => ({
  serverConfig: {
    port: 3000,
    host: "localhost",
  },
  serverCapabilities: {
    tools: [],
  },
}));
// Mock the main function
jest.mock("../../index.ts", () => ({
  main: jest.fn(),
  server: {
    notification: jest.fn().mockImplementation(async () => {}),
  },
}));
// Mock the sampling module
jest.mock("../sampling.js", () => ({
  sendSamplingRequest: jest.fn().mockImplementation(async () => ({
    content: [
      {
        type: "text",
        text: JSON.stringify({ metadata: { title: "Test", description: "Test" }, content: "Test" }),
      },
    ],
  })),
}));
// Mock SystemPromptService
const mockUserStatus: SystempromptUserStatusResponse = {
  user: {
    id: "user123",
    uuid: "uuid123",
    name: "Test User",
    email: "test@example.com",
    roles: ["user"],
    paddle_id: "paddle123",
  },
  content: {
    prompt: 0,
    artifact: 0,
    block: 0,
    conversation: 0,
  },
  usage: {
    ai: {
      execution: 0,
      token: 0,
    },
    api: {
      generation: 0,
    },
  },
  billing: {
    customer: {
      id: "cust123",
      name: null,
      email: "test@example.com",
      marketingConsent: false,
      status: "active",
      customData: null,
      locale: "en",
      createdAt: {
        date: "2024-01-01T00:00:00Z",
        timezone_type: 3,
        timezone: "UTC",
      },
      updatedAt: {
        date: "2024-01-01T00:00:00Z",
        timezone_type: 3,
        timezone: "UTC",
      },
      importMeta: null,
    },
    subscription: [
      {
        id: "sub123",
        status: "active",
        currency_code: "USD",
        billing_cycle: {
          frequency: 1,
          interval: "month",
        },
        current_billing_period: {
          starts_at: "2024-01-01",
          ends_at: "2024-02-01",
        },
        items: [
          {
            product: { name: "Test Product" },
            price: {
              unit_price: { amount: "10.00", currency_code: "USD" },
            },
          },
        ],
      },
    ],
  },
  api_key: "test-api-key",
};
interface MockSystemPromptService {
  fetchUserStatus: () => Promise<SystempromptUserStatusResponse>;
  getAllPrompts: () => Promise<SystempromptPromptResponse[]>;
  listBlocks: () => Promise<SystempromptBlockResponse[]>;
  listAgents: () => Promise<SystempromptAgentResponse[]>;
  deletePrompt: (id: string) => Promise<void>;
  deleteBlock: (id: string) => Promise<void>;
}
const mockSystemPromptService = {
  fetchUserStatus: jest
    .fn<() => Promise<SystempromptUserStatusResponse>>()
    .mockResolvedValue(mockUserStatus),
  getAllPrompts: jest.fn<() => Promise<SystempromptPromptResponse[]>>().mockResolvedValue([]),
  listBlocks: jest.fn<() => Promise<SystempromptBlockResponse[]>>().mockResolvedValue([]),
  listAgents: jest.fn<() => Promise<SystempromptAgentResponse[]>>().mockResolvedValue([]),
  deletePrompt: jest.fn<() => Promise<void>>().mockResolvedValue(undefined),
  deleteBlock: jest.fn<() => Promise<void>>().mockResolvedValue(undefined),
};
jest.mock("../../services/systemprompt-service.js", () => ({
  SystemPromptService: jest.fn(() => mockSystemPromptService),
}));
describe("Tool Handlers", () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });
  describe("handleToolCall", () => {
    describe("Heartbeat", () => {
      it("should handle systemprompt_heartbeat", async () => {
        const request: CallToolRequest = {
          method: "tools/call",
          params: {
            name: "systemprompt_heartbeat",
            params: {},
          },
        };
        const result = await handleToolCall(request);
        expect(mockSystemPromptService.fetchUserStatus).toHaveBeenCalled();
        expect(result.content[0].type).toBe("text");
        expect(result.content[0].text).toContain("User Information");
      });
      it("should handle errors gracefully", async () => {
        const error = new Error("Failed to fetch user status");
        mockSystemPromptService.fetchUserStatus.mockRejectedValueOnce(error);
        const request: CallToolRequest = {
          method: "tools/call",
          params: {
            name: "systemprompt_heartbeat",
            params: {},
          },
        };
        await expect(handleToolCall(request)).rejects.toThrow("Failed to fetch user status");
      });
    });
    describe("Resource Operations", () => {
      it("should handle systemprompt_fetch_resources", async () => {
        const result = await handleToolCall({
          method: "tools/call",
          params: {
            name: "systemprompt_fetch_resources",
            params: {},
          },
        });
        expect(mockSystemPromptService.getAllPrompts).toHaveBeenCalled();
        expect(mockSystemPromptService.listBlocks).toHaveBeenCalled();
        expect(mockSystemPromptService.listAgents).toHaveBeenCalled();
        expect(result.content[0].type).toBe("text");
        expect(result.content[0].text).toContain("Resources");
      });
      it("should handle delete resource failure", async () => {
        mockSystemPromptService.deletePrompt.mockRejectedValueOnce(
          new Error("Failed to delete prompt"),
        );
        mockSystemPromptService.deleteBlock.mockRejectedValueOnce(
          new Error("Failed to delete block"),
        );
        await expect(
          handleToolCall({
            method: "tools/call",
            params: {
              name: "systemprompt_delete_resource",
              arguments: {
                id: "nonexistent123",
              },
            },
          }),
        ).rejects.toThrow("Failed to delete resource with ID nonexistent123");
      });
    });
    describe("Error Handling", () => {
      it("should handle invalid tool name", async () => {
        await expect(
          handleToolCall({
            method: "tools/call",
            params: {
              name: "invalid_tool",
              params: {},
            },
          }),
        ).rejects.toThrow("Unknown tool: invalid_tool");
      });
      it("should handle service errors", async () => {
        mockSystemPromptService.fetchUserStatus.mockRejectedValueOnce(new Error("Service error"));
        await expect(
          handleToolCall({
            method: "tools/call",
            params: {
              name: "systemprompt_heartbeat",
              params: {},
            },
          }),
        ).rejects.toThrow("Service error");
      });
    });
  });
});