Skip to main content
Glama
tools.test.ts10.4 kB
import { ExecutionStep, HttpMethod, PaginationType, RunStatus, Tool } from '@superglue/shared'; import { describe, expect, it } from 'vitest'; import { ApiConfig } from '../../shared/types.js'; import { buildRunResponse, mapFailureBehavior, mapPaginationType, mapStepToOpenAPI, mapToolToOpenAPI } from './tools.js'; describe('tools API helpers', () => { describe('mapPaginationType', () => { it('should map all known pagination types', () => { expect(mapPaginationType('OFFSET_BASED')).toBe('offsetBased'); expect(mapPaginationType('PAGE_BASED')).toBe('pageBased'); expect(mapPaginationType('CURSOR_BASED')).toBe('cursorBased'); expect(mapPaginationType('DISABLED')).toBe('disabled'); }); it('should return disabled for undefined input', () => { expect(mapPaginationType(undefined)).toBe('disabled'); }); it('should lowercase unknown types', () => { expect(mapPaginationType('CUSTOM_TYPE')).toBe('custom_type'); }); }); describe('mapFailureBehavior', () => { it('should map fail behavior', () => { expect(mapFailureBehavior('FAIL')).toBe('fail'); expect(mapFailureBehavior('fail')).toBe('fail'); }); it('should map continue behavior', () => { expect(mapFailureBehavior('CONTINUE')).toBe('continue'); expect(mapFailureBehavior('continue')).toBe('continue'); }); it('should return undefined for undefined input', () => { expect(mapFailureBehavior(undefined)).toBeUndefined(); }); }); describe('mapStepToOpenAPI', () => { const baseStep: ExecutionStep = { id: 'step-1', apiConfig: { urlHost: 'https://api.example.com', urlPath: '/users', method: HttpMethod.GET, instruction: 'Fetch users', id: 'step-1', }, }; it('should map basic step fields', () => { const result = mapStepToOpenAPI(baseStep); expect(result.id).toBe('step-1'); expect(result.url).toBe('https://api.example.com/users'); expect(result.method).toBe('GET'); }); it('should default method to GET', () => { const stepWithoutMethod: ExecutionStep = { id: 'step-1', apiConfig: { id: 'step-1', instruction: 'Fetch users', urlHost: 'https://api.example.com', urlPath: '/users', }, }; const result = mapStepToOpenAPI(stepWithoutMethod); expect(result.method).toBe('GET'); }); it('should include optional fields when present', () => { const stepWithOptionals: ExecutionStep = { ...baseStep, apiConfig: { ...baseStep.apiConfig, queryParams: { search: 'test' }, headers: { 'X-Api-Key': 'secret' }, body: '{"name": "test"}', instruction: 'Fetch users', }, integrationId: 'integration-123', modify: true, loopSelector: '$.data[*]', failureBehavior: 'CONTINUE', }; const result = mapStepToOpenAPI(stepWithOptionals); expect(result.queryParams).toEqual({ search: 'test' }); expect(result.headers).toEqual({ 'X-Api-Key': 'secret' }); expect(result.body).toBe('{"name": "test"}'); expect(result.instruction).toBe('Fetch users'); expect(result.systemId).toBe('integration-123'); expect(result.modify).toBe(true); expect(result.dataSelector).toBe('$.data[*]'); expect(result.failureBehavior).toBe('continue'); }); it('should map pagination config', () => { const stepWithPagination: ExecutionStep = { ...baseStep, apiConfig: { ...baseStep.apiConfig, pagination: { type: PaginationType.CURSOR_BASED, pageSize: '50', cursorPath: '$.nextCursor', stopCondition: '$.hasMore === false', }, }, }; const result = mapStepToOpenAPI(stepWithPagination); expect(result.pagination).toEqual({ type: 'cursorBased', pageSize: '50', cursorPath: '$.nextCursor', stopCondition: '$.hasMore === false', }); }); it('should handle empty urlHost and urlPath', () => { const stepWithEmptyUrl: ExecutionStep = { id: 'step-1', apiConfig: {} as ApiConfig, }; const result = mapStepToOpenAPI(stepWithEmptyUrl); expect(result.url).toBe(''); }); }); describe('mapToolToOpenAPI', () => { const baseTool: Tool = { id: 'tool-123', instruction: 'Test tool instruction', inputSchema: { type: 'object', properties: { name: { type: 'string' } } }, responseSchema: { type: 'object', properties: { result: { type: 'string' } } }, steps: [ { id: 'step-1', apiConfig: { urlHost: 'https://api.example.com', urlPath: '/test', method: HttpMethod.POST, instruction: 'Test step instruction', id: 'step-1', }, }, ], createdAt: new Date('2024-01-01T00:00:00Z'), updatedAt: new Date('2024-01-02T00:00:00Z'), }; it('should map basic tool fields', () => { const result = mapToolToOpenAPI(baseTool); expect(result.id).toBe('tool-123'); expect(result.name).toBe('tool-123'); expect(result.instruction).toBe('Test tool instruction'); expect(result.inputSchema).toEqual({ type: 'object', properties: { name: { type: 'string' } } }); expect(result.outputSchema).toEqual({ type: 'object', properties: { result: { type: 'string' } } }); }); it('should default version to 1.0.0', () => { const result = mapToolToOpenAPI(baseTool); expect(result.version).toBe('1.0.0'); }); it('should use provided version', () => { const toolWithVersion = { ...baseTool, version: '2.0.0' }; const result = mapToolToOpenAPI(toolWithVersion); expect(result.version).toBe('2.0.0'); }); it('should map steps', () => { const result = mapToolToOpenAPI(baseTool); expect(result.steps).toHaveLength(1); expect(result.steps[0].id).toBe('step-1'); expect(result.steps[0].url).toBe('https://api.example.com/test'); }); it('should include finalTransform as outputTransform', () => { const toolWithTransform = { ...baseTool, finalTransform: '$.data' }; const result = mapToolToOpenAPI(toolWithTransform); expect(result.outputTransform).toBe('$.data'); }); it('should format dates as ISO strings', () => { const result = mapToolToOpenAPI(baseTool); expect(result.createdAt).toBe('2024-01-01T00:00:00.000Z'); expect(result.updatedAt).toBe('2024-01-02T00:00:00.000Z'); }); it('should handle string dates', () => { const toolWithStringDates = { ...baseTool, createdAt: '2024-01-01T00:00:00Z' as unknown as Date, updatedAt: '2024-01-02T00:00:00Z' as unknown as Date, }; const result = mapToolToOpenAPI(toolWithStringDates); expect(result.createdAt).toBe('2024-01-01T00:00:00Z'); expect(result.updatedAt).toBe('2024-01-02T00:00:00Z'); }); }); describe('buildRunResponse', () => { const baseTool: Tool = { id: 'tool-123', instruction: 'Test tool', steps: [], }; const baseParams = { runId: 'run-456', tool: baseTool, status: RunStatus.SUCCESS, requestSource: 'api', startedAt: new Date('2024-01-01T10:00:00Z'), }; it('should build basic run response', () => { const result = buildRunResponse(baseParams); expect(result.runId).toBe('run-456'); expect(result.toolId).toBe('tool-123'); expect(result.tool).toEqual({ id: 'tool-123', version: '1.0.0' }); expect(result.status).toBe('success'); expect(result.requestSource).toBe('api'); }); it('should include metadata with startedAt', () => { const result = buildRunResponse(baseParams); expect(result.metadata.startedAt).toBe('2024-01-01T10:00:00.000Z'); expect(result.metadata.completedAt).toBeUndefined(); expect(result.metadata.durationMs).toBeUndefined(); }); it('should calculate duration when completedAt is provided', () => { const result = buildRunResponse({ ...baseParams, completedAt: new Date('2024-01-01T10:01:00Z'), }); expect(result.metadata.completedAt).toBe('2024-01-01T10:01:00.000Z'); expect(result.metadata.durationMs).toBe(60000); }); it('should include optional fields', () => { const result = buildRunResponse({ ...baseParams, toolPayload: { input: 'test' }, data: { output: 'result' }, error: 'Some error', traceId: 'trace-789', options: { timeout: 30000 }, }); expect(result.toolPayload).toEqual({ input: 'test' }); expect(result.data).toEqual({ output: 'result' }); expect(result.error).toBe('Some error'); expect(result.traceId).toBe('trace-789'); expect(result.options).toEqual({ timeout: 30000 }); }); it('should map stepResults', () => { const result = buildRunResponse({ ...baseParams, stepResults: [ { stepId: 'step-1', success: true, data: { foo: 'bar' } }, { stepId: 'step-2', success: false, error: 'Failed' }, ], }); expect(result.stepResults).toEqual([ { stepId: 'step-1', success: true, data: { foo: 'bar' }, error: undefined }, { stepId: 'step-2', success: false, data: undefined, error: 'Failed' }, ]); }); it('should map all run statuses correctly', () => { expect(buildRunResponse({ ...baseParams, status: RunStatus.RUNNING }).status).toBe('running'); expect(buildRunResponse({ ...baseParams, status: RunStatus.SUCCESS }).status).toBe('success'); expect(buildRunResponse({ ...baseParams, status: RunStatus.FAILED }).status).toBe('failed'); expect(buildRunResponse({ ...baseParams, status: RunStatus.ABORTED }).status).toBe('aborted'); }); it('should use tool version if provided', () => { const toolWithVersion = { ...baseTool, version: '2.5.0' }; const result = buildRunResponse({ ...baseParams, tool: toolWithVersion }); expect(result.tool).toEqual({ id: 'tool-123', version: '2.5.0' }); }); }); });

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/superglue-ai/superglue'

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