reliable-controller.test.ts•4.76 kB
/**
* Reliable unit tests for News Controller with proper mocking
*/
import { describe, test, expect, beforeEach, jest } from '@jest/globals';
import { Request, Response } from 'express';
import { cacheService } from '../utils/cache';
// Mock the NewsService before importing the controller
const mockGetTopNews = jest.fn();
const mockGetAllNews = jest.fn();
const mockGetNewsByUuid = jest.fn();
jest.mock('../services/news.service', () => {
return {
// This is the key part - we need to mock the class itself
NewsService: jest.fn().mockImplementation(() => ({
getTopNews: mockGetTopNews,
getAllNews: mockGetAllNews,
getNewsByUuid: mockGetNewsByUuid
}))
};
});
// Import the controller after setting up mocks
import { NewsController } from '../controllers/news.controller';
describe('News Controller', () => {
let newsController: NewsController;
let mockReq: Partial<Request>;
let mockRes: Partial<Response>;
beforeEach(() => {
// Reset mocks
jest.clearAllMocks();
mockGetTopNews.mockReset();
mockGetAllNews.mockReset();
mockGetNewsByUuid.mockReset();
// Clear cache
cacheService.clear();
// Create a new controller instance
newsController = new NewsController();
// Set up mock request and response objects
mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis()
};
mockReq = {
query: {},
params: {}
};
});
test('getTopNews returns 200 with articles when successful', async () => {
// Arrange
const mockArticles = [
{ uuid: 'abc123', title: 'Test Article', source: 'Test Source' }
];
mockGetTopNews.mockResolvedValueOnce({
data: mockArticles,
meta: { found: 1, returned: 1 }
});
// Act
await newsController.getTopNews(mockReq as Request, mockRes as Response);
// Assert
expect(mockRes.status).toHaveBeenCalledWith(200);
expect(mockRes.json).toHaveBeenCalledWith({
success: true,
data: mockArticles,
meta: { found: 1, returned: 1 }
});
});
test('getTopNews handles filtering parameters correctly', async () => {
// Arrange
mockReq.query = { categories: 'technology' };
mockGetTopNews.mockResolvedValueOnce({
data: [{ uuid: 'tech123', title: 'Tech Article', categories: ['technology'] }],
meta: { found: 1, returned: 1 }
});
// Act
await newsController.getTopNews(mockReq as Request, mockRes as Response);
// Assert
expect(mockGetTopNews).toHaveBeenCalledWith(expect.objectContaining({
categories: 'technology'
}));
expect(mockRes.status).toHaveBeenCalledWith(200);
});
test('getAllNews returns paginated results', async () => {
// Arrange
mockReq.query = { page: '2', limit: '10' };
mockGetAllNews.mockResolvedValueOnce({
data: [{ uuid: 'page2-1', title: 'Page 2 Article 1' }],
meta: { found: 25, returned: 1, page: 2, limit: 10 }
});
// Act
await newsController.getAllNews(mockReq as Request, mockRes as Response);
// Assert
expect(mockGetAllNews).toHaveBeenCalledWith(expect.objectContaining({
page: 2,
limit: 10
}));
expect(mockRes.status).toHaveBeenCalledWith(200);
expect(mockRes.json).toHaveBeenCalledWith({
success: true,
data: expect.any(Array),
meta: expect.objectContaining({
page: 2,
limit: 10
})
});
});
test('getNewsByUuid returns a specific article', async () => {
// Arrange
mockReq.params = { uuid: 'test-uuid-1' };
mockGetNewsByUuid.mockResolvedValueOnce({
data: {
uuid: 'test-uuid-1',
title: 'Test Article',
source: 'Test Source'
}
});
// Act
await newsController.getNewsByUuid(mockReq as Request, mockRes as Response);
// Assert
expect(mockGetNewsByUuid).toHaveBeenCalledWith('test-uuid-1');
expect(mockRes.status).toHaveBeenCalledWith(200);
expect(mockRes.json).toHaveBeenCalledWith({
success: true,
data: expect.objectContaining({
uuid: 'test-uuid-1'
})
});
});
test('getNewsByUuid returns 404 for non-existent article', async () => {
// Arrange
mockReq.params = { uuid: 'non-existent' };
// Simulate article not found error
mockGetNewsByUuid.mockRejectedValueOnce(new Error('Article not found'));
// Act
await newsController.getNewsByUuid(mockReq as Request, mockRes as Response);
// Assert
expect(mockRes.status).toHaveBeenCalledWith(404);
expect(mockRes.json).toHaveBeenCalledWith({
success: false,
error: expect.any(String)
});
});
});