Files

207 lines
8.3 KiB
TypeScript

import { ValidationMiddleware } from '../../../src/Application/Services/ValidationMiddleware';
import { Request, Response, NextFunction } from 'express';
import { ErrorResponseService } from '../../../src/Application/Services/ErrorResponseService';
jest.mock('../../../src/Application/Services/ErrorResponseService');
jest.mock('../../../src/Application/Services/Logger');
describe('ValidationMiddleware', () => {
let req: Partial<Request>;
let res: Partial<Response>;
let next: NextFunction;
beforeEach(() => {
req = {
body: {},
params: {},
query: {},
path: '/test'
};
res = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis()
};
next = jest.fn();
jest.clearAllMocks();
});
describe('validateRequiredFields', () => {
it('should pass validation when all required fields are present', () => {
req.body = { username: 'testuser', email: 'test@example.com' };
const middleware = ValidationMiddleware.validateRequiredFields(['username', 'email']);
middleware(req as Request, res as Response, next);
expect(next).toHaveBeenCalledWith();
expect(ErrorResponseService.sendBadRequest).not.toHaveBeenCalled();
});
it('should fail validation when required fields are missing', () => {
req.body = { username: 'testuser' }; // missing email
const middleware = ValidationMiddleware.validateRequiredFields(['username', 'email']);
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'Missing required fields',
{ missingFields: ['email'] }
);
expect(next).not.toHaveBeenCalled();
});
it('should fail validation when fields are empty strings', () => {
req.body = { username: '', email: 'test@example.com' };
const middleware = ValidationMiddleware.validateRequiredFields(['username', 'email']);
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'Missing required fields',
{ missingFields: ['username'] }
);
});
});
describe('validateEmailFormat', () => {
it('should pass validation for valid email', () => {
req.body = { email: 'test@example.com' };
const middleware = ValidationMiddleware.validateEmailFormat(['email']);
middleware(req as Request, res as Response, next);
expect(next).toHaveBeenCalledWith();
expect(ErrorResponseService.sendBadRequest).not.toHaveBeenCalled();
});
it('should fail validation for invalid email', () => {
req.body = { email: 'invalid-email' };
const middleware = ValidationMiddleware.validateEmailFormat(['email']);
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'Email format validation failed',
{ errors: ["Field 'email' must contain a valid email address"] }
);
expect(next).not.toHaveBeenCalled();
});
});
describe('validateUUIDFormat', () => {
it('should pass validation for valid UUID', () => {
req.params = { userId: '123e4567-e89b-12d3-a456-426614174000' };
const middleware = ValidationMiddleware.validateUUIDFormat(['userId']);
middleware(req as Request, res as Response, next);
expect(next).toHaveBeenCalledWith();
expect(ErrorResponseService.sendBadRequest).not.toHaveBeenCalled();
});
it('should fail validation for invalid UUID', () => {
req.params = { userId: 'invalid-uuid' };
const middleware = ValidationMiddleware.validateUUIDFormat(['userId']);
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'UUID format validation failed',
{ errors: ["Field 'userId' must contain a valid UUID"] }
);
expect(next).not.toHaveBeenCalled();
});
});
describe('validateStringLength', () => {
it('should pass validation for strings within length constraints', () => {
req.body = { username: 'testuser', password: 'password123' };
const middleware = ValidationMiddleware.validateStringLength({
username: { min: 3, max: 20 },
password: { min: 8, max: 50 }
});
middleware(req as Request, res as Response, next);
expect(next).toHaveBeenCalledWith();
expect(ErrorResponseService.sendBadRequest).not.toHaveBeenCalled();
});
it('should fail validation for strings that are too short', () => {
req.body = { username: 'ab' }; // too short (min 3)
const middleware = ValidationMiddleware.validateStringLength({
username: { min: 3, max: 20 }
});
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'String length validation failed',
{ errors: ["Field 'username' must be at least 3 characters"] }
);
});
it('should fail validation for strings that are too long', () => {
req.body = { username: 'a'.repeat(25) }; // too long (max 20)
const middleware = ValidationMiddleware.validateStringLength({
username: { min: 3, max: 20 }
});
middleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'String length validation failed',
{ errors: ["Field 'username' must not exceed 20 characters"] }
);
});
});
describe('combine', () => {
it('should run all validations in sequence and pass if all succeed', (done) => {
req.body = { username: 'testuser', email: 'test@example.com' };
const nextSpy = jest.fn(() => {
try {
expect(nextSpy).toHaveBeenCalledWith();
expect(ErrorResponseService.sendBadRequest).not.toHaveBeenCalled();
done();
} catch (error) {
done(error);
}
});
const combinedMiddleware = ValidationMiddleware.combine([
ValidationMiddleware.validateRequiredFields(['username', 'email']),
ValidationMiddleware.validateEmailFormat(['email']),
ValidationMiddleware.validateStringLength({ username: { min: 3, max: 20 } })
]);
combinedMiddleware(req as Request, res as Response, nextSpy);
});
it('should stop at first validation failure', () => {
req.body = { username: 'testuser' }; // missing email
const combinedMiddleware = ValidationMiddleware.combine([
ValidationMiddleware.validateRequiredFields(['username', 'email']),
ValidationMiddleware.validateEmailFormat(['email']), // this won't run
ValidationMiddleware.validateStringLength({ username: { min: 3, max: 20 } }) // this won't run
]);
combinedMiddleware(req as Request, res as Response, next);
expect(ErrorResponseService.sendBadRequest).toHaveBeenCalledWith(
res,
'Missing required fields',
{ missingFields: ['email'] }
);
expect(next).not.toHaveBeenCalled();
});
});
});