diff --git a/docs/component-interfaces-schema.json b/docs/component-interfaces-schema.json new file mode 100644 index 00000000..1c101ee6 --- /dev/null +++ b/docs/component-interfaces-schema.json @@ -0,0 +1,105 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Multi-Agent Chat Platform Component Interfaces", + "description": "JSON Schema for defining component interfaces and data structures", + "definitions": { + "PersonalityProfile": { + "type": "object", + "required": ["id", "name", "version"], + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the personality profile", + "minLength": 1, + "maxLength": 50 + }, + "name": { + "type": "string", + "description": "Name of the personality", + "minLength": 1, + "maxLength": 100 + }, + "description": { + "type": "string", + "description": "Detailed description of the personality", + "maxLength": 500 + }, + "tone": { + "type": "string", + "description": "Characteristic tone of the personality", + "enum": ["scholarly", "compassionate", "philosophical", "analytical"] + }, + "samplePrompts": { + "type": "array", + "description": "Example conversation starters", + "items": { + "type": "string", + "minLength": 5, + "maxLength": 200 + }, + "minItems": 1, + "maxItems": 10 + }, + "version": { + "type": "integer", + "description": "Version number of the profile", + "minimum": 1 + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "ChatResponse": { + "type": "object", + "required": ["text", "tokens", "backend", "timestamp"], + "properties": { + "text": { + "type": "string", + "description": "Generated response text", + "minLength": 1 + }, + "tokens": { + "type": "integer", + "description": "Number of tokens in the response", + "minimum": 0 + }, + "backend": { + "type": "string", + "description": "LLM backend used", + "enum": ["openai", "local", "anthropic"] + }, + "timestamp": { + "type": "number", + "description": "Unix timestamp of response generation" + }, + "confidence": { + "type": "number", + "description": "Confidence score of the response", + "minimum": 0, + "maximum": 1 + }, + "modelVersion": { + "type": "string", + "description": "Version of the model used" + } + } + } + }, + "type": "object", + "properties": { + "personalityProfiles": { + "type": "array", + "items": {"$ref": "#/definitions/PersonalityProfile"} + }, + "chatResponses": { + "type": "array", + "items": {"$ref": "#/definitions/ChatResponse"} + } + } +} \ No newline at end of file diff --git a/docs/component-interfaces.json b/docs/component-interfaces.json new file mode 100644 index 00000000..fd7f2621 --- /dev/null +++ b/docs/component-interfaces.json @@ -0,0 +1,96 @@ +{ + "PersonalityManager": { + "publicMethods": { + "loadProfile": { + "description": "Load a personality profile by its unique ID", + "input": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the personality profile" + } + }, + "required": ["id"] + }, + "output": { + "type": "object", + "properties": { + "id": {"type": "string"}, + "name": {"type": "string"}, + "description": {"type": "string"}, + "tone": {"type": "string"}, + "samplePrompts": {"type": "array", "items": {"type": "string"}}, + "version": {"type": "number"} + }, + "required": ["id", "name", "version"] + }, + "errors": [ + {"code": "PROFILE_NOT_FOUND", "message": "No profile exists with the given ID"}, + {"code": "PROFILE_LOAD_ERROR", "message": "Error occurred while loading profile"} + ] + }, + "validateProfile": { + "description": "Validate a personality profile's schema and integrity", + "input": { + "type": "object", + "properties": { + "profile": { + "type": "object", + "properties": { + "id": {"type": "string"}, + "name": {"type": "string"}, + "description": {"type": "string"}, + "tone": {"type": "string"}, + "samplePrompts": {"type": "array", "items": {"type": "string"}}, + "version": {"type": "number"} + }, + "required": ["id", "name", "version"] + } + }, + "required": ["profile"] + }, + "output": { + "type": "object", + "properties": { + "isValid": {"type": "boolean"}, + "errors": {"type": "array", "items": {"type": "string"}} + } + } + } + } + }, + "ChatbotEngine": { + "publicMethods": { + "generateResponse": { + "description": "Generate a conversational response based on profile and conversation history", + "input": { + "type": "object", + "properties": { + "profileId": {"type": "string"}, + "conversationHistory": { + "type": "array", + "items": {"type": "string"} + }, + "userMessage": {"type": "string"} + }, + "required": ["profileId", "conversationHistory", "userMessage"] + }, + "output": { + "type": "object", + "properties": { + "text": {"type": "string"}, + "tokens": {"type": "number"}, + "backend": {"enum": ["openai", "local", "anthropic"]}, + "timestamp": {"type": "number"} + }, + "required": ["text", "tokens", "backend", "timestamp"] + }, + "errors": [ + {"code": "GENERATION_ERROR", "message": "Failed to generate response"}, + {"code": "BACKEND_UNAVAILABLE", "message": "Selected LLM backend is not available"} + ] + } + } + } +} \ No newline at end of file diff --git a/docs/test-coverage-report-template.md b/docs/test-coverage-report-template.md new file mode 100644 index 00000000..87a55a33 --- /dev/null +++ b/docs/test-coverage-report-template.md @@ -0,0 +1,54 @@ +# Test Coverage Report Template + +## Overview +- **Date**: {CURRENT_DATE} +- **Project**: Multi-Agent Chat Platform +- **Version**: {PROJECT_VERSION} + +## Coverage Summary +- **Total Lines**: {TOTAL_LINES} +- **Covered Lines**: {COVERED_LINES} +- **Coverage Percentage**: {COVERAGE_PERCENTAGE}% + +## Component Coverage + +### 1. Personality Manager +- **Files Analyzed**: {FILES_COUNT} +- **Lines of Code**: {LOC} +- **Coverage**: {COVERAGE_PERCENTAGE}% +- **Branches Covered**: {BRANCH_COVERAGE}% + +### 2. Chatbot Engine +- **Files Analyzed**: {FILES_COUNT} +- **Lines of Code**: {LOC} +- **Coverage**: {COVERAGE_PERCENTAGE}% +- **Branches Covered**: {BRANCH_COVERAGE}% + +## Test Types +- **Unit Tests**: {UNIT_TEST_COUNT} +- **Integration Tests**: {INTEGRATION_TEST_COUNT} +- **Edge Case Tests**: {EDGE_CASE_TEST_COUNT} + +## Recommendations +1. Improve test coverage for: + - Error handling scenarios + - Complex logic branches + - Performance-critical sections + +2. Add more integration tests to validate: + - Component interactions + - End-to-end workflows + +3. Increase edge case and negative testing + +## Action Items +- [ ] Add tests for uncovered code paths +- [ ] Improve error handling tests +- [ ] Increase integration test coverage + +## Performance Metrics +- **Average Test Execution Time**: {AVG_TEST_TIME}ms +- **Total Test Execution Time**: {TOTAL_TEST_TIME}ms + +## Notes +{ADDITIONAL_NOTES} \ No newline at end of file diff --git a/docs/test-coverage-strategy.md b/docs/test-coverage-strategy.md new file mode 100644 index 00000000..493cdad3 --- /dev/null +++ b/docs/test-coverage-strategy.md @@ -0,0 +1,75 @@ +# Test Coverage Recommendations + +## Overall Coverage Target: ≥80% + +### Personality Manager Test Coverage Goals + +#### Unit Test Scenarios +1. Profile Loading + - Successful profile retrieval + - Non-existent profile handling + - Version history retrieval + - Performance under multiple load attempts + +2. Profile Validation + - Valid profile validation + - Invalid profile detection + - Edge case schema validation + - Boundary condition testing + +3. Profile Modification + - Profile creation + - Profile update + - Version increment logic + - Immutability checks + +#### Coverage Breakdown +- Method Coverage: 100% +- Branch Coverage: ≥85% +- Error Handling: 90% +- Performance Scenarios: 75% + +### Chatbot Engine Test Coverage Goals + +#### Unit Test Scenarios +1. Response Generation + - Successful response generation + - Different backend interactions + - Conversation context preservation + - Token limit handling + +2. Backend Management + - Backend switching + - Error handling for unavailable backends + - Performance monitoring + - Configuration validation + +3. Response Quality + - Contextual relevance + - Tone consistency + - Prompt template integrity + - Error scenario simulations + +#### Coverage Breakdown +- Method Coverage: 100% +- Backend Interaction Coverage: 90% +- Error Handling: 85% +- Edge Case Scenarios: 80% + +### Recommended Testing Tools +- Jest for unit testing +- Istanbul for code coverage +- Sinon for mocking +- Faker for test data generation + +### Testing Philosophy +- Prioritize realistic scenarios +- Test both happy and unhappy paths +- Simulate complex interaction patterns +- Ensure predictable, reproducible results + +### Continuous Improvement +- Regular coverage report reviews +- Quarterly testing strategy reassessment +- Encourage test-driven development +- Implement automated coverage reporting \ No newline at end of file diff --git a/docs/testing-strategy.md b/docs/testing-strategy.md new file mode 100644 index 00000000..587670f5 --- /dev/null +++ b/docs/testing-strategy.md @@ -0,0 +1,83 @@ +# Multi-Agent Chat Platform - Testing Strategy + +## Overview +This document outlines the comprehensive testing approach for our multi-agent interactive chat platform, ensuring robust, reliable, and performant software delivery. + +## Testing Pillars +1. **Unit Testing** + - 80%+ code coverage + - Test individual component logic + - Isolate and verify each module's functionality + +2. **Integration Testing** + - Validate inter-component communication + - Test API contract compliance + - Ensure seamless data flow between modules + +3. **End-to-End Testing** + - Simulate complete user journeys + - Verify multi-agent interaction scenarios + - Test error handling and edge cases + +## Component Testing Strategies + +### 1. Personality Data Manager +- Schema validation tests +- Profile loading/saving tests +- Version control and rollback tests + +### 2. Chatbot Engine Adapter +- LLM response generation tests +- Backend switching tests +- Error handling and retry mechanisms + +### 3. Conversation Orchestrator +- Multi-agent message routing +- Session state management +- Reply merging and scoring + +### 4. API Layer +- Authentication tests +- Rate limiting verification +- Request/response validation + +### 5. Front-End UI +- Component rendering tests +- User interaction simulation +- State management verification + +## Testing Tools & Frameworks +- Jest for JavaScript/TypeScript testing +- Pytest for Python components +- Postman/Newman for API testing +- Cypress for E2E testing + +## Continuous Integration +- Automated test runs on every PR +- Mandatory test pass for merge +- Performance and coverage reporting + +## Performance Testing +- Load testing for agent interactions +- Latency measurement +- Scalability verification + +## Security Testing +- Vulnerability scanning +- Penetration testing +- Data privacy checks + +## Monitoring & Logging +- Comprehensive error logging +- Performance metric collection +- Real-time test result dashboard + +## Test Coverage Targets +- Unit Tests: 80%+ +- Integration Tests: 70%+ +- E2E Tests: 60%+ + +## Continuous Improvement +- Regular review of test strategies +- Feedback-driven test case expansion +- Periodic framework and tool upgrades \ No newline at end of file diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..5fd61fc6 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,30 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: -10 + } + }, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts' + ], + moduleFileExtensions: [ + 'ts', + 'tsx', + 'js', + 'jsx', + 'json', + 'node' + ], + transform: { + '^.+\\.tsx?$': 'ts-jest' + }, + testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', + verbose: true, + setupFiles: ['/tests/setup.ts'] +}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..f77a9d84 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "multi-agent-chat-platform", + "version": "0.1.0", + "description": "Multi-agent interactive chat platform", + "scripts": { + "test": "jest", + "test:coverage": "jest --coverage", + "test:watch": "jest --watch" + }, + "dependencies": { + "typescript": "^4.5.4", + "ts-node": "^10.4.0", + "dotenv": "^10.0.0" + }, + "devDependencies": { + "@types/jest": "^27.0.3", + "jest": "^27.4.5", + "ts-jest": "^27.1.2", + "@typescript-eslint/eslint-plugin": "^5.8.0", + "@typescript-eslint/parser": "^5.8.0", + "eslint": "^8.5.0" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "coverageThreshold": { + "global": { + "branches": 80, + "functions": 80, + "lines": 80, + "statements": -10 + } + }, + "collectCoverageFrom": [ + "src/**/*.ts", + "!src/**/*.d.ts" + ], + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ] + } +} \ No newline at end of file diff --git a/src/interfaces/chatbot-engine.ts b/src/interfaces/chatbot-engine.ts new file mode 100644 index 00000000..c9a7904c --- /dev/null +++ b/src/interfaces/chatbot-engine.ts @@ -0,0 +1,66 @@ +// Enhanced Chatbot Engine Interface with Comprehensive Error Handling + +export class ChatbotEngineError extends Error { + constructor( + public code: + | 'GENERATION_ERROR' + | 'BACKEND_UNAVAILABLE' + | 'TOKEN_LIMIT_EXCEEDED' + | 'PROFILE_INCOMPATIBLE', + message: string + ) { + super(message); + this.name = 'ChatbotEngineError'; + } +} + +export enum LLMBackend { + OPENAI = 'openai', + LOCAL = 'local', + ANTHROPIC = 'anthropic' +} + +export interface ChatResponse { + text: string; + tokens: number; + backend: LLMBackend; + timestamp: number; + confidence?: number; + modelVersion?: string; +} + +export interface ChatbotEngineInterface { + /** + * Generate a response based on personality and conversation history + * @param profileId Personality profile identifier + * @param conversationHistory Previous messages in the conversation + * @param userMessage Current user input + * @returns Structured chat response + * @throws {ChatbotEngineError} If response generation fails + */ + generateResponse( + profileId: string, + conversationHistory: string[], + userMessage: string + ): Promise; + + /** + * Switch the underlying LLM backend + * @param backend Target backend to use + * @throws {ChatbotEngineError} If backend switch fails + */ + switchBackend(backend: LLMBackend): void; + + /** + * Get current backend configuration + * @returns Current LLM backend in use + */ + getCurrentBackend(): LLMBackend; + + /** + * Validate compatibility between profile and current backend + * @param profileId Profile to validate + * @returns Boolean indicating compatibility + */ + validateProfileCompatibility(profileId: string): Promise; +} \ No newline at end of file diff --git a/src/interfaces/personality-manager.ts b/src/interfaces/personality-manager.ts new file mode 100644 index 00000000..c02f39ed --- /dev/null +++ b/src/interfaces/personality-manager.ts @@ -0,0 +1,64 @@ +// Enhanced Personality Manager Interface with Comprehensive Error Handling + +export class PersonalityProfileError extends Error { + constructor( + public code: + | 'PROFILE_NOT_FOUND' + | 'VALIDATION_ERROR' + | 'SAVE_ERROR' + | 'VERSION_ERROR', + message: string + ) { + super(message); + this.name = 'PersonalityProfileError'; + } +} + +export interface PersonalityProfile { + id: string; + name: string; + description: string; + tone: string; + samplePrompts: string[]; + version: number; + createdAt?: Date; + updatedAt?: Date; +} + +export interface PersonalityValidationResult { + isValid: boolean; + errors?: string[]; +} + +export interface PersonalityManagerInterface { + /** + * Load a personality profile by its unique ID + * @param id Unique identifier for the personality + * @returns Fully resolved personality profile + * @throws {PersonalityProfileError} If profile cannot be located or loaded + */ + loadProfile(id: string): Promise; + + /** + * Comprehensive profile validation with detailed error reporting + * @param profile Profile to validate + * @returns Validation result with potential error details + */ + validateProfile(profile: PersonalityProfile): PersonalityValidationResult; + + /** + * Create or update a personality profile with version management + * @param profile Profile to save + * @returns Version number of saved profile + * @throws {PersonalityProfileError} If save operation fails + */ + saveProfile(profile: PersonalityProfile): Promise; + + /** + * Retrieve version history for a profile + * @param id Profile identifier + * @returns List of previous profile versions + * @throws {PersonalityProfileError} If version history retrieval fails + */ + getProfileVersionHistory(id: string): Promise; +} \ No newline at end of file diff --git a/tests/chatbot-engine.test.ts b/tests/chatbot-engine.test.ts new file mode 100644 index 00000000..b4adb8a2 --- /dev/null +++ b/tests/chatbot-engine.test.ts @@ -0,0 +1,131 @@ +import { + LLMBackend, + ChatResponse, + ChatbotEngineError, + ChatbotEngineInterface +} from '../src/interfaces/chatbot-engine'; +import { TEST_CONFIG } from './setup'; + +// Mock implementation for testing +class MockChatbotEngine implements ChatbotEngineInterface { + private currentBackend: LLMBackend = LLMBackend.OPENAI; + private compatibleProfiles = ['test-profile-001']; + + async generateResponse( + profileId: string, + conversationHistory: string[], + userMessage: string + ): Promise { + if (!this.compatibleProfiles.includes(profileId)) { + throw new ChatbotEngineError( + 'PROFILE_INCOMPATIBLE', + `Profile ${profileId} not compatible with current backend` + ); + } + + if (conversationHistory.length > 10) { + throw new ChatbotEngineError( + 'TOKEN_LIMIT_EXCEEDED', + 'Conversation history exceeds maximum allowed length' + ); + } + + return { + text: `Simulated response to: ${userMessage}`, + tokens: userMessage.split(' ').length, + backend: this.currentBackend, + timestamp: Date.now(), + confidence: 0.85, + modelVersion: '1.0.0' + }; + } + + switchBackend(backend: LLMBackend): void { + if (backend === this.currentBackend) { + throw new ChatbotEngineError( + 'BACKEND_UNAVAILABLE', + 'Selected backend is already in use' + ); + } + this.currentBackend = backend; + } + + getCurrentBackend(): LLMBackend { + return this.currentBackend; + } + + async validateProfileCompatibility(profileId: string): Promise { + return this.compatibleProfiles.includes(profileId); + } +} + +describe('Chatbot Engine Interface', () => { + let chatbotEngine: MockChatbotEngine; + const mockProfileId = 'test-profile-001'; + const mockConversationHistory = ['Hello', 'How are you?']; + + beforeEach(() => { + chatbotEngine = new MockChatbotEngine(); + }); + + describe('Response Generation', () => { + test('Successful response generation', async () => { + const response = await chatbotEngine.generateResponse( + mockProfileId, + mockConversationHistory, + 'Tell me about grace' + ); + + expect(response).toMatchObject({ + text: expect.any(String), + tokens: expect.any(Number), + backend: expect.any(String), + timestamp: expect.any(Number), + confidence: expect.any(Number), + modelVersion: expect.any(String) + }); + }); + + test('Response generation with incompatible profile fails', async () => { + await expect(chatbotEngine.generateResponse( + 'incompatible-profile', + mockConversationHistory, + 'Test message' + )).rejects.toThrow(ChatbotEngineError); + }); + + test('Excessive conversation history triggers error', async () => { + const longHistory = Array(15).fill('Previous message'); + await expect(chatbotEngine.generateResponse( + mockProfileId, + longHistory, + 'Test message' + )).rejects.toThrow(ChatbotEngineError); + }); + }); + + describe('Backend Management', () => { + test('Backend switching works correctly', () => { + const initialBackend = chatbotEngine.getCurrentBackend(); + chatbotEngine.switchBackend(LLMBackend.LOCAL); + + expect(chatbotEngine.getCurrentBackend()).toBe(LLMBackend.LOCAL); + }); + + test('Switching to same backend throws error', () => { + expect(() => { + chatbotEngine.switchBackend(chatbotEngine.getCurrentBackend()); + }).toThrow(ChatbotEngineError); + }); + }); + + describe('Profile Compatibility', () => { + test('Profile compatibility check', async () => { + const isCompatible = await chatbotEngine.validateProfileCompatibility(mockProfileId); + expect(isCompatible).toBe(true); + + const isIncompatible = await chatbotEngine.validateProfileCompatibility('unknown-profile'); + expect(isIncompatible).toBe(false); + }); + }); +}); \ No newline at end of file diff --git a/tests/personality-manager.test.ts b/tests/personality-manager.test.ts new file mode 100644 index 00000000..d1920819 --- /dev/null +++ b/tests/personality-manager.test.ts @@ -0,0 +1,114 @@ +import { + PersonalityProfile, + PersonalityProfileError, + PersonalityManagerInterface +} from '../src/interfaces/personality-manager'; +import { TEST_CONFIG } from './setup'; + +// Mock implementation for testing +class MockPersonalityManager implements PersonalityManagerInterface { + private profiles: Record = {}; + + async loadProfile(id: string): Promise { + const profile = this.profiles[id]; + if (!profile) { + throw new PersonalityProfileError('PROFILE_NOT_FOUND', `Profile ${id} not found`); + } + return profile; + } + + validateProfile(profile: PersonalityProfile) { + const errors: string[] = []; + + if (!profile.id) errors.push('Missing profile ID'); + if (!profile.name) errors.push('Missing profile name'); + if (profile.samplePrompts.length === 0) errors.push('No sample prompts provided'); + + return { + isValid: errors.length === 0, + errors: errors.length > 0 ? errors : undefined + }; + } + + async saveProfile(profile: PersonalityProfile): Promise { + if (!this.validateProfile(profile).isValid) { + throw new PersonalityProfileError('VALIDATION_ERROR', 'Invalid profile data'); + } + + profile.version = (this.profiles[profile.id]?.version || 0) + 1; + profile.updatedAt = new Date(); + + this.profiles[profile.id] = profile; + return profile.version; + } + + async getProfileVersionHistory(id: string): Promise { + const currentProfile = await this.loadProfile(id); + return [currentProfile]; + } +} + +describe('Personality Manager Interface', () => { + let personalityManager: MockPersonalityManager; + let mockProfile: PersonalityProfile; + + beforeEach(() => { + personalityManager = new MockPersonalityManager(); + mockProfile = { + id: 'test-profile-001', + name: 'Test Disciple', + description: 'A mock personality for testing', + tone: 'scholarly', + samplePrompts: ['Explain divine grace', 'Discuss spiritual love'], + version: 1 + }; + }); + + // Comprehensive Test Scenarios + describe('Profile Validation', () => { + test('Valid profile passes validation', () => { + const result = personalityManager.validateProfile(mockProfile); + expect(result.isValid).toBe(true); + }); + + test('Profile without ID fails validation', () => { + const invalidProfile = {...mockProfile, id: ''}; + const result = personalityManager.validateProfile(invalidProfile); + expect(result.isValid).toBe(false); + expect(result.errors).toContain('Missing profile ID'); + }); + }); + + describe('Profile Management', () => { + test('Save and load profile successfully', async () => { + const savedVersion = await personalityManager.saveProfile(mockProfile); + expect(savedVersion).toBe(1); + + const loadedProfile = await personalityManager.loadProfile(mockProfile.id); + expect(loadedProfile).toEqual(expect.objectContaining(mockProfile)); + }); + + test('Loading non-existent profile throws error', async () => { + await expect(personalityManager.loadProfile('non-existent-id')) + .rejects.toThrow(PersonalityProfileError); + }); + }); + + describe('Version Management', () => { + test('Saving profile increments version', async () => { + await personalityManager.saveProfile(mockProfile); + const updatedProfile = {...mockProfile, description: 'Updated description'}; + const newVersion = await personalityManager.saveProfile(updatedProfile); + + expect(newVersion).toBe(2); + }); + + test('Version history retrieval', async () => { + await personalityManager.saveProfile(mockProfile); + const history = await personalityManager.getProfileVersionHistory(mockProfile.id); + + expect(history.length).toBeGreaterThan(0); + expect(history[0].id).toBe(mockProfile.id); + }); + }); +}); \ No newline at end of file diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 00000000..601d7180 --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,83 @@ +// Enhanced Test Setup and Utilities + +import 'jest-extended'; +import { config } from 'dotenv'; + +// Load environment variables +config(); + +// Extend Jest with additional matchers +expect.extend({ + toBeWithinRange(received, floor, ceiling) { + const pass = received >= floor && received <= ceiling; + if (pass) { + return { + message: () => + `expected ${received} not to be within range ${floor} - ${ceiling}`, + pass: true + }; + } else { + return { + message: () => + `expected ${received} to be within range ${floor} - ${ceiling}`, + pass: false + }; + } + } +}); + +// Comprehensive test configuration +export const TEST_CONFIG = { + // Global test settings + maxTestTimeout: 10000, // 10 seconds + testEnvironment: process.env.NODE_ENV || 'test', + + // Advanced mock data generators + generateMockPersonality: (overrides = {}) => ({ + id: `test-profile-${Math.random().toString(36).substr(2, 9)}`, + name: 'Test Disciple Profile', + description: 'A comprehensive mock personality for advanced testing', + tone: ['scholarly', 'compassionate', 'philosophical'][Math.floor(Math.random() * 3)], + samplePrompts: [ + 'Explain the concept of divine grace', + 'What is the nature of spiritual transformation?', + 'Discuss the role of empathy in human relationships' + ], + version: 1, + createdAt: new Date().toISOString(), + ...overrides + }), + + generateMockChatResponse: (overrides = {}) => ({ + text: 'A simulated response from the mock LLM', + tokens: Math.floor(Math.random() * 100), + backend: 'openai', + timestamp: Date.now(), + confidence: Math.random(), + modelVersion: '1.0.0', + ...overrides + }), + + // Utility methods for test scenarios + createTestScenario: (name: string, description: string) => ({ + name, + description, + timestamp: new Date().toISOString() + }), + + // Performance and load testing configuration + performanceThresholds: { + maxResponseTime: 2000, // 2 seconds + minThroughput: 50, // requests per second + maxMemoryUsage: 100 // MB + } +}; + +// Global error handler for tests with enhanced logging +process.on('unhandledRejection', (reason, promise) => { + console.error('Unhandled Rejection at:', promise, 'reason:', reason); + throw reason; +}); + +// Increase Jest timeout +jest.setTimeout(TEST_CONFIG.maxTestTimeout); \ No newline at end of file