Skip to main content
Glama

News Aggregator API

news-routes-fixed.test.ts8.4 kB
/** * Improved tests for News API endpoints * - Uses dynamic port assignment to avoid conflicts * - Properly shuts down server after tests * - Matches actual API response structure * - Implements better error handling */ import request from 'supertest'; import { Express } from 'express'; import { describe, beforeAll, afterAll, beforeEach, afterEach, test, expect, jest } from '@jest/globals'; import { McpServer } from '../../server'; import { cacheService } from '../../utils/cache'; // Use a separate random port range for each test file const getRandomPort = () => Math.floor(Math.random() * 10000) + 30000; describe('News API Endpoints', () => { let app: Express; let server: McpServer; let port: number; // Setup before all tests beforeAll(async () => { // Generate a random port for this test suite port = getRandomPort(); try { console.log(`Starting news API test server on port ${port}`); // Create and start server server = new McpServer(port); await server.start(); app = server.getApp(); console.log(`News API test server running on port ${port}`); } catch (error) { console.error('Failed to start news API test server:', error); throw error; } }); // Cleanup after all tests afterAll(async () => { try { console.log(`Shutting down news API test server on port ${port}`); if (server) { await server.shutdown(); // Add a delay to ensure all connections are properly closed await new Promise(resolve => setTimeout(resolve, 1000)); } console.log('News API test server successfully shut down'); } catch (error) { console.error('Error during server shutdown:', error); } }); // Reset cache before each test beforeEach(async () => { cacheService.clear(); }); // Test top news retrieval test('GET /api/news/top - should return a list of top news articles', async () => { try { const response = await request(app) .get('/api/news/top') .timeout(5000) // Add timeout to avoid hanging .expect('Content-Type', /json/); // Check response status expect(response.status).toBe(200); // Verify response structure - data is nested in response.body.data.data expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.data).toBeDefined(); expect(Array.isArray(response.body.data.data)).toBe(true); // Log response for debugging if needed // console.log('Response data:', response.body.data); // Skip further assertions if no data returned if (response.body.data.data.length === 0) { console.log('No articles returned from API'); return; } // Verify article properties if data is returned const article = response.body.data.data[0]; expect(article).toHaveProperty('title'); expect(article).toHaveProperty('source'); expect(article).toHaveProperty('published_at'); } catch (error) { console.error('Error in top news test:', error); throw error; } }); // Test category filtering test('GET /api/news/top with category - should filter articles by category', async () => { // Use 'general' as it's a common category across news sources const category = 'general'; try { const response = await request(app) .get(`/api/news/top?category=${category}`) .timeout(5000) .expect('Content-Type', /json/); // Check response status expect(response.status).toBe(200); // Verify response structure expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.data).toBeDefined(); expect(Array.isArray(response.body.data.data)).toBe(true); // Skip further assertions if no data returned if (response.body.data.data.length === 0) { console.log(`No articles returned for category: ${category}`); return; } // Verify that at least one article has the requested category const hasMatchingArticle = response.body.data.data.some( (article: any) => article.categories && (Array.isArray(article.categories) ? article.categories.includes(category) : article.categories === category) ); expect(hasMatchingArticle).toBe(true); } catch (error) { console.error('Error in category filter test:', error); throw error; } }); // Test cache functionality test('GET /api/news/top - should use cache for repeated requests', async () => { try { // Clear cache stats const initialStats = cacheService.getStats() as { hits: number, misses: number, keys: number }; // First request should miss cache await request(app) .get('/api/news/top') .timeout(5000) .expect(200); // Second request should hit cache await request(app) .get('/api/news/top') .timeout(5000) .expect(200); // Get final cache stats const finalStats = cacheService.getStats() as { hits: number, misses: number, keys: number }; // Verify cache hit occurred expect(finalStats.hits).toBeGreaterThan(initialStats.hits); } catch (error) { console.error('Error in cache test:', error); throw error; } }); // Test all news with pagination test('GET /api/news/all - should return all news articles with pagination', async () => { try { const limit = 5; const response = await request(app) .get(`/api/news/all?limit=${limit}`) .timeout(5000) .expect('Content-Type', /json/); // Check response status expect(response.status).toBe(200); // Verify response structure expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.data).toBeDefined(); expect(Array.isArray(response.body.data.data)).toBe(true); // Verify pagination works expect(response.body.data.data.length).toBeLessThanOrEqual(limit); // Check for metadata about pagination expect(response.body.data.meta).toBeDefined(); expect(response.body.data.meta).toHaveProperty('returned'); expect(response.body.data.meta).toHaveProperty('found'); } catch (error) { console.error('Error in pagination test:', error); throw error; } }); // Test UUID-based article retrieval test('GET /api/news/uuid/:uuid - should return a specific article by UUID', async () => { try { // Use a known valid UUID format for testing const testUuid = '123e4567-e89b-12d3-a456-426614174000'; // Request specific article by UUID const response = await request(app) .get(`/api/news/uuid/${testUuid}`) .timeout(5000); // Verify response status expect(response.status).toBe(200); expect(response.body.success).toBe(true); // Check that the data structure is correct expect(response.body.data).toBeDefined(); expect(response.body.data.data).toBeDefined(); // Verify specific article properties expect(response.body.data.data).toHaveProperty('uuid', testUuid); expect(response.body.data.data).toHaveProperty('title'); } catch (error) { console.error('Error in UUID test:', error); throw error; } }); // Test non-existent but valid format UUID test('GET /api/news/uuid/:uuid - should return 404 for non-existent article', async () => { try { // Use a properly formatted UUID that doesn't exist const nonExistentUuid = '00000000-0000-0000-0000-000000000000'; // Request non-existent article by UUID const response = await request(app) .get(`/api/news/uuid/${nonExistentUuid}`) .timeout(5000); // Verify 404 response expect(response.status).toBe(404); expect(response.body.success).toBe(false); expect(response.body.error).toBeDefined(); } catch (error) { console.error('Error in non-existent UUID test:', error); throw error; } }); });

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/Malachi-devel/the-news-api-mcp-server'

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