list-prompts.test.js•8.33 kB
import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
    handleListPrompts,
    listPromptsToolDefinition,
} from '../../../tools/prompts/list-prompts.js';
import { promptRegistry } from '../../../handlers/prompts.js';
describe('List Prompts Tool', () => {
    let mockServer;
    beforeEach(() => {
        // Clear registry before each test
        promptRegistry.clear();
        // Mock server
        mockServer = {
            createErrorResponse: vi.fn((error, context) => {
                throw new Error(`${context}: ${error.message}`);
            }),
        };
    });
    describe('Tool Definition', () => {
        it('should have correct tool definition', () => {
            expect(listPromptsToolDefinition).toMatchObject({
                name: 'list_prompts',
                description: expect.stringContaining('List all available prompt templates'),
                inputSchema: {
                    type: 'object',
                    properties: {},
                },
                outputSchema: {
                    type: 'object',
                    properties: {
                        total_prompts: { type: 'integer' },
                        prompts: { type: 'array' },
                    },
                    required: ['total_prompts', 'prompts'],
                },
            });
        });
    });
    describe('Functionality', () => {
        it('should return empty list when no prompts registered', async () => {
            const result = await handleListPrompts(mockServer);
            expect(result).toHaveProperty('content');
            expect(result.content[0].type).toBe('text');
            const parsedContent = JSON.parse(result.content[0].text);
            expect(parsedContent).toEqual({
                total_prompts: 0,
                prompts: [],
            });
            expect(result.structuredContent).toEqual({
                total_prompts: 0,
                prompts: [],
            });
        });
        it('should list all registered prompts', async () => {
            // Register test prompts
            promptRegistry.set('test_prompt_1', {
                name: 'test_prompt_1',
                title: 'Test Prompt 1',
                description: 'First test prompt',
                arguments: [
                    {
                        name: 'arg1',
                        title: 'Argument 1',
                        description: 'First argument',
                        required: true,
                    },
                ],
                handler: async () => [],
            });
            promptRegistry.set('test_prompt_2', {
                name: 'test_prompt_2',
                description: 'Second test prompt',
                // No title - should use name
                arguments: [],
                handler: async () => [],
            });
            const result = await handleListPrompts(mockServer);
            expect(result).toHaveProperty('content');
            expect(result.content[0].type).toBe('text');
            const parsedContent = JSON.parse(result.content[0].text);
            expect(parsedContent.total_prompts).toBe(2);
            expect(parsedContent.prompts).toHaveLength(2);
            // Check first prompt
            expect(parsedContent.prompts[0]).toEqual({
                name: 'test_prompt_1',
                title: 'Test Prompt 1',
                description: 'First test prompt',
                arguments: [
                    {
                        name: 'arg1',
                        title: 'Argument 1',
                        description: 'First argument',
                        required: true,
                    },
                ],
            });
            // Check second prompt uses name as title
            expect(parsedContent.prompts[1]).toEqual({
                name: 'test_prompt_2',
                title: 'test_prompt_2',
                description: 'Second test prompt',
                arguments: [],
            });
        });
        it('should handle prompts without arguments field', async () => {
            promptRegistry.set('minimal_prompt', {
                name: 'minimal_prompt',
                description: 'Minimal prompt',
                handler: async () => [],
                // No arguments field
            });
            const result = await handleListPrompts(mockServer);
            const parsedContent = JSON.parse(result.content[0].text);
            expect(parsedContent.prompts[0].arguments).toEqual([]);
        });
        it('should format output as pretty JSON', async () => {
            promptRegistry.set('test', {
                name: 'test',
                title: 'Test',
                description: 'Test prompt',
                arguments: [],
                handler: async () => [],
            });
            const result = await handleListPrompts(mockServer);
            const text = result.content[0].text;
            // Check for indentation (pretty printed)
            expect(text).toContain('\n  ');
            expect(text).toContain('"total_prompts": 1');
        });
    });
    describe('Error Handling', () => {
        it('should handle errors during prompt listing', async () => {
            // Mock Map.values to throw error
            const originalValues = Map.prototype.values;
            Map.prototype.values = vi.fn(() => {
                throw new Error('Map iteration failed');
            });
            await expect(handleListPrompts(mockServer)).rejects.toThrow(
                'Failed to list prompts: Map iteration failed',
            );
            expect(mockServer.createErrorResponse).toHaveBeenCalledWith(
                expect.objectContaining({ message: 'Map iteration failed' }),
                'Failed to list prompts',
            );
            // Restore
            Map.prototype.values = originalValues;
        });
        it('should handle errors during JSON stringification', async () => {
            // Mock JSON.stringify to throw error
            const originalStringify = JSON.stringify;
            JSON.stringify = vi.fn(() => {
                throw new TypeError('Converting circular structure to JSON');
            });
            promptRegistry.set('test', {
                name: 'test',
                description: 'Test prompt',
                handler: async () => [],
            });
            await expect(handleListPrompts(mockServer)).rejects.toThrow('Failed to list prompts');
            // Restore
            JSON.stringify = originalStringify;
        });
    });
    describe('Output Format', () => {
        it('should include both content and structuredContent', async () => {
            promptRegistry.set('test', {
                name: 'test',
                title: 'Test',
                description: 'Test prompt',
                arguments: [],
                handler: async () => [],
            });
            const result = await handleListPrompts(mockServer);
            // Check content format
            expect(result.content).toBeInstanceOf(Array);
            expect(result.content[0]).toHaveProperty('type', 'text');
            expect(result.content[0]).toHaveProperty('text');
            // Check structuredContent
            expect(result.structuredContent).toEqual({
                total_prompts: 1,
                prompts: [
                    {
                        name: 'test',
                        title: 'Test',
                        description: 'Test prompt',
                        arguments: [],
                    },
                ],
            });
        });
        it('should not include handler function in output', async () => {
            const handler = async () => [];
            promptRegistry.set('test', {
                name: 'test',
                title: 'Test',
                description: 'Test prompt',
                arguments: [],
                handler,
            });
            const result = await handleListPrompts(mockServer);
            // Handler should not be in output
            expect(result.content[0].text).not.toContain('handler');
            expect(result.structuredContent.prompts[0]).not.toHaveProperty('handler');
        });
    });
});