Skip to main content
Glama
ReverseGeocodeTool.test.ts12.7 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 { ReverseGeocodeTool } from './ReverseGeocodeTool.js'; describe('ReverseGeocodeTool', () => { afterEach(() => { jest.restoreAllMocks(); }); it('sends custom header', async () => { const mockFetch = setupFetch(); await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733 }); assertHeadersSent(mockFetch); }); it('constructs correct URL for reverse geocoding', async () => { const mockFetch = setupFetch(); await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733 }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('search/geocode/v6/reverse'); expect(calledUrl).toContain('longitude=-73.989'); expect(calledUrl).toContain('latitude=40.733'); expect(calledUrl).toContain('access_token='); }); it('includes all optional parameters', async () => { const mockFetch = setupFetch(); await new ReverseGeocodeTool().run({ longitude: -74.006, latitude: 40.7128, permanent: true, country: ['US'], language: 'fr', limit: 3, types: ['address'], worldview: 'jp' }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('longitude=-74.006'); expect(calledUrl).toContain('latitude=40.7128'); expect(calledUrl).toContain('permanent=true'); expect(calledUrl).toContain('country=US'); expect(calledUrl).toContain('language=fr'); expect(calledUrl).toContain('limit=3'); expect(calledUrl).toContain('types=address'); expect(calledUrl).toContain('worldview=jp'); }); it('uses default values', async () => { const mockFetch = setupFetch(); await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733 }); const calledUrl = mockFetch.mock.calls[0][0]; expect(calledUrl).toContain('permanent=false'); expect(calledUrl).toContain('limit=1'); expect(calledUrl).toContain('worldview=us'); }); it('validates limit constraints', async () => { const tool = new ReverseGeocodeTool(); // Test limit too high await expect( tool.run({ longitude: -73.989, latitude: 40.733, limit: 6 }) ).resolves.toMatchObject({ isError: true }); // Test limit too low await expect( tool.run({ longitude: -73.989, latitude: 40.733, limit: 0 }) ).resolves.toMatchObject({ isError: true }); }); it('validates coordinate constraints', async () => { const tool = new ReverseGeocodeTool(); // Test invalid longitude await expect( tool.run({ longitude: -181, latitude: 40.733 }) ).resolves.toMatchObject({ isError: true }); await expect( tool.run({ longitude: 181, latitude: 40.733 }) ).resolves.toMatchObject({ isError: true }); // Test invalid latitude await expect( tool.run({ longitude: -73.989, latitude: 91 }) ).resolves.toMatchObject({ isError: true }); await expect( tool.run({ longitude: -73.989, latitude: -91 }) ).resolves.toMatchObject({ isError: true }); }); it('enforces types constraint when limit > 1', async () => { const tool = new ReverseGeocodeTool(); // Should succeed with exactly one type const mockFetch = setupFetch(); await tool.run({ longitude: -73.989, latitude: 40.733, limit: 3, types: ['address'] }); expect(mockFetch).toHaveBeenCalled(); // Should fail without types when limit > 1 await expect( tool.run({ longitude: -73.989, latitude: 40.733, limit: 3 }) ).resolves.toMatchObject({ isError: true }); // Should fail with multiple types when limit > 1 await expect( tool.run({ longitude: -73.989, latitude: 40.733, limit: 3, types: ['address', 'place'] }) ).resolves.toMatchObject({ isError: true }); }); it('allows limit of 1 without types constraint', async () => { const mockFetch = setupFetch(); // Should succeed with limit=1 and no types await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733, limit: 1 }); expect(mockFetch).toHaveBeenCalled(); // Should also succeed with limit=1 and multiple types await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733, limit: 1, types: ['address', 'place'] }); expect(mockFetch).toHaveBeenCalledTimes(2); }); it('handles fetch errors gracefully', async () => { const mockFetch = setupFetch({ ok: false, status: 404, statusText: 'Not Found' }); const result = await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733 }); expect(result.isError).toBe(true); expect(result.content[0]).toMatchObject({ type: 'text', text: 'Failed to reverse geocode: 404 Not Found' }); }); it('validates country code format', async () => { const tool = new ReverseGeocodeTool(); // Should fail with invalid country code length await expect( tool.run({ longitude: -73.989, latitude: 40.733, country: ['USA'] // Should be 2 characters }) ).resolves.toMatchObject({ isError: true }); }); it('formats GeoJSON response to text with basic information', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: '123 Main Street', full_address: '123 Main Street, New York, NY 10001, United States', feature_type: 'address' }, geometry: { type: 'Point', coordinates: [-73.989, 40.733] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: -73.989, latitude: 40.733 }); 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. 123 Main Street'); expect(textContent).toContain( 'Address: 123 Main Street, New York, NY 10001, United States' ); expect(textContent).toContain('Coordinates: 40.733, -73.989'); expect(textContent).toContain('Type: address'); }); it('formats GeoJSON response with name_preferred', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Manhattan', name_preferred: 'Manhattan Borough', place_formatted: 'Manhattan, New York, NY, United States' }, geometry: { type: 'Point', coordinates: [-73.971, 40.776] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: -73.971, latitude: 40.776 }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. Manhattan (Manhattan Borough)'); expect(textContent).toContain( 'Address: Manhattan, New York, NY, United States' ); expect(textContent).toContain('Coordinates: 40.776, -73.971'); }); it('handles multiple results in formatted text', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: '456 Oak Street', full_address: '456 Oak Street, Brooklyn, NY 11201, United States', feature_type: 'address' }, geometry: { type: 'Point', coordinates: [-73.99, 40.694] } }, { type: 'Feature', properties: { name: '458 Oak Street', full_address: '458 Oak Street, Brooklyn, NY 11201, United States', feature_type: 'address' }, geometry: { type: 'Point', coordinates: [-73.991, 40.695] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: -73.99, latitude: 40.694, limit: 2, types: ['address'] }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. 456 Oak Street'); expect(textContent).toContain('2. 458 Oak Street'); expect(textContent).toContain( '456 Oak Street, Brooklyn, NY 11201, United States' ); expect(textContent).toContain( '458 Oak Street, Brooklyn, NY 11201, United States' ); }); it('handles empty results gracefully', async () => { const mockResponse = { type: 'FeatureCollection', features: [] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: 0.0, latitude: 0.0 }); 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 Location' }, geometry: { type: 'Point', coordinates: [-100.123, 35.456] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: -100.123, latitude: 35.456 }); expect(result.isError).toBe(false); const textContent = (result.content[0] as { type: 'text'; text: string }) .text; expect(textContent).toContain('1. Some Location'); expect(textContent).toContain('Coordinates: 35.456, -100.123'); expect(textContent).not.toContain('Address:'); }); it('returns JSON string format when requested', async () => { const mockResponse = { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Test Address', 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 ReverseGeocodeTool().run({ longitude: -122.676, latitude: 45.515, 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 Location' }, geometry: { type: 'Point', coordinates: [-122.676, 45.515] } } ] }; const mockFetch = setupFetch({ json: async () => mockResponse }); const result = await new ReverseGeocodeTool().run({ longitude: -122.676, latitude: 45.515 }); 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 Location'); }); });

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