@nestjsvn/swagger-sse
Version:
OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints
228 lines (227 loc) • 13.3 kB
JavaScript
;
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());
}
});
});
});