@the_cfdude/productboard-mcp
Version:
Model Context Protocol server for Productboard REST API with dynamic tool loading
121 lines (102 loc) • 4.16 kB
text/typescript
/**
* Tests for Webhooks tools
*/
import { describe, it, expect, jest, beforeEach } from '@jest/globals';
import {
handleWebhooksTool,
setupWebhooksTools,
} from '../../tools/webhooks.js';
import type { ToolDefinition } from '../../types/tool-types.js';
describe('Webhooks Tools', () => {
beforeEach(() => {
jest.clearAllMocks();
});
describe('Tool Definitions', () => {
it('should define all webhooks tools with correct schemas', () => {
const tools = setupWebhooksTools();
expect(tools).toHaveLength(4);
const toolNames = tools.map((tool: ToolDefinition) => tool.name);
expect(toolNames).toContain('create_webhook');
expect(toolNames).toContain('list_webhooks');
expect(toolNames).toContain('get_webhook');
expect(toolNames).toContain('delete_webhook');
});
it('should have standardized parameters for list operations', () => {
const tools = setupWebhooksTools();
const listWebhooks = tools.find(
(t: ToolDefinition) => t.name === 'list_webhooks'
);
expect(listWebhooks?.inputSchema.properties).toHaveProperty('limit');
expect(listWebhooks?.inputSchema.properties).toHaveProperty('startWith');
expect(listWebhooks?.inputSchema.properties).toHaveProperty('detail');
expect(listWebhooks?.inputSchema.properties).toHaveProperty(
'includeSubData'
);
});
it('should have standardized parameters for get operations', () => {
const tools = setupWebhooksTools();
const getWebhook = tools.find(
(t: ToolDefinition) => t.name === 'get_webhook'
);
expect(getWebhook?.inputSchema.properties).toHaveProperty('detail');
expect(getWebhook?.inputSchema.properties).toHaveProperty(
'includeSubData'
);
});
it('should require events, name and url for create_webhook', () => {
const tools = setupWebhooksTools();
const createWebhook = tools.find(
(t: ToolDefinition) => t.name === 'create_webhook'
);
expect(createWebhook?.inputSchema.required).toContain('events');
expect(createWebhook?.inputSchema.required).toContain('name');
expect(createWebhook?.inputSchema.required).toContain('url');
});
it('should have optional headers and version fields for create_webhook', () => {
const tools = setupWebhooksTools();
const createWebhook = tools.find(
(t: ToolDefinition) => t.name === 'create_webhook'
);
expect(createWebhook?.inputSchema.properties).toHaveProperty('headers');
expect(createWebhook?.inputSchema.properties).toHaveProperty('version');
expect(createWebhook?.inputSchema.properties).toHaveProperty('events');
expect(createWebhook?.inputSchema.properties).toHaveProperty('name');
});
it('should require id for individual webhook operations', () => {
const tools = setupWebhooksTools();
const getWebhook = tools.find(
(t: ToolDefinition) => t.name === 'get_webhook'
);
const deleteWebhook = tools.find(
(t: ToolDefinition) => t.name === 'delete_webhook'
);
expect(getWebhook?.inputSchema.required).toContain('id');
expect(deleteWebhook?.inputSchema.required).toContain('id');
});
});
describe('Tool Handler', () => {
it('should handle unknown tool error', async () => {
await expect(handleWebhooksTool('unknown_tool', {})).rejects.toThrow(
'Unknown webhooks tool: unknown_tool'
);
});
it('should accept valid tool names including aliases', () => {
const validTools = [
'create_webhook',
'post_webhook', // alias for create_webhook
'list_webhooks',
'get_webhooks', // alias for list_webhooks
'get_webhook',
'delete_webhook',
];
validTools.forEach(toolName => {
expect(() => {
// Just check it doesn't throw immediately
const promise = handleWebhooksTool(toolName, {});
// Catch the expected error about missing required fields
promise.catch(() => {});
}).not.toThrow('Unknown webhooks tool');
});
});
});
});