Skip to main content
Glama
CategorySearchTool.test.ts12 kB
// Set the token before importing the tool process.env.MAPBOX_ACCESS_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.signature'; import { setupFetch, assertHeadersSent } from '../../utils/requestUtils.test-helpers.js'; import { CategorySearchTool } from '../category-search-tool/CategorySearchTool.js'; describe('CategorySearchTool', () => { afterEach(() => { jest.restoreAllMocks(); }); it('sends custom header', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'restaurant' }); assertHeadersSent(mockFetch); }); it('constructs correct URL with required parameters', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'cafe' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('search/searchbox/v1/category/cafe'); expect(calledUrl).toContain('access_token='); }); it('includes all optional parameters in URL', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'hotel', language: 'es', limit: 15, proximity: { longitude: -74.006, latitude: 40.7128 }, bbox: { minLongitude: -74.1, minLatitude: 40.6, maxLongitude: -73.9, maxLatitude: 40.8 }, country: ['US', 'CA'], poi_category_exclusions: ['motel', 'hostel'] }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('category/hotel'); expect(calledUrl).toContain('language=es'); expect(calledUrl).toContain('limit=15'); expect(calledUrl).toContain('proximity=-74.006%2C40.7128'); expect(calledUrl).toContain('bbox=-74.1%2C40.6%2C-73.9%2C40.8'); expect(calledUrl).toContain('country=US%2CCA'); expect(calledUrl).toContain('poi_category_exclusions=motel%2Chostel'); }); it('handles IP-based proximity', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'gas_station', proximity: 'ip' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('proximity=ip'); }); it('handles string format proximity coordinates', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'restaurant', proximity: '-82.451668,27.942976' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('proximity=-82.451668%2C27.942976'); }); it('handles array-like string format proximity', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'restaurant', proximity: '[-82.451668, 27.942964]' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('proximity=-82.451668%2C27.942964'); }); it('handles JSON-stringified object format proximity', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'taco_shop', proximity: '{"longitude": -82.458107, "latitude": 27.937259}' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('proximity=-82.458107%2C27.937259'); }); it('uses default limit when not specified', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'pharmacy' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('limit=10'); }); it('handles fetch errors gracefully', async () => { const mockFetch = setupFetch({ ok: false, status: 404, statusText: 'Not Found' }); const result = await new CategorySearchTool().run({ category: 'restaurant' }); expect(result.isError).toBe(true); expect(result.content[0]).toMatchObject({ type: 'text', text: 'Failed to search category: 404 Not Found' }); }); it('validates limit constraints', async () => { const tool = new CategorySearchTool(); // Test limit too high await expect( tool.run({ category: 'atm', limit: 26 }) ).resolves.toMatchObject({ isError: true }); // Test limit too low await expect( tool.run({ category: 'atm', limit: 0 }) ).resolves.toMatchObject({ isError: true }); }); it('validates coordinate constraints', async () => { const tool = new CategorySearchTool(); // Test invalid longitude in proximity await expect( tool.run({ category: 'parking', proximity: { longitude: -181, latitude: 40 } }) ).resolves.toMatchObject({ isError: true }); // Test invalid latitude in bbox await expect( tool.run({ category: 'parking', bbox: { minLongitude: -74, minLatitude: -91, maxLongitude: -73, maxLatitude: 40 } }) ).resolves.toMatchObject({ isError: true }); }); it('encodes special characters in category', async () => { const mockFetch = setupFetch(); await new CategorySearchTool().run({ category: 'shopping mall' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('category/shopping%20mall'); }); it('formats GeoJSON response to text with basic information', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Local Coffee Shop', full_address: '456 Oak St, Portland, OR 97205', feature_type: 'poi', poi_category: ['coffee', 'cafe'] }, geometry: { type: 'Point', coordinates: [-122.676, 45.515] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'cafe' }); expect(result.isError).toBe(false); expect(result.content[0].type).toBe('text'); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. Local Coffee Shop'); expect(textContent).toContain('Address: 456 Oak St, Portland, OR 97205'); expect(textContent).toContain('Coordinates: 45.515, -122.676'); expect(textContent).toContain('Type: poi'); expect(textContent).toContain('Category: coffee, cafe'); }); it('formats GeoJSON response with name_preferred', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'McDonalds', name_preferred: "McDonald's", place_formatted: '123 Main St, Boston, MA' }, geometry: { type: 'Point', coordinates: [-71.0589, 42.3601] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'fast_food' }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain("1. McDonalds (McDonald's)"); expect(textContent).toContain('Address: 123 Main St, Boston, MA'); expect(textContent).toContain('Coordinates: 42.3601, -71.0589'); }); it('handles multiple results in formatted text', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Target', full_address: '100 Store St, Seattle, WA 98101', feature_type: 'poi' }, geometry: { type: 'Point', coordinates: [-122.335, 47.608] } }, { type: 'Feature', properties: { name: 'Walmart', full_address: '200 Shop Ave, Seattle, WA 98102', feature_type: 'poi' }, geometry: { type: 'Point', coordinates: [-122.34, 47.61] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'department_store', limit: 2 }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. Target'); expect(textContent).toContain('2. Walmart'); expect(textContent).toContain('100 Store St, Seattle, WA 98101'); expect(textContent).toContain('200 Shop Ave, Seattle, WA 98102'); }); it('handles empty results gracefully', async () => { const mockResponse = { type: 'FeatureCollection', features: [] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'nonexistent_category' }); expect(result.isError).toBe(false); expect(result.content[0].type).toBe('text'); expect((result.content[0] as { type: 'text'; text: string }).text).toBe( 'No results found.' ); }); it('handles results with minimal properties', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Some Gas Station' }, geometry: { type: 'Point', coordinates: [-74.006, 40.7128] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'gas_station' }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. Some Gas Station'); expect(textContent).toContain('Coordinates: 40.7128, -74.006'); expect(textContent).not.toContain('Address:'); }); it('returns JSON string format when requested', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Test Restaurant', full_address: '123 Test St, Test City, TC 12345' }, geometry: { type: 'Point', coordinates: [-122.676, 45.515] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'restaurant', format: 'json_string' }); expect(result.isError).toBe(false); expect(result.content[0].type).toBe('text'); const jsonContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(JSON.parse(jsonContent)).toEqual(mockResponse); }); it('defaults to formatted_text format when format not specified', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Test Cafe' }, geometry: { type: 'Point', coordinates: [-122.676, 45.515] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new CategorySearchTool().run({ category: 'cafe' }); expect(result.isError).toBe(false); expect(result.content[0].type).toBe('text'); expect( (result.content[0] as { type: 'text'; text: string }).text ).toContain('1. Test Cafe'); }); });

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/Waldzell-Agentics/mcp-server'

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