import { describe, it, expect } from 'vitest'; import { z } from 'zod'; import { registerTool, getTool, listTools } from './registry.js'; describe('tool registry', () => { it('registers and retrieves a tool by name', () => { registerTool({ name: 'test.hello', description: 'A test tool', requiredRole: 'viewer', inputSchema: z.object({ name: z.string() }), async execute(args) { return { hello: args.name }; }, }); const tool = getTool('test.hello'); expect(tool).toBeDefined(); expect(tool?.name).toBe('test.hello'); expect(tool?.requiredRole).toBe('viewer'); }); it('listTools returns all registered tools with meta', () => { const all = listTools(); const found = all.find(t => t.name === 'test.hello'); expect(found).toBeDefined(); expect(found?.description).toBe('A test tool'); expect(found?.inputSchema).toHaveProperty('type', 'object'); }); it('getTool returns undefined for unknown tool', () => { expect(getTool('does.not.exist')).toBeUndefined(); }); it('zodToJsonSchema emits correct types for boolean/number/array fields', () => { registerTool({ name: 'test.types', description: 'Type test', requiredRole: 'viewer', inputSchema: z.object({ flag: z.boolean(), count: z.coerce.number(), tags: z.array(z.string()), label: z.string().optional(), enabled: z.boolean().default(false), }), async execute(args) { return args; }, }); const tool = listTools().find(t => t.name === 'test.types'); const props = (tool?.inputSchema as { properties: Record }) .properties; expect(props.flag.type).toBe('boolean'); expect(props.count.type).toBe('number'); expect(props.tags.type).toBe('array'); expect(props.label.type).toBe('string'); // ZodDefault should unwrap to boolean, not 'string' expect(props.enabled.type).toBe('boolean'); // optional + default fields should NOT be in required const required = tool?.inputSchema.required as string[]; expect(required).toContain('flag'); expect(required).toContain('count'); expect(required).not.toContain('label'); expect(required).not.toContain('enabled'); }); }); describe('tool execute', () => { it('executes with validated args', async () => { registerTool({ name: 'test.echo', description: 'Echo', requiredRole: 'admin', inputSchema: z.object({ value: z.string() }), async execute(args) { return { echoed: args.value }; }, }); const tool = getTool('test.echo')!; const result = await tool.execute({ value: 'ping' }, {} as never); expect(result).toEqual({ echoed: 'ping' }); }); });