import { convertParametersToTypes } from '../../src/utils/parameterConversion.js'; // Integration tests for OpenAPI controller's parameter type conversion describe('OpenAPI Controller - Parameter Type Conversion Integration', () => { test('should convert integer parameters correctly', () => { const queryParams = { limit: '5', offset: '10', name: 'test' }; const inputSchema = { type: 'object', properties: { limit: { type: 'integer' }, offset: { type: 'integer' }, name: { type: 'string' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ limit: 5, // Converted to integer offset: 10, // Converted to integer name: 'test' // Remains string }); }); test('should convert number parameters correctly', () => { const queryParams = { price: '19.99', discount: '0.15' }; const inputSchema = { type: 'object', properties: { price: { type: 'number' }, discount: { type: 'number' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ price: 19.99, discount: 0.15 }); }); test('should convert boolean parameters correctly', () => { const queryParams = { enabled: 'true', disabled: 'false', active: '1', inactive: '0' }; const inputSchema = { type: 'object', properties: { enabled: { type: 'boolean' }, disabled: { type: 'boolean' }, active: { type: 'boolean' }, inactive: { type: 'boolean' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ enabled: true, disabled: false, active: true, inactive: false }); }); test('should convert array parameters correctly', () => { const queryParams = { tags: 'tag1,tag2,tag3', ids: '1,2,3' }; const inputSchema = { type: 'object', properties: { tags: { type: 'array' }, ids: { type: 'array' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ tags: ['tag1', 'tag2', 'tag3'], ids: ['1', '2', '3'] }); }); test('should handle missing schema gracefully', () => { const queryParams = { limit: '5', name: 'test' }; const result = convertParametersToTypes(queryParams, {}); expect(result).toEqual({ limit: '5', // Should remain as string name: 'test' // Should remain as string }); }); test('should handle properties not in schema', () => { const queryParams = { limit: '5', unknownParam: 'value' }; const inputSchema = { type: 'object', properties: { limit: { type: 'integer' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ limit: 5, // Converted based on schema unknownParam: 'value' // Kept as is (no schema) }); }); test('should handle invalid number conversion gracefully', () => { const queryParams = { limit: 'not-a-number', price: 'invalid' }; const inputSchema = { type: 'object', properties: { limit: { type: 'integer' }, price: { type: 'number' } } }; const result = convertParametersToTypes(queryParams, inputSchema); expect(result).toEqual({ limit: 'not-a-number', // Should remain as string when conversion fails price: 'invalid' // Should remain as string when conversion fails }); }); }); // Test the new OpenAPI endpoints functionality describe('OpenAPI Granular Endpoints', () => { // Mock the required services const mockGetAvailableServers = jest.fn(); const mockGenerateOpenAPISpec = jest.fn(); const mockGetGroupByIdOrName = jest.fn(); beforeEach(() => { jest.clearAllMocks(); }); test('should generate server-specific OpenAPI spec', async () => { // Mock available servers mockGetAvailableServers.mockResolvedValue(['server1', 'server2']); // Mock OpenAPI spec generation const mockSpec = { openapi: '3.0.3', info: { title: 'server1 MCP API' } }; mockGenerateOpenAPISpec.mockResolvedValue(mockSpec); // Test server spec generation options const expectedOptions = { title: 'server1 MCP API', description: 'OpenAPI specification for server1 MCP server tools', serverFilter: ['server1'] }; // Verify that the correct options would be passed expect(expectedOptions.serverFilter).toEqual(['server1']); expect(expectedOptions.title).toBe('server1 MCP API'); }); test('should generate group-specific OpenAPI spec', async () => { // Mock group data const mockGroup = { id: 'group1', name: 'webtools', servers: [ { name: 'server1', tools: 'all' }, { name: 'server2', tools: ['tool1', 'tool2'] } ] }; mockGetGroupByIdOrName.mockReturnValue(mockGroup); // Mock OpenAPI spec generation const mockSpec = { openapi: '3.0.3', info: { title: 'webtools Group MCP API' } }; mockGenerateOpenAPISpec.mockResolvedValue(mockSpec); // Test group spec generation options const expectedOptions = { title: 'webtools Group MCP API', description: 'OpenAPI specification for webtools group tools', groupFilter: 'webtools' }; // Verify that the correct options would be passed expect(expectedOptions.groupFilter).toBe('webtools'); expect(expectedOptions.title).toBe('webtools Group MCP API'); }); test('should handle non-existent server', async () => { // Mock available servers (not including 'nonexistent') mockGetAvailableServers.mockResolvedValue(['server1', 'server2']); // Verify error handling for non-existent server const serverExists = ['server1', 'server2'].includes('nonexistent'); expect(serverExists).toBe(false); }); test('should handle non-existent group', async () => { // Mock group lookup returning null mockGetGroupByIdOrName.mockReturnValue(null); // Verify error handling for non-existent group const group = mockGetGroupByIdOrName('nonexistent'); expect(group).toBeNull(); }); test('should decode URL-encoded server and tool names with slashes', () => { // Test that URL-encoded names with slashes are properly decoded const encodedServerName = 'com.atlassian%2Fatlassian-mcp-server'; const encodedToolName = 'atlassianUserInfo'; const decodedServerName = decodeURIComponent(encodedServerName); const decodedToolName = decodeURIComponent(encodedToolName); expect(decodedServerName).toBe('com.atlassian/atlassian-mcp-server'); expect(decodedToolName).toBe('atlassianUserInfo'); }); });