Skip to main content
Glama
Meloyg

MCP Weather Server

by Meloyg
weather-tool.test.ts18.1 kB
import { getWeatherTool } from "../src/tools/weather-tool"; import { WeatherAPI } from "../src/utils/api"; import { WeatherResponse } from "../src/types/weather"; // Mock the WeatherAPI class jest.mock("../src/utils/api"); const mockedWeatherAPI = WeatherAPI as jest.Mocked<typeof WeatherAPI>; describe("getWeatherTool", () => { beforeEach(() => { jest.clearAllMocks(); // Clear console.error mock calls jest.spyOn(console, "error").mockImplementation(() => {}); }); afterEach(() => { jest.restoreAllMocks(); }); describe("Successful weather requests", () => { it("should return weather data for a valid city", async () => { // Arrange const city = "London"; const mockCoordinates = { latitude: 51.5074, longitude: -0.1278 }; const mockWeatherData = { current_weather: { temperature: 15.5, windspeed: 12.3, winddirection: 180, weathercode: 0, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in London is 15.5°C with a wind speed of 12.3 km/h.", }, ], }); expect(mockedWeatherAPI.getCoordinates).toHaveBeenCalledWith("London"); expect(mockedWeatherAPI.getCurrentWeather).toHaveBeenCalledWith( 51.5074, -0.1278 ); }); it("should handle cities with special characters", async () => { // Arrange const city = "São Paulo"; const mockCoordinates = { latitude: -23.5505, longitude: -46.6333 }; const mockWeatherData = { current_weather: { temperature: 22.0, windspeed: 8.5, winddirection: 90, weathercode: 1, is_day: 1, time: "2023-01-01T15:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in São Paulo is 22°C with a wind speed of 8.5 km/h.", }, ], }); }); it("should handle cities with spaces and multiple words", async () => { // Arrange const city = "New York City"; const mockCoordinates = { latitude: 40.7128, longitude: -74.006 }; const mockWeatherData = { current_weather: { temperature: 18.7, windspeed: 15.2, winddirection: 270, weathercode: 2, is_day: 0, time: "2023-01-01T20:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in New York City is 18.7°C with a wind speed of 15.2 km/h.", }, ], }); }); it("should handle negative temperatures", async () => { // Arrange const city = "Moscow"; const mockCoordinates = { latitude: 55.7558, longitude: 37.6176 }; const mockWeatherData = { current_weather: { temperature: -10.5, windspeed: 20.1, winddirection: 45, weathercode: 71, is_day: 1, time: "2023-01-01T10:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Moscow is -10.5°C with a wind speed of 20.1 km/h.", }, ], }); }); it("should handle zero temperature and wind speed", async () => { // Arrange const city = "Reykjavik"; const mockCoordinates = { latitude: 64.1466, longitude: -21.9426 }; const mockWeatherData = { current_weather: { temperature: 0, windspeed: 0, winddirection: 0, weathercode: 0, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Reykjavik is 0°C with a wind speed of 0 km/h.", }, ], }); }); }); describe("Error handling - Geocoding failures", () => { it("should handle city not found (null coordinates)", async () => { // Arrange const city = "NonExistentCity"; mockedWeatherAPI.getCoordinates.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not find location for city: NonExistentCity", }, ], }); expect(mockedWeatherAPI.getCoordinates).toHaveBeenCalledWith( "NonExistentCity" ); expect(mockedWeatherAPI.getCurrentWeather).not.toHaveBeenCalled(); }); it("should handle empty city name", async () => { // Arrange const city = ""; mockedWeatherAPI.getCoordinates.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not find location for city: ", }, ], }); }); it("should handle city with only whitespace", async () => { // Arrange const city = " "; mockedWeatherAPI.getCoordinates.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not find location for city: ", }, ], }); }); it("should handle very long city names", async () => { // Arrange const city = "A".repeat(1000); mockedWeatherAPI.getCoordinates.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: `Could not find location for city: ${city}`, }, ], }); }); }); describe("Error handling - Weather API failures", () => { it("should handle weather API returning null", async () => { // Arrange const city = "London"; const mockCoordinates = { latitude: 51.5074, longitude: -0.1278 }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not retrieve weather data for city: London", }, ], }); expect(mockedWeatherAPI.getCoordinates).toHaveBeenCalledWith("London"); expect(mockedWeatherAPI.getCurrentWeather).toHaveBeenCalledWith( 51.5074, -0.1278 ); }); it("should handle extreme coordinates", async () => { // Arrange const city = "North Pole"; const mockCoordinates = { latitude: 90, longitude: 0 }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not retrieve weather data for city: North Pole", }, ], }); expect(mockedWeatherAPI.getCurrentWeather).toHaveBeenCalledWith(90, 0); }); }); describe("Error handling - Exception scenarios", () => { it("should handle geocoding API throwing an error", async () => { // Arrange const city = "London"; const error = new Error("Network error"); mockedWeatherAPI.getCoordinates.mockRejectedValue(error); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not retrieve weather data for city: London", }, ], }); }); it("should handle weather API throwing an error", async () => { // Arrange const city = "London"; const mockCoordinates = { latitude: 51.5074, longitude: -0.1278 }; const error = new Error("Weather API error"); mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockRejectedValue(error); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not retrieve weather data for city: London", }, ], }); }); it("should handle timeout errors", async () => { // Arrange const city = "Tokyo"; const timeoutError = new Error("Request timeout"); mockedWeatherAPI.getCoordinates.mockRejectedValue(timeoutError); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "Could not retrieve weather data for city: Tokyo", }, ], }); }); }); describe("Edge cases and boundary conditions", () => { it("should handle very high temperatures", async () => { // Arrange const city = "Death Valley"; const mockCoordinates = { latitude: 36.5323, longitude: -116.9325 }; const mockWeatherData = { current_weather: { temperature: 54.4, windspeed: 5.0, winddirection: 180, weathercode: 0, is_day: 1, time: "2023-07-01T14:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Death Valley is 54.4°C with a wind speed of 5 km/h.", }, ], }); }); it("should handle very low temperatures", async () => { // Arrange const city = "Antarctica"; const mockCoordinates = { latitude: -82.8628, longitude: 135.0 }; const mockWeatherData = { current_weather: { temperature: -89.2, windspeed: 100.5, winddirection: 270, weathercode: 71, is_day: 0, time: "2023-07-01T02:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Antarctica is -89.2°C with a wind speed of 100.5 km/h.", }, ], }); }); it("should handle very high wind speeds", async () => { // Arrange const city = "Hurricane Zone"; const mockCoordinates = { latitude: 25.7617, longitude: -80.1918 }; const mockWeatherData = { current_weather: { temperature: 25.0, windspeed: 250.7, winddirection: 45, weathercode: 95, is_day: 1, time: "2023-09-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Hurricane Zone is 25°C with a wind speed of 250.7 km/h.", }, ], }); }); it("should handle decimal precision in temperature and wind speed", async () => { // Arrange const city = "Precision City"; const mockCoordinates = { latitude: 40.0, longitude: -74.0 }; const mockWeatherData = { current_weather: { temperature: 15.123456789, windspeed: 12.987654321, winddirection: 180, weathercode: 0, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in Precision City is 15.123456789°C with a wind speed of 12.987654321 km/h.", }, ], }); }); }); describe("Input validation and sanitization", () => { it("should handle cities with numbers", async () => { // Arrange const city = "City123"; const mockCoordinates = { latitude: 40.0, longitude: -74.0 }; const mockWeatherData = { current_weather: { temperature: 20.0, windspeed: 10.0, winddirection: 180, weathercode: 0, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in City123 is 20°C with a wind speed of 10 km/h.", }, ], }); }); it("should handle cities with hyphens and apostrophes", async () => { // Arrange const city = "St. John's-on-the-Lake"; const mockCoordinates = { latitude: 45.0, longitude: -75.0 }; const mockWeatherData = { current_weather: { temperature: 12.5, windspeed: 8.3, winddirection: 90, weathercode: 1, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toEqual({ content: [ { type: "text", text: "The current temperature in St. John's-on-the-Lake is 12.5°C with a wind speed of 8.3 km/h.", }, ], }); }); }); describe("Response format validation", () => { it("should return response in correct WeatherResponse format", async () => { // Arrange const city = "London"; const mockCoordinates = { latitude: 51.5074, longitude: -0.1278 }; const mockWeatherData = { current_weather: { temperature: 15.5, windspeed: 12.3, winddirection: 180, weathercode: 0, is_day: 1, time: "2023-01-01T12:00", }, }; mockedWeatherAPI.getCoordinates.mockResolvedValue(mockCoordinates); mockedWeatherAPI.getCurrentWeather.mockResolvedValue(mockWeatherData); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toHaveProperty("content"); expect(Array.isArray(result.content)).toBe(true); expect(result.content).toHaveLength(1); expect(result.content[0]).toHaveProperty("type", "text"); expect(result.content[0]).toHaveProperty("text"); expect(typeof result.content[0].text).toBe("string"); }); it("should return error response in correct WeatherResponse format", async () => { // Arrange const city = "NonExistentCity"; mockedWeatherAPI.getCoordinates.mockResolvedValue(null); // Act const result = await getWeatherTool({ city }); // Assert expect(result).toHaveProperty("content"); expect(Array.isArray(result.content)).toBe(true); expect(result.content).toHaveLength(1); expect(result.content[0]).toHaveProperty("type", "text"); expect(result.content[0]).toHaveProperty("text"); expect(typeof result.content[0].text).toBe("string"); expect(result.content[0].text).toContain( "Could not find location for city" ); }); }); });

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/Meloyg/life-assitant-mcp'

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