vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
89 lines (88 loc) • 4.01 kB
JavaScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { sseNotifier } from './index.js';
import { JobStatus } from '../job-manager/index.js';
vi.mock('../../logger.js', () => ({
default: {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
}
}));
const createMockResponse = () => ({
write: vi.fn(),
flushHeaders: vi.fn(),
on: vi.fn((event, listener) => {
if (event === 'close') {
mockResponse._closeListener = listener;
}
return mockResponse;
}),
off: vi.fn(),
writableEnded: false,
});
let mockResponse;
describe('SseNotifier Singleton', () => {
beforeEach(() => {
mockResponse = createMockResponse();
vi.clearAllMocks();
sseNotifier.connections.clear();
});
it('should register a new connection', () => {
const sessionId = 'session-1';
sseNotifier.registerConnection(sessionId, mockResponse);
expect(sseNotifier.connections.has(sessionId)).toBe(true);
expect(sseNotifier.connections.get(sessionId)).toBe(mockResponse);
expect(mockResponse.write).toHaveBeenCalledWith('event: connection\ndata: established\n\n');
});
it('should unregister a connection', () => {
const sessionId = 'session-1';
sseNotifier.registerConnection(sessionId, mockResponse);
sseNotifier.unregisterConnection(sessionId);
expect(sseNotifier.connections.has(sessionId)).toBe(false);
});
it('should automatically unregister when the connection closes', () => {
const sessionId = 'session-1';
sseNotifier.registerConnection(sessionId, mockResponse);
expect(sseNotifier.connections.has(sessionId)).toBe(true);
if (mockResponse._closeListener) {
mockResponse._closeListener();
}
else {
throw new Error("Close listener was not registered by mock");
}
expect(sseNotifier.connections.has(sessionId)).toBe(false);
});
it('should send progress updates to a registered connection', () => {
const sessionId = 'session-1';
const jobId = 'job-123';
const status = JobStatus.RUNNING;
const message = 'Processing step 1...';
sseNotifier.registerConnection(sessionId, mockResponse);
sseNotifier.sendProgress(sessionId, jobId, status, message);
const expectedData = JSON.stringify({ jobId, status, message });
const expectedSseMessage = `event: progress\ndata: ${expectedData}\n\n`;
expect(mockResponse.write).toHaveBeenCalledWith(expectedSseMessage);
});
it('should not send progress if session ID is not registered', () => {
sseNotifier.sendProgress('non-existent-session', 'job-1', JobStatus.RUNNING, 'message');
expect(mockResponse.write).not.toHaveBeenCalledWith(expect.stringContaining('event: progress'));
});
it('should handle JSON stringify errors gracefully when sending progress', () => {
const sessionId = 'session-1';
sseNotifier.registerConnection(sessionId, mockResponse);
const circularData = { jobId: 'job-circ' };
circularData.self = circularData;
expect(() => sseNotifier.sendProgress(sessionId, 'job-circ', JobStatus.FAILED, 'Test circular data handling')).not.toThrow();
expect(mockResponse.write).toHaveBeenCalledTimes(1);
expect(mockResponse.write).not.toHaveBeenCalledWith(expect.stringContaining('job-circ'));
});
it('should not send progress if the connection is already closed (writableEnded)', () => {
const sessionId = 'session-1';
sseNotifier.registerConnection(sessionId, mockResponse);
mockResponse.writableEnded = true;
sseNotifier.sendProgress(sessionId, 'job-1', JobStatus.COMPLETED, 'Done');
expect(mockResponse.write).toHaveBeenCalledTimes(1);
expect(mockResponse.write).not.toHaveBeenCalledWith(expect.stringContaining('event: progress'));
});
});