import { createEchoTool, createVersionTool, createStatusTool, withErrorHandling, withLogging } from '../ToolHelpers'; const parse = (result: string) => JSON.parse(result); describe('ToolHelpers', () => { beforeEach(() => { jest.useFakeTimers(); jest.setSystemTime(new Date('2024-01-02T12:34:56.000Z')); }); afterEach(() => { jest.useRealTimers(); }); it('creates an echo tool that returns the provided message', async () => { const tool = createEchoTool() as any; const response = await tool.execute({ message: 'hello world' }); expect(parse(response)).toEqual({ echo: 'hello world', timestamp: '2024-01-02T12:34:56.000Z' }); }); it('creates a version tool that returns version metadata', async () => { const tool = createVersionTool('2.3.4', { commit: 'abc123' }) as any; const response = await tool.execute(); expect(parse(response)).toEqual({ version: '2.3.4', commit: 'abc123', timestamp: '2024-01-02T12:34:56.000Z' }); }); it('creates a status tool that merges provider data', async () => { const tool = createStatusTool(async () => ({ healthy: true, uptime: 42 })) as any; const response = await tool.execute(); expect(parse(response)).toEqual({ healthy: true, uptime: 42, timestamp: '2024-01-02T12:34:56.000Z' }); }); it('wraps a tool with error handling producing structured errors', async () => { const tool = withErrorHandling({ name: 'unstable', execute: jest.fn().mockRejectedValue(new Error('boom')) }); const response = await tool.execute({}); expect(parse(response)).toMatchObject({ error: true, message: 'Error: boom', timestamp: '2024-01-02T12:34:56.000Z' }); }); it('supports custom error handler in withErrorHandling', async () => { const tool = withErrorHandling({ name: 'unstable', execute: jest.fn().mockRejectedValue(new Error('boom')) }, (error) => `custom: ${error.message}`); const response = await tool.execute({}); expect(parse(response).message).toBe('custom: boom'); }); it('wraps a tool with logging for success and failure', async () => { const logger = jest.fn(); const originalExecute = jest.fn().mockResolvedValue('success'); const tool = withLogging({ name: 'loggable', execute: originalExecute }, logger); const result = await tool.execute({ foo: 'bar' }); expect(result).toBe('success'); expect(originalExecute).toHaveBeenCalledWith({ foo: 'bar' }); expect(logger).toHaveBeenCalledWith('[loggable] Executing with params:', { foo: 'bar' }); expect(logger).toHaveBeenCalledWith(expect.stringMatching(/\[loggable\] Completed in \d+ms/)); }); it('logs failures when wrapped with logging', async () => { const logger = jest.fn(); const error = new Error('failure'); const tool = withLogging({ name: 'loggable', execute: jest.fn().mockRejectedValue(error) }, logger); await expect(tool.execute({})).rejects.toThrow('failure'); expect(logger).toHaveBeenCalledWith('[loggable] Executing with params:', {}); expect(logger).toHaveBeenCalledWith(expect.stringMatching(/\[loggable\] Failed after \d+ms:/), error); }); });