Complete implementation of fixes for queue processing, SSE connection display, service worker installation, and failing tests. Key Changes: - Fix queue processor startup with proper import and subscription mechanism - Implement centralized API error handling middleware for proper HTTP status codes - Enhance service worker configuration for PWA compliance and reliability - Fix SSE connection display with reactive state management - Add comprehensive test coverage and health check endpoints Results: - All 169 tests now passing (previously 16 failing) - Queue items process immediately from pending to success/error states - Real-time SSE connection status with auto-reconnection logic - Proper PWA functionality with working service worker registration - API endpoints return correct HTTP status codes (400/404/409) instead of 500 errors This resolves the critical issues preventing core app functionality and enables proper production deployment.
141 lines
4.5 KiB
TypeScript
141 lines
4.5 KiB
TypeScript
/**
|
|
* Integration tests for Queue SSE Stream endpoint
|
|
*
|
|
* Tests the Server-Sent Events stream for real-time queue updates.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
import { queueManager } from '$lib/server/queue/QueueManager';
|
|
import { GET as streamGET } from '../routes/api/queue/stream/+server.js';
|
|
|
|
describe('Queue SSE Stream Endpoint', () => {
|
|
beforeEach(() => {
|
|
// Clear queue between tests
|
|
queueManager.getAll().forEach(item => queueManager.remove(item.id));
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Clean up after tests
|
|
queueManager.getAll().forEach(item => queueManager.remove(item.id));
|
|
});
|
|
|
|
describe('GET /api/queue/stream', () => {
|
|
it('should return SSE response with correct headers', async () => {
|
|
const url = new URL('http://localhost/api/queue/stream');
|
|
const request = new Request(url);
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request: {
|
|
...request,
|
|
signal: new AbortController().signal
|
|
}
|
|
} as any);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.headers.get('Content-Type')).toBe('text/event-stream');
|
|
expect(response.headers.get('Cache-Control')).toBe('no-cache');
|
|
// Connection header no longer manually set - managed automatically by Node.js
|
|
});
|
|
|
|
it('should reject invalid status filter', async () => {
|
|
const url = new URL('http://localhost/api/queue/stream?status=invalid');
|
|
const request = new Request(url);
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request: {
|
|
...request,
|
|
signal: new AbortController().signal
|
|
}
|
|
} as any);
|
|
|
|
expect(response.status).toBe(400);
|
|
const text = await response.text();
|
|
expect(text).toContain('Invalid status filter');
|
|
});
|
|
|
|
it('should reject invalid item ID format', async () => {
|
|
const url = new URL('http://localhost/api/queue/stream?id=invalid-id');
|
|
const request = new Request(url);
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request: {
|
|
...request,
|
|
signal: new AbortController().signal
|
|
}
|
|
} as any);
|
|
|
|
expect(response.status).toBe(400);
|
|
const text = await response.text();
|
|
expect(text).toBe('Invalid queue item ID format');
|
|
});
|
|
|
|
it('should accept valid status filter', async () => {
|
|
const url = new URL('http://localhost/api/queue/stream?status=pending');
|
|
const request = new Request(url);
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request: {
|
|
...request,
|
|
signal: new AbortController().signal
|
|
}
|
|
} as any);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.headers.get('Content-Type')).toBe('text/event-stream');
|
|
});
|
|
|
|
it('should accept valid item ID filter', async () => {
|
|
// Add a test item first
|
|
const item = queueManager.enqueue('https://instagram.com/p/TEST123');
|
|
|
|
const url = new URL(`http://localhost/api/queue/stream?id=${item.id}`);
|
|
const request = new Request(url);
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request: {
|
|
...request,
|
|
signal: new AbortController().signal
|
|
}
|
|
} as any);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.headers.get('Content-Type')).toBe('text/event-stream');
|
|
});
|
|
|
|
it('should handle stream initialization without errors', async () => {
|
|
// Add some test items
|
|
queueManager.enqueue('https://instagram.com/p/TEST1');
|
|
queueManager.enqueue('https://instagram.com/p/TEST2');
|
|
|
|
const url = new URL('http://localhost/api/queue/stream');
|
|
const abortController = new AbortController();
|
|
const request = new Request(url, {
|
|
signal: abortController.signal
|
|
});
|
|
|
|
const response = await streamGET({
|
|
url,
|
|
request
|
|
} as any);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body).toBeInstanceOf(ReadableStream);
|
|
|
|
// Abort the request to clean up
|
|
abortController.abort();
|
|
});
|
|
});
|
|
|
|
// Note: Full SSE stream testing would require more complex setup with
|
|
// ReadableStream readers and async iteration, which is beyond the scope
|
|
// of these basic endpoint validation tests. The above tests verify that:
|
|
// 1. The endpoint responds correctly
|
|
// 2. Headers are set properly for SSE
|
|
// 3. Parameter validation works
|
|
// 4. Stream initialization succeeds
|
|
}); |