the-tip-top-backend/test/unit/middleware.test.js
soufiane 614abeb196 test: add comprehensive unit and integration tests
Backend Tests Added:
- Unit tests for helpers.js (tokens, validation, pagination)
- Unit tests for middleware (auth, errorHandler, validate)
- Integration tests for auth endpoints
- Integration tests for game endpoints
- Integration tests for admin endpoints
- Integration tests for employee endpoints
- Integration tests for draw endpoints
- Integration tests for newsletter/contact endpoints

Also added:
- cross-env for Windows compatibility
- Test scripts update

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 11:23:43 +01:00

218 lines
5.6 KiB
JavaScript

/**
* Tests unitaires pour src/middleware/
*/
import { jest } from '@jest/globals';
// Mock du pool de base de données
jest.unstable_mockModule('../../db.js', () => ({
pool: {
query: jest.fn(),
},
}));
const { pool } = await import('../../db.js');
const { authenticateToken, authorizeRoles, optionalAuth } = await import('../../src/middleware/auth.js');
const { AppError, errorHandler, asyncHandler } = await import('../../src/middleware/errorHandler.js');
const { validate } = await import('../../src/middleware/validate.js');
describe('Auth Middleware', () => {
let mockReq;
let mockRes;
let mockNext;
beforeEach(() => {
mockReq = {
headers: {},
cookies: {},
};
mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
};
mockNext = jest.fn();
jest.clearAllMocks();
});
describe('authenticateToken', () => {
it('should return 401 if no token provided', async () => {
await authenticateToken(mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(401);
expect(mockRes.json).toHaveBeenCalledWith(
expect.objectContaining({
success: false,
})
);
expect(mockNext).not.toHaveBeenCalled();
});
it('should return 401 for invalid token', async () => {
mockReq.headers.authorization = 'Bearer invalid-token';
await authenticateToken(mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(401);
expect(mockNext).not.toHaveBeenCalled();
});
});
describe('authorizeRoles', () => {
it('should call next if user has required role', () => {
mockReq.user = { role: 'ADMIN' };
const middleware = authorizeRoles('ADMIN', 'EMPLOYEE');
middleware(mockReq, mockRes, mockNext);
expect(mockNext).toHaveBeenCalled();
});
it('should return 403 if user lacks required role', () => {
mockReq.user = { role: 'CLIENT' };
const middleware = authorizeRoles('ADMIN');
middleware(mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(403);
expect(mockNext).not.toHaveBeenCalled();
});
});
describe('optionalAuth', () => {
it('should call next without user if no token', async () => {
await optionalAuth(mockReq, mockRes, mockNext);
expect(mockNext).toHaveBeenCalled();
expect(mockReq.user).toBeUndefined();
});
});
});
describe('Error Handler Middleware', () => {
let mockReq;
let mockRes;
let mockNext;
beforeEach(() => {
mockReq = {};
mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
};
mockNext = jest.fn();
});
describe('AppError', () => {
it('should create an operational error', () => {
const error = new AppError('Test error', 400);
expect(error.message).toBe('Test error');
expect(error.statusCode).toBe(400);
expect(error.isOperational).toBe(true);
});
});
describe('errorHandler', () => {
it('should handle AppError with correct status', () => {
const error = new AppError('Not found', 404);
errorHandler(error, mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(404);
expect(mockRes.json).toHaveBeenCalledWith(
expect.objectContaining({
success: false,
message: 'Not found',
})
);
});
it('should handle generic errors with 500', () => {
const error = new Error('Something went wrong');
errorHandler(error, mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(500);
});
});
describe('asyncHandler', () => {
it('should pass errors to next middleware', async () => {
const error = new Error('Async error');
const asyncFn = async () => {
throw error;
};
const wrappedFn = asyncHandler(asyncFn);
await wrappedFn(mockReq, mockRes, mockNext);
expect(mockNext).toHaveBeenCalledWith(error);
});
it('should not call next on success', async () => {
const asyncFn = async (req, res) => {
res.json({ success: true });
};
const wrappedFn = asyncHandler(asyncFn);
await wrappedFn(mockReq, mockRes, mockNext);
expect(mockRes.json).toHaveBeenCalledWith({ success: true });
expect(mockNext).not.toHaveBeenCalled();
});
});
});
describe('Validation Middleware', () => {
let mockReq;
let mockRes;
let mockNext;
beforeEach(() => {
mockReq = {
body: {},
query: {},
params: {},
};
mockRes = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
};
mockNext = jest.fn();
});
describe('validate', () => {
it('should call next for valid data', async () => {
const { z } = await import('zod');
const schema = z.object({
body: z.object({
email: z.string().email(),
}),
});
mockReq.body = { email: 'test@example.com' };
const middleware = validate(schema);
await middleware(mockReq, mockRes, mockNext);
expect(mockNext).toHaveBeenCalled();
});
it('should return 400 for invalid data', async () => {
const { z } = await import('zod');
const schema = z.object({
body: z.object({
email: z.string().email(),
}),
});
mockReq.body = { email: 'invalid-email' };
const middleware = validate(schema);
await middleware(mockReq, mockRes, mockNext);
expect(mockRes.status).toHaveBeenCalledWith(400);
expect(mockNext).not.toHaveBeenCalled();
});
});
});