/** * Unit tests for src/utils/validators.ts */ import { createAgentSchema, updateAgentSchema, listAgentsQuerySchema, tokenRequestSchema, introspectRequestSchema, revokeRequestSchema, generateCredentialSchema, listCredentialsQuerySchema, auditQuerySchema, } from '../../../src/utils/validators'; describe('validators', () => { // ──────────────────────────────────────────────────────────────── // createAgentSchema // ──────────────────────────────────────────────────────────────── describe('createAgentSchema', () => { const valid = { email: 'agent@sentryagent.ai', agentType: 'screener', version: '1.0.0', capabilities: ['resume:read'], owner: 'team-a', deploymentEnv: 'production', }; it('should accept a valid request', () => { const { error } = createAgentSchema.validate(valid); expect(error).toBeUndefined(); }); it('should reject an invalid email', () => { const { error } = createAgentSchema.validate({ ...valid, email: 'not-an-email' }); expect(error).toBeDefined(); }); it('should reject an invalid agentType', () => { const { error } = createAgentSchema.validate({ ...valid, agentType: 'invalid' }); expect(error).toBeDefined(); }); it('should reject an invalid semver', () => { const { error } = createAgentSchema.validate({ ...valid, version: 'v1' }); expect(error).toBeDefined(); }); it('should reject empty capabilities array', () => { const { error } = createAgentSchema.validate({ ...valid, capabilities: [] }); expect(error).toBeDefined(); }); it('should reject capability with invalid format', () => { const { error } = createAgentSchema.validate({ ...valid, capabilities: ['invalid'] }); expect(error).toBeDefined(); }); it('should reject missing required fields', () => { const { error } = createAgentSchema.validate({}); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // updateAgentSchema // ──────────────────────────────────────────────────────────────── describe('updateAgentSchema', () => { it('should accept a single field update', () => { const { error } = updateAgentSchema.validate({ version: '2.0.0' }); expect(error).toBeUndefined(); }); it('should reject an empty object (minProperties: 1)', () => { const { error } = updateAgentSchema.validate({}); expect(error).toBeDefined(); }); it('should accept valid status values', () => { expect(updateAgentSchema.validate({ status: 'active' }).error).toBeUndefined(); expect(updateAgentSchema.validate({ status: 'suspended' }).error).toBeUndefined(); expect(updateAgentSchema.validate({ status: 'decommissioned' }).error).toBeUndefined(); }); it('should reject invalid status', () => { const { error } = updateAgentSchema.validate({ status: 'deleted' }); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // listAgentsQuerySchema // ──────────────────────────────────────────────────────────────── describe('listAgentsQuerySchema', () => { it('should apply default values', () => { const { value } = listAgentsQuerySchema.validate({}); expect(value.page).toBe(1); expect(value.limit).toBe(20); }); it('should reject limit > 100', () => { const { error } = listAgentsQuerySchema.validate({ limit: 101 }); expect(error).toBeDefined(); }); it('should reject page < 1', () => { const { error } = listAgentsQuerySchema.validate({ page: 0 }); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // tokenRequestSchema // ──────────────────────────────────────────────────────────────── describe('tokenRequestSchema', () => { it('should accept a valid token request', () => { const { error } = tokenRequestSchema.validate({ grant_type: 'client_credentials', client_id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', client_secret: 'sk_live_abc123', scope: 'agents:read agents:write', }); expect(error).toBeUndefined(); }); it('should reject missing grant_type', () => { const { error } = tokenRequestSchema.validate({ client_id: 'uuid', client_secret: 'secret' }); expect(error).toBeDefined(); }); it('should reject invalid scope', () => { const { error } = tokenRequestSchema.validate({ grant_type: 'client_credentials', scope: 'admin:all', }); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // introspectRequestSchema // ──────────────────────────────────────────────────────────────── describe('introspectRequestSchema', () => { it('should accept a valid introspect request', () => { const { error } = introspectRequestSchema.validate({ token: 'some.jwt.token' }); expect(error).toBeUndefined(); }); it('should reject missing token', () => { const { error } = introspectRequestSchema.validate({}); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // revokeRequestSchema // ──────────────────────────────────────────────────────────────── describe('revokeRequestSchema', () => { it('should accept a valid revoke request', () => { const { error } = revokeRequestSchema.validate({ token: 'some.jwt.token' }); expect(error).toBeUndefined(); }); it('should reject missing token', () => { const { error } = revokeRequestSchema.validate({}); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // generateCredentialSchema // ──────────────────────────────────────────────────────────────── describe('generateCredentialSchema', () => { it('should accept empty body (expiresAt is optional)', () => { const { error } = generateCredentialSchema.validate({}); expect(error).toBeUndefined(); }); it('should accept valid ISO 8601 expiresAt', () => { const { error } = generateCredentialSchema.validate({ expiresAt: '2027-01-01T00:00:00.000Z', }); expect(error).toBeUndefined(); }); it('should reject non-ISO date', () => { const { error } = generateCredentialSchema.validate({ expiresAt: '2027/01/01' }); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // listCredentialsQuerySchema // ──────────────────────────────────────────────────────────────── describe('listCredentialsQuerySchema', () => { it('should apply defaults', () => { const { value } = listCredentialsQuerySchema.validate({}); expect(value.page).toBe(1); expect(value.limit).toBe(20); }); it('should accept status filter', () => { const { error } = listCredentialsQuerySchema.validate({ status: 'active' }); expect(error).toBeUndefined(); }); it('should reject invalid status', () => { const { error } = listCredentialsQuerySchema.validate({ status: 'expired' }); expect(error).toBeDefined(); }); }); // ──────────────────────────────────────────────────────────────── // auditQuerySchema // ──────────────────────────────────────────────────────────────── describe('auditQuerySchema', () => { it('should apply defaults', () => { const { value } = auditQuerySchema.validate({}); expect(value.page).toBe(1); expect(value.limit).toBe(50); }); it('should accept valid audit action', () => { const { error } = auditQuerySchema.validate({ action: 'token.issued' }); expect(error).toBeUndefined(); }); it('should reject invalid action', () => { const { error } = auditQuerySchema.validate({ action: 'unknown.action' }); expect(error).toBeDefined(); }); it('should accept limit up to 200', () => { const { error } = auditQuerySchema.validate({ limit: 200 }); expect(error).toBeUndefined(); }); it('should reject limit > 200', () => { const { error } = auditQuerySchema.validate({ limit: 201 }); expect(error).toBeDefined(); }); }); });