Spaces:
Paused
Paused
Download __tests__/feedback.controller.test.js from imkrish/yatra-x-feedback: direct link, hf CLI and curl.
- Browser
- Download file 10.7 kB
-
https://huggingface.co/spaces/imkrish/yatra-x-feedback/resolve/main/__tests__/feedback.controller.test.js
- Command line
-
hf download hf://spaces/imkrish/yatra-x-feedback/__tests__/feedback.controller.test.js
-
curl -L -o feedback.controller.test.js https://huggingface.co/spaces/imkrish/yatra-x-feedback/resolve/main/__tests__/feedback.controller.test.js
10.7 kB
| ; | |
| /** | |
| * Feedback Controller Unit Tests | |
| * Tests for feedback event endpoints | |
| */ | |
| // Mock dependencies before requiring the controller | |
| const mockPool = { | |
| query: jest.fn(), | |
| connect: jest.fn(() => ({ | |
| query: jest.fn(), | |
| release: jest.fn() | |
| })) | |
| }; | |
| jest.mock('../src/db', () => ({ | |
| getPool: jest.fn(() => mockPool) | |
| })); | |
| jest.mock('uuid', () => ({ | |
| v4: jest.fn(() => 'mock-uuid-1234') | |
| })); | |
| const feedbackController = require('../src/controllers/feedback.controller'); | |
| const { getPool } = require('../src/db'); | |
| describe('Feedback Controller', () => { | |
| let mockReq; | |
| let mockRes; | |
| let mockPool; | |
| beforeEach(() => { | |
| mockReq = { | |
| body: {}, | |
| query: {}, | |
| params: {} | |
| }; | |
| mockRes = { | |
| status: jest.fn().mockReturnThis(), | |
| json: jest.fn().mockReturnThis() | |
| }; | |
| mockPool = getPool(); | |
| jest.clearAllMocks(); | |
| }); | |
| describe('createFeedbackEvent', () => { | |
| it('should return 400 if event_type is missing', async () => { | |
| mockReq.body = { session_id: 'session-1' }; | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(400); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'event_type is required' } | |
| }); | |
| }); | |
| it('should return 400 for invalid event_type', async () => { | |
| mockReq.body = { event_type: 'invalid_type' }; | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(400); | |
| expect(mockRes.json).toHaveBeenCalledWith( | |
| expect.objectContaining({ | |
| error: expect.objectContaining({ | |
| message: expect.stringContaining('Invalid event_type') | |
| }) | |
| }) | |
| ); | |
| }); | |
| it('should accept all valid event types', async () => { | |
| const validEventTypes = [ | |
| 'plan_saved', 'plan_completed', 'rating_positive', | |
| 'poi_added', 'plan_abandoned', 'poi_removed', | |
| 'rating_negative', 'poi_reordered', 'poi_swapped', 'session_start' | |
| ]; | |
| for (const eventType of validEventTypes) { | |
| mockReq.body = { event_type: eventType }; | |
| mockPool.query.mockResolvedValueOnce({}); | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| // Reset for next iteration | |
| jest.clearAllMocks(); | |
| mockPool = getPool(); | |
| } | |
| }); | |
| it('should create a feedback event successfully', async () => { | |
| mockReq.body = { | |
| event_type: 'plan_saved', | |
| session_id: 'session-123', | |
| user_hash: 'user-hash-456', | |
| context: { destination: 'Ranchi' }, | |
| itinerary_snapshot: [{ poi_id: 'poi-1', name: 'Hundru Falls' }], | |
| modifications: [], | |
| reward: 1.5 | |
| }; | |
| mockPool.query.mockResolvedValueOnce({}); | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(201); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| data: expect.objectContaining({ | |
| id: 'mock-uuid-1234', | |
| event_type: 'plan_saved', | |
| session_id: 'session-123', | |
| reward: 1.5 | |
| }), | |
| message: 'Feedback event recorded successfully' | |
| }); | |
| }); | |
| it('should return 503 if database is not available', async () => { | |
| mockReq.body = { event_type: 'plan_saved' }; | |
| // Override getPool to return null | |
| require('../src/db').getPool.mockReturnValueOnce(null); | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(503); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'Database not available' } | |
| }); | |
| }); | |
| it('should return 500 on database error', async () => { | |
| mockReq.body = { event_type: 'plan_saved' }; | |
| mockPool.query.mockRejectedValueOnce(new Error('DB connection failed')); | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(500); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'Failed to record feedback event' } | |
| }); | |
| }); | |
| it('should use default values for optional fields', async () => { | |
| mockReq.body = { event_type: 'session_start' }; | |
| mockPool.query.mockResolvedValueOnce({}); | |
| await feedbackController.createFeedbackEvent(mockReq, mockRes); | |
| expect(mockPool.query).toHaveBeenCalledWith( | |
| expect.any(String), | |
| expect.arrayContaining([ | |
| 'mock-uuid-1234', | |
| 'session_start', | |
| null, // session_id | |
| null, // user_hash | |
| '{}', // context | |
| '[]', // itinerary_snapshot | |
| '[]', // modifications | |
| 0 // reward | |
| ]) | |
| ); | |
| }); | |
| }); | |
| describe('listFeedbackEvents', () => { | |
| it('should list all feedback events with default pagination', async () => { | |
| const mockEvents = [ | |
| { id: '1', event_type: 'plan_saved' }, | |
| { id: '2', event_type: 'poi_added' } | |
| ]; | |
| mockPool.query.mockResolvedValueOnce({ rows: mockEvents }); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockRes.json).toHaveBeenCalledWith({ data: mockEvents }); | |
| }); | |
| it('should filter by event_type', async () => { | |
| mockReq.query = { event_type: 'plan_saved' }; | |
| mockPool.query.mockResolvedValueOnce({ rows: [] }); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockPool.query).toHaveBeenCalledWith( | |
| expect.stringContaining('event_type = $'), | |
| expect.arrayContaining(['plan_saved']) | |
| ); | |
| }); | |
| it('should filter by session_id', async () => { | |
| mockReq.query = { session_id: 'session-123' }; | |
| mockPool.query.mockResolvedValueOnce({ rows: [] }); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockPool.query).toHaveBeenCalledWith( | |
| expect.stringContaining('session_id = $'), | |
| expect.arrayContaining(['session-123']) | |
| ); | |
| }); | |
| it('should apply custom pagination', async () => { | |
| mockReq.query = { limit: '50', offset: '100' }; | |
| mockPool.query.mockResolvedValueOnce({ rows: [] }); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockPool.query).toHaveBeenCalledWith( | |
| expect.any(String), | |
| expect.arrayContaining([50, 100]) | |
| ); | |
| }); | |
| it('should cap limit at 1000', async () => { | |
| mockReq.query = { limit: '5000' }; | |
| mockPool.query.mockResolvedValueOnce({ rows: [] }); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockPool.query).toHaveBeenCalledWith( | |
| expect.any(String), | |
| expect.arrayContaining([1000]) | |
| ); | |
| }); | |
| it('should return 503 if database is not available', async () => { | |
| require('../src/db').getPool.mockReturnValueOnce(null); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(503); | |
| }); | |
| it('should return 500 on database error', async () => { | |
| mockPool.query.mockRejectedValueOnce(new Error('DB error')); | |
| await feedbackController.listFeedbackEvents(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(500); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'Failed to list feedback events' } | |
| }); | |
| }); | |
| }); | |
| describe('getPOIStats', () => { | |
| it('should return 400 if poi_id is missing', async () => { | |
| mockReq.params = {}; | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(400); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'poi_id is required' } | |
| }); | |
| }); | |
| it('should return aggregated stats for a POI', async () => { | |
| mockReq.params = { poi_id: 'poi-123' }; | |
| const mockEvents = [ | |
| { event_type: 'plan_saved', reward: '1.0', modifications: '[]' }, | |
| { event_type: 'plan_saved', reward: '0.5', modifications: '[]' }, | |
| { event_type: 'poi_removed', reward: '-0.5', modifications: '[{"poi_id": "poi-123"}]' } | |
| ]; | |
| mockPool.query.mockResolvedValueOnce({ rows: mockEvents }); | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| data: expect.objectContaining({ | |
| poi_id: 'poi-123', | |
| times_suggested: 3, | |
| times_saved: 2, | |
| times_removed: 1 | |
| }) | |
| }); | |
| }); | |
| it('should calculate save_rate correctly', async () => { | |
| mockReq.params = { poi_id: 'poi-456' }; | |
| const mockEvents = [ | |
| { event_type: 'plan_saved', reward: '1.0', modifications: '[]' }, | |
| { event_type: 'plan_completed', reward: '1.0', modifications: '[]' } | |
| ]; | |
| mockPool.query.mockResolvedValueOnce({ rows: mockEvents }); | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| data: expect.objectContaining({ | |
| times_saved: 1, | |
| times_suggested: 2, | |
| save_rate: '0.50' | |
| }) | |
| }); | |
| }); | |
| it('should return zero stats for POI with no events', async () => { | |
| mockReq.params = { poi_id: 'new-poi' }; | |
| mockPool.query.mockResolvedValueOnce({ rows: [] }); | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| data: expect.objectContaining({ | |
| poi_id: 'new-poi', | |
| times_suggested: 0, | |
| times_saved: 0, | |
| times_removed: 0, | |
| avg_reward: 0, | |
| save_rate: 0 | |
| }) | |
| }); | |
| }); | |
| it('should return 503 if database is not available', async () => { | |
| mockReq.params = { poi_id: 'poi-123' }; | |
| require('../src/db').getPool.mockReturnValueOnce(null); | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(503); | |
| }); | |
| it('should return 500 on database error', async () => { | |
| mockReq.params = { poi_id: 'poi-123' }; | |
| mockPool.query.mockRejectedValueOnce(new Error('DB error')); | |
| await feedbackController.getPOIStats(mockReq, mockRes); | |
| expect(mockRes.status).toHaveBeenCalledWith(500); | |
| expect(mockRes.json).toHaveBeenCalledWith({ | |
| error: { message: 'Failed to get POI stats' } | |
| }); | |
| }); | |
| }); | |
| }); | |