import { AIService } from '../../src/services/ai'; import { AccessibilityIssue, AIProcessingOptions, AICrawlResult, } from '../../src/types/ai'; jest.mock('../../src/services/cache', () => ({ CacheService: { getInstance: jest.fn(() => ({ get: jest.fn(), set: jest.fn(), delete: jest.fn(), clear: jest.fn(), getStats: jest.fn(), disconnect: jest.fn(), })), }, })); jest.mock('../../src/utils/ai-processor', () => ({ AIProcessor: jest.fn().mockImplementation(() => ({ processAccessibilityIssues: jest.fn().mockResolvedValue({ enabled: true, issues: [], metadata: { cacheHits: 0, cacheMisses: 1, processingTime: 100, }, }), processAccessibilityIssuesWithoutAI: jest.fn().mockResolvedValue({ enabled: false, issues: [], metadata: { cacheHits: 0, cacheMisses: 0, processingTime: 0, }, }), })), })); describe('AIService', () => { let aiService: AIService; beforeEach(() => { aiService = new AIService(); }); const mockIssues: AccessibilityIssue[] = [ { id: 'color-contrast', impact: 'serious', description: 'Elements must have sufficient color contrast', help: 'Ensure all text elements have sufficient color contrast', helpUrl: 'https://dequeuniversity.com/rules/axe/4.4/color-contrast', nodes: [ { target: ['h1'], html: '

Low contrast text

', failureSummary: 'Fix any of the following: Element has insufficient color contrast', }, ], }, ]; describe('processAccessibilityIssues', () => { it('should process accessibility issues with AI when apiKey is provided', async () => { const options: AIProcessingOptions = { apiKey: 'test-api-key', includeExplanations: true, includeRemediation: true, }; const result = await aiService.processAccessibilityIssues( mockIssues, options ); expect(result).toHaveProperty('enabled'); expect(result).toHaveProperty('issues'); expect(result).toHaveProperty('metadata'); expect(result.enabled).toBe(true); expect(Array.isArray(result.issues)).toBe(true); }); it('should process accessibility issues without AI when apiKey is not provided', async () => { const options: AIProcessingOptions = {}; const result = await aiService.processAccessibilityIssues( mockIssues, options ); expect(result).toHaveProperty('enabled'); expect(result).toHaveProperty('issues'); expect(result).toHaveProperty('metadata'); expect(result.enabled).toBe(false); expect(Array.isArray(result.issues)).toBe(true); }); it('should handle empty issues array', async () => { const result = await aiService.processAccessibilityIssues([]); expect(result).toHaveProperty('enabled'); expect(result).toHaveProperty('issues'); expect(result.issues).toEqual([]); }); }); describe('processCrawlResults', () => { it('should process crawl results with AI', async () => { const crawlResults = { issues: mockIssues, url: 'https://example.com', timestamp: new Date(), }; const options: AIProcessingOptions = { apiKey: 'test-api-key', }; const result = await aiService.processCrawlResults(crawlResults, options); expect(result).toHaveProperty('issues'); expect(result).toHaveProperty('aiEnabled'); expect(result).toHaveProperty('url'); expect(result).toHaveProperty('timestamp'); expect(result.aiEnabled).toBe(true); }); it('should handle crawl results without issues', async () => { const crawlResults = { issues: [], url: 'https://example.com', timestamp: new Date(), }; const result = await aiService.processCrawlResults(crawlResults); expect(result).toHaveProperty('aiEnabled'); expect(result).toHaveProperty('url'); expect(result).toHaveProperty('timestamp'); expect(result.aiEnabled).toBe(true); }); it('should handle crawl results with non-array issues', async () => { const crawlResults = { issues: 'invalid-issues' as unknown as AccessibilityIssue[], url: 'https://example.com', timestamp: new Date(), }; const result = await aiService.processCrawlResults(crawlResults); expect(result).toHaveProperty('aiEnabled'); expect(result.aiEnabled).toBe(false); }); }); describe('processCombinedResults', () => { it('should process combined results with multiple crawl results', async () => { const combinedResults = { results: [ { issues: mockIssues, url: 'https://example.com/page1', timestamp: new Date(), }, { issues: mockIssues, url: 'https://example.com/page2', timestamp: new Date(), }, ], summary: { totalIssues: 2, totalUrls: 2, }, }; const options: AIProcessingOptions = { apiKey: 'test-api-key', }; const result = await aiService.processCombinedResults( combinedResults, options ); expect(result).toHaveProperty('results'); expect(result).toHaveProperty('summary'); expect(Array.isArray(result.results)).toBe(true); expect(result.results).toHaveLength(2); }); it('should handle combined results without results array', async () => { const combinedResults = { results: [], summary: { totalIssues: 0, totalUrls: 0, }, }; const result = await aiService.processCombinedResults(combinedResults); expect(result).toHaveProperty('summary'); expect(result.results).toEqual([]); }); it('should handle combined results with non-array results', async () => { const combinedResults = { results: 'invalid-results' as unknown as AICrawlResult[], summary: { totalIssues: 0, totalUrls: 0, }, }; const result = await aiService.processCombinedResults(combinedResults); expect(result).toHaveProperty('summary'); expect(result.results).toBe('invalid-results'); }); it('should process results with and without issues', async () => { const combinedResults = { results: [ { issues: mockIssues, url: 'https://example.com/page1', timestamp: new Date(), }, { issues: [], url: 'https://example.com/page2', timestamp: new Date(), }, ], }; const result = await aiService.processCombinedResults(combinedResults); expect(result).toHaveProperty('results'); expect(Array.isArray(result.results)).toBe(true); expect(result.results).toHaveLength(2); }); }); });