import { test, expect, describe } from 'bun:test' import { WebSearchTool } from '../WebSearchTool' describe('WebSearchTool', () => { describe('Tool Properties', () => { test('should have correct tool name', () => { expect(WebSearchTool.name).toBe('WebSearch') }) test('should have correct description', () => { expect(WebSearchTool.description).toContain('SearXNG') }) test('should be enabled', () => { expect(WebSearchTool.isEnabled()).toBe(true) }) test('should be concurrency safe', () => { expect(WebSearchTool.isConcurrencySafe()).toBe(true) }) test('should be read only', () => { expect(WebSearchTool.isReadOnly()).toBe(true) }) }) describe('Input Validation', () => { test('should accept valid query', async () => { const result = await WebSearchTool.validateInput( { query: 'typescript' }, {} ) expect(result.result).toBe(true) }) test('should reject empty query', async () => { const result = await WebSearchTool.validateInput( { query: '' }, {} ) expect(result.result).toBe(false) }) test('should reject missing input', async () => { const result = await WebSearchTool.validateInput( {} as any, {} ) expect(result.result).toBe(false) }) }) describe('Permissions', () => { test('should allow all web search requests', async () => { const result = await WebSearchTool.checkPermissions( { query: 'typescript' }, {} ) expect(result.behavior).toBe('allow') }) }) describe('Tool Call - Successful Search', () => { test('should perform web search', async () => { const result = await WebSearchTool.call( { query: 'typescript programming' }, {}, () => {}, null ) expect(result).toBeDefined() expect(result.data.query).toBe('typescript programming') expect(Array.isArray(result.data.results)).toBe(true) expect(result.data.durationSeconds).toBeGreaterThan(0) }, 60000) test('should return structured results', async () => { const result = await WebSearchTool.call( { query: 'javascript' }, {}, () => {}, null ) expect(result.data.results.length).toBeGreaterThanOrEqual(0) const first = result.data.results[0] if (first && typeof first !== 'string') { expect(first).toHaveProperty('tool_use_id') expect(Array.isArray(first.content)).toBe(true) } }, 60000) }) describe('Tool Call - Error Handling', () => { test('should handle missing query', async () => { const result = await WebSearchTool.call( { query: '' } as any, {}, () => {}, null ) expect(result.data.results.some(r => typeof r === 'string' && r.includes('Error'))).toBe(true) }) test('should not crash on failure', async () => { const result = await WebSearchTool.call( { query: 'test' }, {}, () => {}, null ) expect(result).toBeDefined() }, 60000) }) describe('Schema Validation', () => { test('should have valid input schema', () => { const schema = WebSearchTool.inputSchema const parsed = schema.safeParse({ query: 'test' }) expect(parsed.success).toBe(true) }) test('should have valid output schema', () => { expect(WebSearchTool.outputSchema).toBeDefined() }) }) describe('Tool Metadata', () => { test('should provide activity description', () => { const desc = WebSearchTool.getActivityDescription({ query: 'typescript' }) expect(desc).toContain('Searching') }) test('should provide tool use summary', () => { const summary = WebSearchTool.getToolUseSummary({ query: 'javascript' }) expect(summary).toBeDefined() }) test('should return empty search text', () => { const text = WebSearchTool.extractSearchText?.({ results: ['test'] } as any) expect(text).toBe('') }) }) describe('Auto Classifier Input', () => { test('should format input correctly', () => { const input = WebSearchTool.toAutoClassifierInput({ query: 'typescript' }) expect(input).toBe('typescript') }) }) describe('Tool Result Mapping', () => { test('should map tool result correctly', () => { const output = { query: 'test', results: [{ tool_use_id: '1', content: [{ title: 'Test', url: 'https://example.com', snippet: 'snippet' }] }], durationSeconds: 1 } const result = WebSearchTool.mapToolResultToToolResultBlockParam( output, 'id' ) expect(result.type).toBe('tool_result') expect(typeof result.content).toBe('string') }) test('should handle empty results', () => { const output = { query: 'test', results: [], durationSeconds: 1 } const result = WebSearchTool.mapToolResultToToolResultBlockParam( output, 'id' ) expect(result.content).toContain('Results') }) }) describe('SearXNG Integration', () => { test('should search using SearXNG', async () => { const result = await WebSearchTool.call( { query: 'milet 的最新动态' }, {}, () => {}, null ) expect(result).toBeDefined() expect(result.data.query).toBe('milet 的最新动态') expect(Array.isArray(result.data.results)).toBe(true) expect(result.data.durationSeconds).toBeGreaterThan(0) }, 60000) }) })