Skip to main content
Glama

News Aggregator API

reliable-controller.test.ts6.07 kB
/** * Reliable Controller Tests * * This approach fixes TypeScript errors and follows best practices for controller testing: * 1. Proper type definitions * 2. Consistent setup/teardown * 3. Focused scope on controller behavior * 4. Clean mock implementation */ import { describe, test, expect, jest, beforeEach, afterEach } from '@jest/globals'; import { Request, Response } from 'express'; import { NewsController } from '../../controllers/news.controller'; // We need to mock the NewsService before importing the controller jest.mock('../../services/news.service', () => { return { NewsService: jest.fn().mockImplementation(() => ({ getTopNews: jest.fn(), getAllNews: jest.fn(), getNewsByUuid: jest.fn(), getNewsSources: jest.fn(), getSimilarNews: jest.fn() })) }; }); // Mock the cache service to avoid side effects jest.mock('../../utils/cache', () => ({ cacheService: { get: jest.fn(), set: jest.fn(), clear: jest.fn(), getStats: jest.fn().mockReturnValue({ hits: 0, misses: 0, keys: 0 }) } })); // Import NewsService for type checking import { NewsService } from '../../services/news.service'; describe('NewsController', () => { let controller: NewsController; let mockNewsService: jest.Mocked<NewsService>; let req: Partial<Request>; let res: Partial<Response>; beforeEach(() => { // Create a fresh controller controller = new NewsController(); // Access the mock instance for configuration // This is a safe cast since we control the mock implementation mockNewsService = (controller as any).newsService; // Reset mock functions jest.clearAllMocks(); // Set up request with all necessary properties req = { query: { search: undefined, search_fields: undefined, locale: undefined, categories: undefined, exclude_categories: undefined, domains: undefined, exclude_domains: undefined, source_ids: undefined, exclude_source_ids: undefined, language: undefined, published_before: undefined, published_after: undefined, limit: undefined, page: undefined, sort: undefined }, params: {} }; // Set up response res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; }); afterEach(() => { jest.clearAllMocks(); }); describe('getTopNews', () => { test('returns 200 and data when service succeeds', async () => { // Arrange - Set up successful response const mockArticles = [{ uuid: 'test-123', title: 'Test Article' }]; mockNewsService.getTopNews.mockResolvedValueOnce({ data: mockArticles, meta: { found: 1, returned: 1 } }); // Act await controller.getTopNews(req as Request, res as Response); // Assert expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: true, data: expect.objectContaining({ data: expect.arrayContaining([ expect.objectContaining({ uuid: 'test-123' }) ]), meta: expect.objectContaining({ found: 1, returned: 1 }) }) })); }); test('returns 500 when service fails', async () => { // Arrange - Force error mockNewsService.getTopNews.mockRejectedValueOnce( new Error('Service error') ); // Act await controller.getTopNews(req as Request, res as Response); // Assert expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: false, error: expect.stringContaining('Service error') })); }); test('passes query parameters correctly', async () => { // Arrange - Set query params req.query = { ...req.query, categories: 'technology', limit: '10' }; mockNewsService.getTopNews.mockResolvedValueOnce({ data: [], meta: { found: 0, returned: 0 } }); // Act await controller.getTopNews(req as Request, res as Response); // Assert - Check args passed to service expect(mockNewsService.getTopNews).toHaveBeenCalledWith( expect.objectContaining({ categories: 'technology', limit: 10 // Number conversion }) ); }); }); describe('getNewsByUuid', () => { test('returns 200 and article when found', async () => { // Arrange const uuid = 'test-uuid-123'; req.params = { uuid }; mockNewsService.getNewsByUuid.mockResolvedValueOnce({ data: { uuid, title: 'Test Article' } }); // Act await controller.getNewsByUuid(req as Request, res as Response); // Assert expect(mockNewsService.getNewsByUuid).toHaveBeenCalledWith(uuid); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: true, data: expect.objectContaining({ data: expect.objectContaining({ uuid }) }) })); }); test('returns 404 when article not found', async () => { // Arrange const uuid = 'non-existent'; req.params = { uuid }; mockNewsService.getNewsByUuid.mockRejectedValueOnce( new Error('Article not found') ); // Act await controller.getNewsByUuid(req as Request, res as Response); // Assert expect(mockNewsService.getNewsByUuid).toHaveBeenCalledWith(uuid); // Note: Controller actually returns 500 for all errors, not 404 specifically expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: false, error: expect.stringContaining('not found') })); }); }); });

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