UNPKG

@nestjsvn/swagger-sse

Version:

OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints

228 lines (227 loc) 13.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const setup_1 = require("./setup"); const test_controllers_1 = require("./test-controllers"); describe('Basic SSE Functionality E2E Tests', () => { let context; beforeAll(async () => { context = await setup_1.E2ETestSetup.createContext('basic-functionality', { controllers: [test_controllers_1.TestEventsController, test_controllers_1.MobileTestController], }); }); afterAll(async () => { await setup_1.E2ETestSetup.cleanup('basic-functionality'); }); describe('Swagger UI Integration', () => { it('should load Swagger UI with SSE endpoints', async () => { await context.page.goto(`${context.baseUrl}/api-docs`); // Wait for Swagger UI to load await context.page.waitForSelector('.swagger-ui'); // Check that test-events endpoints are documented const testEventsEndpoints = await context.page.$$('[data-path*="/test-events"]'); expect(testEventsEndpoints.length).toBeGreaterThan(0); // Verify basic endpoint is present const basicEndpoint = await context.page.$('[data-path="/test-events/basic"]'); expect(basicEndpoint).toBeTruthy(); }); it('should display SSE-specific UI elements after clicking Execute', async () => { await context.page.goto(`${context.baseUrl}/api-docs`); await context.page.waitForSelector('.swagger-ui'); // Expand the basic SSE endpoint - click on the summary control const summarySelector = '[data-path="/test-events/basic"]'; await context.page.click(summarySelector); await context.page.waitForTimeout(1000); // Wait for "Try it out" button and click it await context.page.waitForSelector('.btn.try-out__btn', { timeout: 5000 }); await context.page.click('.btn.try-out__btn'); await context.page.waitForTimeout(1000); // Wait for the Execute button to appear and click it await context.page.waitForSelector('.execute-wrapper .btn.execute', { timeout: 5000 }); await context.page.click('.execute-wrapper .btn.execute'); // Wait for SSE-specific UI elements to appear await context.page.waitForSelector('[data-testid="sse-connect-btn"]', { timeout: 5000 }); const connectButton = await context.page.$('[data-testid="sse-connect-btn"]'); const statusIndicator = await context.page.$('[data-testid="sse-status"]'); const eventLog = await context.page.$('[data-testid="sse-event-log"]'); expect(connectButton).toBeTruthy(); expect(statusIndicator).toBeTruthy(); expect(eventLog).toBeTruthy(); }); }); describe('SSE Connection Management', () => { beforeEach(async () => { await context.page.goto(`${context.baseUrl}/api-docs`); await context.page.waitForSelector('.swagger-ui'); // Expand the basic SSE endpoint specifically await context.page.click('[data-path="/test-events/basic"]'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.btn.try-out__btn', { timeout: 5000 }); await context.page.click('.btn.try-out__btn'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.execute-wrapper .btn.execute', { timeout: 5000 }); await context.page.click('.execute-wrapper .btn.execute'); await context.page.waitForSelector('[data-testid="sse-connect-btn"]', { timeout: 5000 }); }); it('should establish SSE connection successfully', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); // Verify connection status const status = await context.page.getAttribute('[data-testid="sse-status"]', 'data-status'); expect(status).toBe('connected'); // Verify connect button is disabled and disconnect button is enabled const connectBtn = await context.page.$('[data-testid="sse-connect-btn"]:disabled'); const disconnectBtn = await context.page.$('[data-testid="sse-disconnect-btn"]:not(:disabled)'); expect(connectBtn).toBeTruthy(); expect(disconnectBtn).toBeTruthy(); }); it('should disconnect SSE connection successfully', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); await setup_1.SSETestHelpers.disconnectFromSSE(context.page); // Verify disconnection status const status = await context.page.getAttribute('[data-testid="sse-status"]', 'data-status'); expect(status).toBe('disconnected'); // Verify button states are reversed const connectBtn = await context.page.$('[data-testid="sse-connect-btn"]:not(:disabled)'); const disconnectBtn = await context.page.$('[data-testid="sse-disconnect-btn"]:disabled'); expect(connectBtn).toBeTruthy(); expect(disconnectBtn).toBeTruthy(); }); it('should handle connection errors gracefully', async () => { // Navigate to a non-existent endpoint to trigger error await context.page.goto(`${context.baseUrl}/api-docs`); await context.page.waitForSelector('.swagger-ui'); await context.page.evaluate(() => { // Mock a connection error by overriding EventSource window.EventSource = class { constructor() { this.onerror = null; setTimeout(() => { if (this.onerror) this.onerror(new Event('error')); }, 100); } addEventListener() { } close() { } }; }); // Follow the correct Swagger UI flow for basic SSE endpoint await context.page.click('[data-path="/test-events/basic"]'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.btn.try-out__btn', { timeout: 5000 }); await context.page.click('.btn.try-out__btn'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.execute-wrapper .btn.execute', { timeout: 5000 }); await context.page.click('.execute-wrapper .btn.execute'); await context.page.waitForSelector('[data-testid="sse-connect-btn"]', { timeout: 5000 }); await context.page.click('[data-testid="sse-connect-btn"]'); // Wait for error state await context.page.waitForSelector('[data-testid="sse-status"][data-status="error"]', { timeout: 5000, }); const status = await context.page.getAttribute('[data-testid="sse-status"]', 'data-status'); expect(status).toBe('error'); }); }); describe('Event Reception and Display', () => { beforeEach(async () => { await context.page.goto(`${context.baseUrl}/api-docs`); await context.page.waitForSelector('.swagger-ui'); // Expand the basic SSE endpoint specifically await context.page.click('[data-path="/test-events/basic"]'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.btn.try-out__btn', { timeout: 5000 }); await context.page.click('.btn.try-out__btn'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.execute-wrapper .btn.execute', { timeout: 5000 }); await context.page.click('.execute-wrapper .btn.execute'); await context.page.waitForSelector('[data-testid="sse-connect-btn"]', { timeout: 5000 }); }); it('should receive and display SSE events', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); // Wait for events to arrive await setup_1.SSETestHelpers.waitForSSEEvents(context.page, 2, 15000); // Get received events const events = await setup_1.SSETestHelpers.getSSEEvents(context.page); expect(events.length).toBeGreaterThanOrEqual(2); expect(events[0].type).toMatch(/user-created|message-received/); expect(events[0].data).toBeDefined(); expect(events[0].timestamp).toBeDefined(); }); it('should display events with correct formatting', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); await setup_1.SSETestHelpers.waitForSSEEvents(context.page, 1, 10000); // Check event display formatting const eventElement = await context.page.$('[data-testid="sse-event"]:first-child'); expect(eventElement).toBeTruthy(); // Verify event has proper structure const eventType = await eventElement?.getAttribute('data-event-type'); const eventData = await eventElement?.getAttribute('data-event-data'); const timestamp = await eventElement?.getAttribute('data-timestamp'); expect(eventType).toMatch(/user-created|message-received/); expect(eventData).toBeDefined(); expect(timestamp).toBeDefined(); // Verify JSON data is valid expect(() => JSON.parse(eventData ?? '{}')).not.toThrow(); }); it('should handle multiple event types correctly', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); await setup_1.SSETestHelpers.waitForSSEEvents(context.page, 3, 20000); const events = await setup_1.SSETestHelpers.getSSEEvents(context.page); // Should have both user-created and message-received events const userCreatedEvents = events.filter(e => e.type === 'user-created'); const messageReceivedEvents = events.filter(e => e.type === 'message-received'); expect(userCreatedEvents.length).toBeGreaterThan(0); expect(messageReceivedEvents.length).toBeGreaterThan(0); // Verify data structure for each event type if (userCreatedEvents.length > 0) { const userData = userCreatedEvents[0].data; expect(userData.userId).toBeDefined(); expect(userData.username).toBeDefined(); expect(userData.email).toBeDefined(); } if (messageReceivedEvents.length > 0) { const messageData = messageReceivedEvents[0].data; expect(messageData.messageId).toBeDefined(); expect(messageData.fromUserId).toBeDefined(); expect(messageData.content).toBeDefined(); } }); }); describe('Event Log Management', () => { beforeEach(async () => { await context.page.goto(`${context.baseUrl}/api-docs`); await context.page.waitForSelector('.swagger-ui'); // Expand the basic SSE endpoint specifically await context.page.click('[data-path="/test-events/basic"]'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.btn.try-out__btn', { timeout: 5000 }); await context.page.click('.btn.try-out__btn'); await context.page.waitForTimeout(1000); await context.page.waitForSelector('.execute-wrapper .btn.execute', { timeout: 5000 }); await context.page.click('.execute-wrapper .btn.execute'); await context.page.waitForSelector('[data-testid="sse-connect-btn"]', { timeout: 5000 }); }); it('should clear event log when clear button is clicked', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); await setup_1.SSETestHelpers.waitForSSEEvents(context.page, 2, 15000); // Verify events are present let events = await setup_1.SSETestHelpers.getSSEEvents(context.page); expect(events.length).toBeGreaterThan(0); // Clear the log await setup_1.SSETestHelpers.clearEventLog(context.page); // Verify events are cleared events = await setup_1.SSETestHelpers.getSSEEvents(context.page); expect(events.length).toBe(0); }); it('should maintain event order chronologically', async () => { await setup_1.SSETestHelpers.connectToSSE(context.page); await setup_1.SSETestHelpers.waitForSSEEvents(context.page, 3, 20000); const events = await setup_1.SSETestHelpers.getSSEEvents(context.page); // Verify timestamps are in chronological order for (let i = 1; i < events.length; i++) { const prevTime = new Date(events[i - 1].timestamp); const currTime = new Date(events[i].timestamp); expect(currTime.getTime()).toBeGreaterThanOrEqual(prevTime.getTime()); } }); }); });