UNPKG

ctrlshiftleft

Version:

AI-powered toolkit for embedding QA and security testing into development workflows

274 lines (214 loc) 9.47 kB
/** * Unit tests for QA validation middleware */ const { expect, describe, test, beforeEach } = require('@jest/globals'); // Mock for express response const mockResponse = () => { const res = {}; res.status = jest.fn().mockReturnValue(res); res.json = jest.fn().mockReturnValue(res); return res; }; describe('QA Validation Middleware', () => { let validation; beforeEach(() => { // Reset modules before each test jest.resetModules(); // Import the validation module - TypeScript file requires ts-jest validation = require('../../../src/middleware/qa-validation'); }); describe('validateInput', () => { test('should validate text input without issues', () => { const result = validation.validateInput('Hello world', 'text'); expect(result.valid).toBe(true); expect(result.securityIssues).toHaveLength(0); }); test('should detect potential XSS in text input', () => { const result = validation.validateInput('<script>alert("XSS")</script>', 'text'); expect(result.valid).toBe(false); expect(result.securityIssues.length).toBeGreaterThan(0); expect(result.securityIssues[0]).toContain('unsafe code'); }); test('should detect potential SQL injection', () => { const result = validation.validateInput("DROP TABLE users;", 'text'); expect(result.valid).toBe(false); expect(result.securityIssues.length).toBeGreaterThan(0); expect(result.securityIssues[0]).toContain('SQL'); }); test('should validate URL format', () => { const validResult = validation.validateInput('https://example.com', 'url'); const invalidResult = validation.validateInput('not-a-url', 'url'); expect(validResult.valid).toBe(true); expect(invalidResult.valid).toBe(false); }); test('should detect unsafe URL', () => { const result = validation.validateInput('javascript:alert(1)', 'url'); expect(result.valid).toBe(false); expect(result.securityIssues.length).toBeGreaterThan(0); }); test('should validate email format', () => { const validResult = validation.validateInput('user@example.com', 'email'); const invalidResult = validation.validateInput('not-an-email', 'email'); expect(validResult.valid).toBe(true); expect(invalidResult.valid).toBe(false); }); test('should validate password strength', () => { const weakResult = validation.validateInput('123456', 'password'); const strongResult = validation.validateInput('StrongP@ssw0rd123', 'password'); expect(weakResult.valid).toBe(false); expect(strongResult.valid).toBe(true); }); test('should detect common passwords', () => { const result = validation.validateInput('password123', 'password'); expect(result.valid).toBe(false); expect(result.securityIssues.length).toBeGreaterThan(0); expect(result.securityIssues[0]).toContain('common'); }); }); describe('validateRequestBody', () => { test('should validate multiple fields in request body', () => { const body = { name: 'John Doe', email: 'john@example.com', password: 'SecureP@ss123' }; const rules = { name: { type: 'text', required: true }, email: { type: 'email', required: true }, password: { type: 'password', required: true } }; const result = validation.validateRequestBody(body, rules); expect(result.isValid).toBe(true); expect(result.errors).toEqual({}); expect(result.securityIssues).toHaveLength(0); }); test('should detect missing required fields', () => { const body = { name: 'John Doe', // Missing email password: 'SecureP@ss123' }; const rules = { name: { type: 'text', required: true }, email: { type: 'email', required: true }, password: { type: 'password', required: true } }; const result = validation.validateRequestBody(body, rules); expect(result.isValid).toBe(false); expect(result.errors).toHaveProperty('email'); }); test('should skip validation for optional empty fields', () => { const body = { name: 'John Doe', email: 'john@example.com', // Optional field is empty phone: '' }; const rules = { name: { type: 'text', required: true }, email: { type: 'email', required: true }, phone: { type: 'text', required: false } }; const result = validation.validateRequestBody(body, rules); expect(result.isValid).toBe(true); }); test('should validate optional fields when provided', () => { const body = { name: 'John Doe', email: 'john@example.com', phone: '<script>alert(1)</script>' // Optional but insecure }; const rules = { name: { type: 'text', required: true }, email: { type: 'email', required: true }, phone: { type: 'text', required: false } }; const result = validation.validateRequestBody(body, rules); expect(result.isValid).toBe(false); expect(result.errors).toHaveProperty('phone'); expect(result.securityIssues.length).toBeGreaterThan(0); }); }); describe('createValidationMiddleware', () => { test('should create middleware that passes for valid requests', () => { const middleware = validation.createValidationMiddleware({ name: { type: 'text', required: true }, email: { type: 'email', required: true } }); const req = { body: { name: 'John Doe', email: 'john@example.com' } }; const res = mockResponse(); const next = jest.fn(); middleware(req, res, next); expect(next).toHaveBeenCalled(); expect(res.status).not.toHaveBeenCalled(); }); test('should create middleware that rejects invalid requests', () => { const middleware = validation.createValidationMiddleware({ name: { type: 'text', required: true }, email: { type: 'email', required: true } }); const req = { body: { name: 'John Doe', email: 'not-an-email' } }; const res = mockResponse(); const next = jest.fn(); middleware(req, res, next); expect(next).not.toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalled(); }); test('should add validation result to request object', () => { const middleware = validation.createValidationMiddleware({ name: { type: 'text', required: true } }); const req = { body: { name: 'John Doe' } }; const res = mockResponse(); const next = jest.fn(); middleware(req, res, next); expect(req).toHaveProperty('validationResult'); expect(next).toHaveBeenCalled(); }); }); describe('convenience validation functions', () => { test('validateUrl should provide formatted validation results', () => { const validResult = validation.validateUrl('https://example.com'); const invalidResult = validation.validateUrl('javascript:alert(1)'); expect(validResult.isValid).toBe(true); expect(validResult.errorMessage).toBe(''); expect(invalidResult.isValid).toBe(false); expect(invalidResult.errorMessage).not.toBe(''); expect(invalidResult.hasSecurity).toBe(true); }); test('validateEmail should provide formatted validation results', () => { const validResult = validation.validateEmail('user@example.com'); const invalidResult = validation.validateEmail('not-an-email'); expect(validResult.isValid).toBe(true); expect(validResult.errorMessage).toBe(''); expect(invalidResult.isValid).toBe(false); expect(invalidResult.errorMessage).not.toBe(''); }); test('validatePassword should check strength and provide suggestions', () => { // This test assumes the implementation of the validatePassword function // that provides strength metrics and suggestions if (typeof validation.validatePassword === 'function') { const result = validation.validatePassword('weak123'); expect(result).toHaveProperty('isValid'); expect(result).toHaveProperty('strength'); expect(result).toHaveProperty('suggestions'); } else { console.warn('validatePassword function not implemented, skipping test'); } }); test('validateJson should validate JSON strings and objects', () => { // This test assumes the implementation of the validateJson function if (typeof validation.validateJson === 'function') { const validStringResult = validation.validateJson('{"name":"John"}'); const validObjectResult = validation.validateJson({name: "John"}); const invalidResult = validation.validateJson('{not valid json}'); expect(validStringResult.isValid).toBe(true); expect(validObjectResult.isValid).toBe(true); expect(invalidResult.isValid).toBe(false); } else { console.warn('validateJson function not implemented, skipping test'); } }); }); });