Skip to main content
Glama
page-tools.test.js9.71 kB
/** * Ghost Page Tools Tests * * Tests for create, list, update, delete page operations */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { createMockServer, mockResponses } from './helpers/test-utils.js'; // Create mock client with spies const mockClient = { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn() }; // Mock the api-client module vi.mock('../core/api-client.js', () => ({ createApiClient: vi.fn(() => ({ client: mockClient, apiUrl: 'https://test-ghost.example.com', token: 'mock-token' })), buildApiUrl: vi.fn((baseUrl, endpoint, params) => { let url = `${baseUrl}/ghost/api/admin/${endpoint}/`; if (params && Object.keys(params).length > 0) { const queryParams = new URLSearchParams(); for (const [key, value] of Object.entries(params)) { if (value !== undefined && value !== null) { queryParams.append(key, value); } } const queryString = queryParams.toString(); if (queryString) url += `?${queryString}`; } return url; }), formatSuccessResponse: vi.fn((data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] })), formatErrorResponse: vi.fn((error) => ({ content: [{ type: 'text', text: JSON.stringify({ error: error.message }, null, 2) }], isError: true })) })); // Mock environment variables const originalEnv = process.env; beforeEach(() => { vi.clearAllMocks(); mockClient.get.mockReset(); mockClient.post.mockReset(); mockClient.put.mockReset(); mockClient.delete.mockReset(); process.env = { ...originalEnv, GHOST_API_URL: 'https://test-ghost.example.com', GHOST_ADMIN_KEY: 'test-key-id:a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2' }; }); afterEach(() => { process.env = originalEnv; }); // Import handlers after mocking const { handleCreateGhostPage, handleListGhostPages, handleUpdateGhostPage, handleDeleteGhostPage, createGhostPageToolDefinition, listGhostPagesToolDefinition, updateGhostPageToolDefinition, deleteGhostPageToolDefinition } = await import('../tools/page-tools.js'); // Mock server object const mockServer = createMockServer(); describe('Tool Definitions', () => { describe('createGhostPageToolDefinition', () => { it('should have correct name', () => { expect(createGhostPageToolDefinition.name).toBe('create_ghost_page'); }); it('should have required fields for title and content', () => { expect(createGhostPageToolDefinition.inputSchema.required).toContain('title'); expect(createGhostPageToolDefinition.inputSchema.required).toContain('content'); }); it('should have correct property types', () => { const props = createGhostPageToolDefinition.inputSchema.properties; expect(props.title.type).toBe('string'); expect(props.content.type).toBe('string'); }); }); describe('listGhostPagesToolDefinition', () => { it('should have correct name', () => { expect(listGhostPagesToolDefinition.name).toBe('list_ghost_pages'); }); it('should have no required fields', () => { expect(listGhostPagesToolDefinition.inputSchema.required).toEqual([]); }); it('should have pagination fields', () => { const props = listGhostPagesToolDefinition.inputSchema.properties; expect(props.page).toBeDefined(); expect(props.limit).toBeDefined(); }); }); describe('updateGhostPageToolDefinition', () => { it('should have correct name', () => { expect(updateGhostPageToolDefinition.name).toBe('update_ghost_page'); }); it('should require page_id', () => { expect(updateGhostPageToolDefinition.inputSchema.required).toContain('page_id'); }); }); describe('deleteGhostPageToolDefinition', () => { it('should have correct name', () => { expect(deleteGhostPageToolDefinition.name).toBe('delete_ghost_page'); }); it('should require page_id', () => { expect(deleteGhostPageToolDefinition.inputSchema.required).toContain('page_id'); }); }); }); describe('handleCreateGhostPage', () => { it('should return error when title is missing', async () => { const result = await handleCreateGhostPage(mockServer, { content: '<p>Test content</p>' }); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text); expect(response.error).toContain('Title and content are required'); }); it('should return error when content is missing', async () => { const result = await handleCreateGhostPage(mockServer, { title: 'Test Page' }); expect(result.isError).toBe(true); }); it('should create page with valid parameters', async () => { mockClient.post.mockResolvedValueOnce({ data: { pages: [{ id: 'page-123', title: 'Test Page', status: 'draft' }] } }); const result = await handleCreateGhostPage(mockServer, { title: 'Test Page', content: '<p>Test content</p>' }); expect(result.isError).toBeUndefined(); expect(mockClient.post).toHaveBeenCalledTimes(1); }); it('should handle API errors gracefully', async () => { mockClient.post.mockRejectedValueOnce(new Error('API Error')); const result = await handleCreateGhostPage(mockServer, { title: 'Test Page', content: '<p>Test content</p>' }); expect(result.isError).toBe(true); }); }); describe('handleListGhostPages', () => { it('should list pages successfully', async () => { mockClient.get.mockResolvedValueOnce({ data: { pages: [ { id: 'page-1', title: 'Page 1' }, { id: 'page-2', title: 'Page 2' } ] } }); const result = await handleListGhostPages(mockServer, {}); expect(result.isError).toBeUndefined(); expect(mockClient.get).toHaveBeenCalledTimes(1); }); it('should handle empty results', async () => { mockClient.get.mockResolvedValueOnce({ data: { pages: [] } }); const result = await handleListGhostPages(mockServer, {}); expect(result.isError).toBeUndefined(); }); it('should handle API errors gracefully', async () => { mockClient.get.mockRejectedValueOnce(new Error('Connection refused')); const result = await handleListGhostPages(mockServer, {}); expect(result.isError).toBe(true); }); }); describe('handleUpdateGhostPage', () => { it('should return error when page_id is missing', async () => { const result = await handleUpdateGhostPage(mockServer, { title: 'Updated Title' }); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text); expect(response.error).toContain('Page ID is required'); }); it('should update page successfully', async () => { mockClient.get.mockResolvedValueOnce({ data: { pages: [{ id: 'page-123', updated_at: '2025-01-15T12:00:00Z' }] } }); mockClient.put.mockResolvedValueOnce({ data: { pages: [{ id: 'page-123', title: 'Updated Title' }] } }); const result = await handleUpdateGhostPage(mockServer, { page_id: 'page-123', title: 'Updated Title' }); expect(result.isError).toBeUndefined(); expect(mockClient.get).toHaveBeenCalledTimes(1); expect(mockClient.put).toHaveBeenCalledTimes(1); }); it('should return error when page not found', async () => { mockClient.get.mockResolvedValueOnce({ data: { pages: [] } }); const result = await handleUpdateGhostPage(mockServer, { page_id: 'non-existent', title: 'Updated Title' }); expect(result.isError).toBe(true); }); }); describe('handleDeleteGhostPage', () => { it('should return error when page_id is missing', async () => { const result = await handleDeleteGhostPage(mockServer, {}); expect(result.isError).toBe(true); const response = JSON.parse(result.content[0].text); expect(response.error).toContain('Page ID is required'); }); it('should delete page successfully', async () => { mockClient.delete.mockResolvedValueOnce({ status: 204 }); const result = await handleDeleteGhostPage(mockServer, { page_id: 'page-123' }); expect(result.isError).toBeUndefined(); expect(mockClient.delete).toHaveBeenCalledTimes(1); }); it('should handle deletion errors', async () => { mockClient.delete.mockRejectedValueOnce(new Error('Not found')); const result = await handleDeleteGhostPage(mockServer, { page_id: 'non-existent' }); expect(result.isError).toBe(true); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oculairmedia/Ghost-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server