/** * Integration tests for SSE extraction endpoint * * Tests the real-time progress streaming from extraction to frontend */ import { describe, it, expect } from 'vitest'; import type { ProgressEvent } from '$lib/server/extraction'; describe('SSE Extraction Endpoint', () => { it('should stream progress events for successful extraction', async () => { // Mock Instagram URL (would need real URL for full e2e test) const testUrl = 'https://www.instagram.com/p/test123/'; const events: ProgressEvent[] = []; // Note: This is a structure test. Real testing requires: // 1. Running server // 2. Valid Instagram URL // 3. Browser context available // Expected event flow const expectedEventTypes = [ 'status', // Starting extraction 'status', // Loading page 'method', // Trying first method 'status', // Success or next method 'status', // Parsing recipe 'complete' // Final result ]; expect(expectedEventTypes).toBeDefined(); }); it('should handle errors gracefully', async () => { // Test with invalid URL const invalidUrl = 'not-a-valid-url'; // Expected: error event should be sent expect(invalidUrl).toBeTruthy(); }); it('should include method information in progress events', () => { const mockMethodEvent: ProgressEvent = { type: 'method', message: 'Trying extraction method: Embedded JSON', method: 'embedded-json', timestamp: new Date().toISOString() }; expect(mockMethodEvent.type).toBe('method'); expect(mockMethodEvent.method).toBe('embedded-json'); expect(mockMethodEvent.message).toContain('Embedded JSON'); }); it('should include retry information in retry events', () => { const mockRetryEvent: ProgressEvent = { type: 'retry', message: 'Attempt 1/3 failed. Retrying in 1000ms...', attemptNumber: 1, maxAttempts: 3, timestamp: new Date().toISOString() }; expect(mockRetryEvent.type).toBe('retry'); expect(mockRetryEvent.attemptNumber).toBe(1); expect(mockRetryEvent.maxAttempts).toBe(3); }); it('should include recipe data in complete event', () => { const mockCompleteEvent: ProgressEvent = { type: 'complete', message: 'Extraction and parsing completed', data: { recipe: { name: 'Test Recipe', ingredients: [], steps: [] }, thumbnail: 'data:image/jpeg;base64,...' }, timestamp: new Date().toISOString() }; expect(mockCompleteEvent.type).toBe('complete'); expect(mockCompleteEvent.data).toBeDefined(); expect(mockCompleteEvent.data.recipe).toBeDefined(); expect(mockCompleteEvent.data.thumbnail).toBeDefined(); }); }); describe('Frontend SSE Parser', () => { it('should parse SSE event format correctly', () => { const sseMessage = 'event: progress\ndata: {"type":"status","message":"test"}\n\n'; const eventMatch = sseMessage.match(/^event: (\w+)\ndata: (.+)$/s); expect(eventMatch).toBeTruthy(); if (eventMatch) { const [, eventType, eventData] = eventMatch; expect(eventType).toBe('progress'); const parsed = JSON.parse(eventData.replace(/\n\n$/, '')); expect(parsed.type).toBe('status'); expect(parsed.message).toBe('test'); } }); it('should map methods to correct icons', () => { const getMethodIcon = (method?: string): string => { const icons: Record = { 'embedded-json': 'đŸ“Ļ', 'dom-selector': 'đŸŽ¯', 'graphql-api': '🔌', 'legacy': '📄' }; return method ? icons[method] || 'âš™ī¸' : 'âš™ī¸'; }; expect(getMethodIcon('embedded-json')).toBe('đŸ“Ļ'); expect(getMethodIcon('dom-selector')).toBe('đŸŽ¯'); expect(getMethodIcon('graphql-api')).toBe('🔌'); expect(getMethodIcon('legacy')).toBe('📄'); expect(getMethodIcon('unknown')).toBe('âš™ī¸'); expect(getMethodIcon()).toBe('âš™ī¸'); }); }); /** * Manual E2E Testing Checklist: * * □ Start dev server: npm run dev * □ Open /share?url= * □ Click "Extract Recipe" * □ Verify logs show: * - 🚀 Starting extraction * - â„šī¸ Loading Instagram page * - đŸ“Ļ Trying extraction method: Embedded JSON (or other methods) * - ✅ Success message * - Recipe displays correctly * □ Test with problematic URL (should show retries): * - 🔄 Retry messages appear * - Multiple methods attempted * □ Test with invalid URL: * - ❌ Error messages appear * - No crash or hang * □ Verify current method indicator: * - Blue badge appears during extraction * - Shows correct method name * - Disappears when complete * □ Check log colors: * - Success = green * - Errors = red * - Retries = yellow * - Methods = blue */