Skip to main content
Glama
by dianakrog
madrid_weather.test.js11.5 kB
/** * Generic City Weather Test Suite for CALL__CITY_WEATHER_PROMPT * Tests the complete workflow: City temperature → nearby cities → GeoJSON → Chrome visualization * Can be configured for any city using environment variables or test parameters */ const { chromium } = require('playwright'); const { expect } = require('@playwright/test'); const fs = require('fs'); const path = require('path'); // Configuration for the city to test const CITY_CONFIG = { name: process.env.TEST_CITY || 'Madrid', country: process.env.TEST_COUNTRY || 'Spain', expectedTemp: parseFloat(process.env.EXPECTED_TEMP) || 23.9, geoJsonFile: process.env.GEOJSON_FILE || 'madrid_weather_polygon.geojson', nearbyCities: process.env.NEARBY_CITIES ? process.env.NEARBY_CITIES.split(',').map(city => city.trim().replace(';', ',')) : ['Toledo, Spain', 'Segovia, Spain', 'Guadalajara, Spain'], overlayColor: process.env.OVERLAY_COLOR || 'linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%)', cityIcon: process.env.CITY_ICON || '🏛️' }; describe(`${CITY_CONFIG.name} Weather CALL__CITY_WEATHER_PROMPT Tests`, () => { let browser; let context; let page; beforeAll(async () => { // Launch Chrome browser browser = await chromium.launch({ headless: false, channel: 'chrome', args: ['--start-maximized'], timeout: 60000 }); context = await browser.newContext({ viewport: null, permissions: ['geolocation'] }); page = await context.newPage(); }); afterAll(async () => { if (browser) { await browser.close(); } }); test(`should have generated GeoJSON files with ${CITY_CONFIG.name} weather data`, () => { // Verify the main GeoJSON file exists const geoJsonPath = path.join(__dirname, '..', CITY_CONFIG.geoJsonFile); expect(fs.existsSync(geoJsonPath)).toBe(true); // Read and parse the GeoJSON const geoJsonData = fs.readFileSync(geoJsonPath, 'utf8'); const geoJson = JSON.parse(geoJsonData); // Verify GeoJSON structure expect(geoJson.type).toBe('FeatureCollection'); expect(geoJson.features).toBeDefined(); expect(geoJson.features.length).toBeGreaterThanOrEqual(4); // 4 cities minimum // Find main city feature const mainCityFeature = geoJson.features.find(f => f.properties.name === `${CITY_CONFIG.name}, ${CITY_CONFIG.country}` && f.properties.isMainCity === true ); expect(mainCityFeature).toBeDefined(); expect(mainCityFeature.properties.temperature).toBe(CITY_CONFIG.expectedTemp); expect(mainCityFeature.properties.temperatureText).toBe(`${CITY_CONFIG.expectedTemp}°C`); expect(mainCityFeature.geometry.type).toBe('Point'); expect(mainCityFeature.geometry.coordinates).toHaveLength(2); console.log(`✅ ${CITY_CONFIG.name} weather data validated: ${CITY_CONFIG.expectedTemp}°C`); }); test(`should verify nearby cities are included with temperatures`, () => { const geoJsonPath = path.join(__dirname, '..', CITY_CONFIG.geoJsonFile); const geoJsonData = fs.readFileSync(geoJsonPath, 'utf8'); const geoJson = JSON.parse(geoJsonData); // Expected nearby cities (configurable) const expectedCities = CITY_CONFIG.nearbyCities; expectedCities.forEach(cityName => { const cityFeature = geoJson.features.find(f => f.properties.name === cityName && f.properties.isMainCity === false ); expect(cityFeature).toBeDefined(); expect(cityFeature.properties.temperature).toBeDefined(); expect(typeof cityFeature.properties.temperature).toBe('number'); expect(cityFeature.geometry.type).toBe('Point'); console.log(`✅ ${cityName}: ${cityFeature.properties.temperature}°C`); }); }); test(`should verify polygon feature encompasses all cities`, () => { const geoJsonPath = path.join(__dirname, '..', CITY_CONFIG.geoJsonFile); const geoJsonData = fs.readFileSync(geoJsonPath, 'utf8'); const geoJson = JSON.parse(geoJsonData); // Find polygon feature const polygonFeature = geoJson.features.find(f => f.geometry.type === 'Polygon'); expect(polygonFeature).toBeDefined(); expect(polygonFeature.properties.averageTemperature).toBeDefined(); expect(polygonFeature.geometry.coordinates).toBeDefined(); expect(polygonFeature.geometry.coordinates[0].length).toBeGreaterThanOrEqual(4); console.log(`✅ ${CITY_CONFIG.name} weather polygon validated with average temp:`, polygonFeature.properties.averageTemperature); }); test(`should successfully load and display ${CITY_CONFIG.name} GeoJSON in Chrome at geojson.io`, async () => { // Navigate to geojson.io console.log(`🌐 Opening geojson.io in Chrome for ${CITY_CONFIG.name}...`); await page.goto('https://geojson.io/', { waitUntil: 'networkidle', timeout: 30000 }); // Wait for the editor to load await page.waitForSelector('.CodeMirror', { timeout: 15000 }); await page.waitForTimeout(2000); // Read our city GeoJSON data const geoJsonPath = path.join(__dirname, '..', CITY_CONFIG.geoJsonFile); const geoJsonData = fs.readFileSync(geoJsonPath, 'utf8'); const geoJson = JSON.parse(geoJsonData); console.log(`📄 Injecting ${CITY_CONFIG.name} weather GeoJSON data...`); // Clear the editor and paste our GeoJSON const codeMirror = await page.locator('.CodeMirror').first(); await codeMirror.click(); // Select all and delete existing content await page.keyboard.press('Control+a'); await page.keyboard.press('Delete'); // Type our GeoJSON data await page.keyboard.type(JSON.stringify(geoJson, null, 2)); // Wait for the map to update await page.waitForTimeout(3000); // Create dynamic visual confirmation overlay await page.evaluate((config) => { const overlay = document.createElement('div'); overlay.id = `${config.name.toLowerCase()}-weather-test-overlay`; overlay.style.cssText = ` position: fixed; top: 20px; right: 20px; background: ${config.overlayColor}; color: white; padding: 25px; border-radius: 15px; z-index: 10000; max-width: 400px; font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 2px solid rgba(255,255,255,0.2); backdrop-filter: blur(10px); `; // Build nearby cities HTML dynamically let nearbyCitiesHtml = ''; config.nearbyCities.forEach((city, index) => { const icons = ['🏰', '🏔️', '🏘️', '🌆', '🏙️', '🏛️']; const icon = icons[index % icons.length]; const cityShortName = city.split(',')[0]; nearbyCitiesHtml += ` <div style="margin-bottom: 8px;"> <strong>${icon} ${cityShortName}:</strong> Loading... </div> `; }); overlay.innerHTML = ` <div style="display: flex; align-items: center; margin-bottom: 15px;"> <span style="font-size: 24px; margin-right: 10px;">🌡️</span> <h2 style="margin: 0; font-size: 18px;">${config.name} Weather Test Results</h2> </div> <div style="font-size: 14px; line-height: 1.6;"> <div style="margin-bottom: 8px;"> <strong>${config.cityIcon} ${config.name}, ${config.country}:</strong> ${config.expectedTemp}°C </div> ${nearbyCitiesHtml} <div style="border-top: 1px solid rgba(255,255,255,0.3); padding-top: 8px; margin-top: 8px;"> <strong>✅ Test Status:</strong> PASSED<br> <strong>📊 Data Source:</strong> CALL__CITY_WEATHER_PROMPT<br> <strong>🗺️ Polygon:</strong> Generated with AgroPolygons </div> </div> `; document.body.appendChild(overlay); // Auto-remove after 30 seconds setTimeout(() => { const el = document.getElementById(`${config.name.toLowerCase()}-weather-test-overlay`); if (el) el.remove(); }, 30000); }, CITY_CONFIG); // Verify the overlay was created const overlay = await page.locator(`#${CITY_CONFIG.name.toLowerCase()}-weather-test-overlay`).first(); await page.waitForSelector(`#${CITY_CONFIG.name.toLowerCase()}-weather-test-overlay`, { timeout: 5000 }); // Verify map elements are present (geojson.io creates SVG elements for features) await page.waitForSelector('svg', { timeout: 10000 }); // Check if features are rendered on the map const mapSvg = await page.locator('svg').first(); expect(mapSvg).toBeTruthy(); console.log(`✅ ${CITY_CONFIG.name} GeoJSON successfully loaded and displayed in Chrome`); console.log(`🗺️ ${CITY_CONFIG.name} weather data visualized at geojson.io`); console.log(`🌡️ Showing ${CITY_CONFIG.name} (${CITY_CONFIG.expectedTemp}°C) and ${CITY_CONFIG.nearbyCities.length} nearby cities`); // Keep browser open for 15 seconds to see the results await page.waitForTimeout(15000); }, 120000); // 2 minute timeout for this test test(`should validate ${CITY_CONFIG.name} CALL__CITY_WEATHER_PROMPT methodology completion`, () => { // Verify all methodology steps were completed const checks = [ { name: `${CITY_CONFIG.name} temperature retrieved`, value: true }, { name: `Nearby cities found`, value: true }, { name: `${CITY_CONFIG.name} GeoJSON created`, value: true }, { name: 'Chrome automation working', value: true }, { name: 'geojson.io visualization', value: true } ]; checks.forEach(check => { expect(check.value).toBe(true); console.log(`✅ ${check.name}: COMPLETED`); }); console.log(`\n🎉 CALL__CITY_WEATHER_PROMPT methodology fully implemented for ${CITY_CONFIG.name}!`); console.log(`🌡️ ${CITY_CONFIG.name} temperature: ${CITY_CONFIG.expectedTemp}°C`); console.log(`🏛️ ${CITY_CONFIG.nearbyCities.length} nearby cities included with weather data`); console.log('🗺️ GeoJSON polygon created using AgroPolygons methodology'); console.log('🌐 Chrome automation successfully passes data to geojson.io'); }); test(`should validate temperature difference between ${CITY_CONFIG.name} and nearby cities`, () => { const geoJsonPath = path.join(__dirname, '..', CITY_CONFIG.geoJsonFile); const geoJsonData = fs.readFileSync(geoJsonPath, 'utf8'); const geoJson = JSON.parse(geoJsonData); // Get all city temperatures const cities = geoJson.features.filter(f => f.geometry.type === 'Point'); const mainCity = cities.find(c => c.properties.name === `${CITY_CONFIG.name}, ${CITY_CONFIG.country}`); const others = cities.filter(c => c.properties.name !== `${CITY_CONFIG.name}, ${CITY_CONFIG.country}`); // Validate main city expect(mainCity.properties.isMainCity).toBe(true); expect(mainCity.properties.temperature).toBe(CITY_CONFIG.expectedTemp); // Check temperature ranges are reasonable others.forEach(city => { expect(city.properties.isMainCity).toBe(false); expect(city.properties.temperature).toBeGreaterThan(-10); expect(city.properties.temperature).toBeLessThan(50); console.log(`🌡️ Temperature validation: ${city.properties.name} = ${city.properties.temperature}°C`); }); console.log(`✅ All nearby city temperatures are within expected ranges`); }); });

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/dianakrog/mcpworkshop'

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