207 lines
8.3 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|