more backend unit test coverage
This commit is contained in:
244
backend/tests/unit/routes/feedback.test.js
Normal file
244
backend/tests/unit/routes/feedback.test.js
Normal file
@@ -0,0 +1,244 @@
|
||||
const request = require('supertest');
|
||||
const express = require('express');
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock('../../../models', () => ({
|
||||
Feedback: {
|
||||
create: jest.fn(),
|
||||
},
|
||||
User: {
|
||||
findByPk: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../middleware/auth', () => ({
|
||||
authenticateToken: (req, res, next) => {
|
||||
req.user = { id: 'user-123', email: 'test@example.com' };
|
||||
next();
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../middleware/validation', () => ({
|
||||
validateFeedback: (req, res, next) => next(),
|
||||
sanitizeInput: (req, res, next) => next(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../services/email', () => ({
|
||||
feedback: {
|
||||
sendFeedbackConfirmation: jest.fn(),
|
||||
sendFeedbackNotificationToAdmin: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/logger', () => ({
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
withRequestId: jest.fn(() => ({
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
const { Feedback } = require('../../../models');
|
||||
const emailServices = require('../../../services/email');
|
||||
const feedbackRoutes = require('../../../routes/feedback');
|
||||
|
||||
describe('Feedback Routes', () => {
|
||||
let app;
|
||||
|
||||
beforeEach(() => {
|
||||
app = express();
|
||||
app.use(express.json());
|
||||
app.use('/feedback', feedbackRoutes);
|
||||
|
||||
// Add error handler
|
||||
app.use((err, req, res, next) => {
|
||||
res.status(500).json({ error: err.message });
|
||||
});
|
||||
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('POST /feedback', () => {
|
||||
it('should create feedback successfully', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
userId: 'user-123',
|
||||
feedbackText: 'Great app!',
|
||||
url: 'https://example.com/page',
|
||||
userAgent: 'Mozilla/5.0',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.set('User-Agent', 'Mozilla/5.0')
|
||||
.send({
|
||||
feedbackText: 'Great app!',
|
||||
url: 'https://example.com/page',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(response.body.id).toBe('feedback-123');
|
||||
expect(response.body.feedbackText).toBe('Great app!');
|
||||
expect(Feedback.create).toHaveBeenCalledWith({
|
||||
userId: 'user-123',
|
||||
feedbackText: 'Great app!',
|
||||
url: 'https://example.com/page',
|
||||
userAgent: 'Mozilla/5.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should send confirmation email to user', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(emailServices.feedback.sendFeedbackConfirmation).toHaveBeenCalledWith(
|
||||
{ id: 'user-123', email: 'test@example.com' },
|
||||
mockFeedback
|
||||
);
|
||||
});
|
||||
|
||||
it('should send notification email to admin', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(emailServices.feedback.sendFeedbackNotificationToAdmin).toHaveBeenCalledWith(
|
||||
{ id: 'user-123', email: 'test@example.com' },
|
||||
mockFeedback
|
||||
);
|
||||
});
|
||||
|
||||
it('should succeed even if confirmation email fails', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockRejectedValue(new Error('Email failed'));
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
});
|
||||
|
||||
it('should succeed even if admin notification email fails', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockRejectedValue(new Error('Email failed'));
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
});
|
||||
|
||||
it('should handle feedback with null url', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
url: null,
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
expect(Feedback.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
url: null,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should capture user agent from headers', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
userAgent: 'CustomUserAgent/1.0',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
await request(app)
|
||||
.post('/feedback')
|
||||
.set('User-Agent', 'CustomUserAgent/1.0')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(Feedback.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
userAgent: 'CustomUserAgent/1.0',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle missing user agent', async () => {
|
||||
const mockFeedback = {
|
||||
id: 'feedback-123',
|
||||
feedbackText: 'Great app!',
|
||||
};
|
||||
|
||||
Feedback.create.mockResolvedValue(mockFeedback);
|
||||
emailServices.feedback.sendFeedbackConfirmation.mockResolvedValue();
|
||||
emailServices.feedback.sendFeedbackNotificationToAdmin.mockResolvedValue();
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
});
|
||||
|
||||
it('should return 500 when database error occurs', async () => {
|
||||
Feedback.create.mockRejectedValue(new Error('Database error'));
|
||||
|
||||
const response = await request(app)
|
||||
.post('/feedback')
|
||||
.send({ feedbackText: 'Great app!' });
|
||||
|
||||
expect(response.status).toBe(500);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user