mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
test fixes
This commit is contained in:
parent
dcd65b5db4
commit
bfeb94d972
5 changed files with 128 additions and 105 deletions
|
|
@ -95,7 +95,7 @@ describe('TerminalQuickKeys', () => {
|
||||||
|
|
||||||
// Should have sent only the 'a' key
|
// Should have sent only the 'a' key
|
||||||
expect(mockOnKeyPress).toHaveBeenCalledOnce();
|
expect(mockOnKeyPress).toHaveBeenCalledOnce();
|
||||||
expect(mockOnKeyPress).toHaveBeenCalledWith('a', false, false);
|
expect(mockOnKeyPress).toHaveBeenCalledWith('a', false, false, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle multiple Option+Arrow sequences', () => {
|
it('should handle multiple Option+Arrow sequences', () => {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,27 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { DEFAULT_NOTIFICATION_PREFERENCES } from '../../types/config.js';
|
import { DEFAULT_NOTIFICATION_PREFERENCES } from '../../types/config.js';
|
||||||
import type { NotificationPreferences } from './push-notification-service.js';
|
import type { NotificationPreferences } from './push-notification-service.js';
|
||||||
import { pushNotificationService } from './push-notification-service.js';
|
import { pushNotificationService } from './push-notification-service.js';
|
||||||
|
import { notificationEventService } from './notification-event-service.js';
|
||||||
|
import { serverConfigService } from './server-config-service.js';
|
||||||
|
|
||||||
|
// Mock notification event service
|
||||||
|
vi.mock('./notification-event-service', () => ({
|
||||||
|
notificationEventService: {
|
||||||
|
on: vi.fn(),
|
||||||
|
off: vi.fn(),
|
||||||
|
connect: vi.fn(),
|
||||||
|
disconnect: vi.fn(),
|
||||||
|
getConnectionStatus: vi.fn(() => true),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock server config service
|
||||||
|
vi.mock('./server-config-service', () => ({
|
||||||
|
serverConfigService: {
|
||||||
|
getNotificationPreferences: vi.fn(),
|
||||||
|
updateNotificationPreferences: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
// Mock the auth client
|
// Mock the auth client
|
||||||
vi.mock('./auth-client', () => ({
|
vi.mock('./auth-client', () => ({
|
||||||
|
|
@ -303,33 +324,7 @@ describe('PushNotificationService', () => {
|
||||||
soundEnabled: true,
|
soundEnabled: true,
|
||||||
vibrationEnabled: false,
|
vibrationEnabled: false,
|
||||||
};
|
};
|
||||||
|
(serverConfigService.getNotificationPreferences as vi.Mock).mockResolvedValue(serverPrefs);
|
||||||
// Mock the config API response
|
|
||||||
global.fetch = vi.fn().mockImplementation((url: string) => {
|
|
||||||
if (url === '/api/push/vapid-public-key') {
|
|
||||||
return Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
json: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
publicKey: 'test-vapid-key',
|
|
||||||
enabled: true,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (url === '/api/config') {
|
|
||||||
return Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
json: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
notificationPreferences: serverPrefs,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
json: () => Promise.resolve({}),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
await pushNotificationService.initialize();
|
await pushNotificationService.initialize();
|
||||||
|
|
||||||
|
|
@ -501,27 +496,9 @@ describe('PushNotificationService', () => {
|
||||||
vibrationEnabled: true,
|
vibrationEnabled: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
global.fetch = vi.fn().mockResolvedValue({
|
|
||||||
ok: true,
|
|
||||||
json: () =>
|
|
||||||
Promise.resolve({
|
|
||||||
notificationPreferences: preferences,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
await pushNotificationService.savePreferences(preferences);
|
await pushNotificationService.savePreferences(preferences);
|
||||||
|
|
||||||
// Since we're now using serverConfigService, we expect a config API call
|
expect(serverConfigService.updateNotificationPreferences).toHaveBeenCalledWith(preferences);
|
||||||
expect(fetch).toHaveBeenCalledWith(
|
|
||||||
'/api/config',
|
|
||||||
expect.objectContaining({
|
|
||||||
method: 'PUT',
|
|
||||||
headers: expect.objectContaining({
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}),
|
|
||||||
body: expect.stringContaining('notificationPreferences'),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle save failure gracefully', async () => {
|
it('should handle save failure gracefully', async () => {
|
||||||
|
|
@ -537,9 +514,8 @@ describe('PushNotificationService', () => {
|
||||||
vibrationEnabled: true,
|
vibrationEnabled: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
global.fetch = vi.fn().mockRejectedValue(new Error('Network error'));
|
(serverConfigService.updateNotificationPreferences as vi.Mock).mockRejectedValue(new Error('Network error'));
|
||||||
|
|
||||||
// Should throw error now since we don't fallback to localStorage
|
|
||||||
await expect(pushNotificationService.savePreferences(preferences)).rejects.toThrow(
|
await expect(pushNotificationService.savePreferences(preferences)).rejects.toThrow(
|
||||||
'Network error'
|
'Network error'
|
||||||
);
|
);
|
||||||
|
|
@ -555,7 +531,27 @@ describe('PushNotificationService', () => {
|
||||||
|
|
||||||
await pushNotificationService.initialize();
|
await pushNotificationService.initialize();
|
||||||
|
|
||||||
await pushNotificationService.testNotification();
|
// Capture the event handler
|
||||||
|
let testNotificationHandler: (data: any) => void;
|
||||||
|
(notificationEventService.on as vi.Mock).mockImplementation((event, handler) => {
|
||||||
|
if (event === 'test-notification') {
|
||||||
|
testNotificationHandler = handler;
|
||||||
|
}
|
||||||
|
return () => {}; // Return an unsubscribe function
|
||||||
|
});
|
||||||
|
|
||||||
|
const testPromise = pushNotificationService.testNotification();
|
||||||
|
|
||||||
|
// Simulate receiving the event
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100)); // allow time for listener to be registered
|
||||||
|
|
||||||
|
expect(testNotificationHandler!).toBeDefined();
|
||||||
|
testNotificationHandler!({
|
||||||
|
title: 'VibeTunnel Test',
|
||||||
|
body: 'Push notifications are working correctly!',
|
||||||
|
});
|
||||||
|
|
||||||
|
await testPromise;
|
||||||
|
|
||||||
expect(mockServiceWorkerRegistration.showNotification).toHaveBeenCalledWith(
|
expect(mockServiceWorkerRegistration.showNotification).toHaveBeenCalledWith(
|
||||||
'VibeTunnel Test',
|
'VibeTunnel Test',
|
||||||
|
|
@ -563,7 +559,7 @@ describe('PushNotificationService', () => {
|
||||||
body: 'Push notifications are working correctly!',
|
body: 'Push notifications are working correctly!',
|
||||||
icon: '/apple-touch-icon.png',
|
icon: '/apple-touch-icon.png',
|
||||||
badge: '/favicon-32.png',
|
badge: '/favicon-32.png',
|
||||||
tag: 'vibetunnel-test',
|
tag: 'vibetunnel-test-sse',
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -576,9 +572,24 @@ describe('PushNotificationService', () => {
|
||||||
|
|
||||||
await pushNotificationService.initialize();
|
await pushNotificationService.initialize();
|
||||||
|
|
||||||
await expect(pushNotificationService.testNotification()).rejects.toThrow(
|
// Capture the event handler
|
||||||
'Notification permission not granted'
|
let testNotificationHandler: (data: any) => void;
|
||||||
);
|
(notificationEventService.on as vi.Mock).mockImplementation((event, handler) => {
|
||||||
|
if (event === 'test-notification') {
|
||||||
|
testNotificationHandler = handler;
|
||||||
|
}
|
||||||
|
return () => {}; // Return an unsubscribe function
|
||||||
|
});
|
||||||
|
|
||||||
|
const testPromise = pushNotificationService.testNotification();
|
||||||
|
|
||||||
|
// Simulate receiving the event
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
expect(testNotificationHandler!).toBeDefined();
|
||||||
|
testNotificationHandler!({});
|
||||||
|
|
||||||
|
await testPromise;
|
||||||
|
|
||||||
expect(mockServiceWorkerRegistration.showNotification).not.toHaveBeenCalled();
|
expect(mockServiceWorkerRegistration.showNotification).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ vi.mock('../utils/logger', () => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('Claude Turn Events', () => {
|
describe('Claude Turn Events', () => {
|
||||||
let mockPtyManager: PtyManager & EventEmitter;
|
let mockSessionMonitor: SessionMonitor & EventEmitter;
|
||||||
let mockRequest: Partial<Request> & {
|
let mockRequest: Partial<Request> & {
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
on: ReturnType<typeof vi.fn>;
|
on: ReturnType<typeof vi.fn>;
|
||||||
|
|
@ -26,8 +26,8 @@ describe('Claude Turn Events', () => {
|
||||||
let eventHandler: (req: Request, res: Response) => void;
|
let eventHandler: (req: Request, res: Response) => void;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Create a mock PtyManager that extends EventEmitter
|
// Create a mock SessionMonitor that extends EventEmitter
|
||||||
mockPtyManager = new EventEmitter() as PtyManager & EventEmitter;
|
mockSessionMonitor = new EventEmitter() as SessionMonitor & EventEmitter;
|
||||||
|
|
||||||
// Create mock request
|
// Create mock request
|
||||||
mockRequest = {
|
mockRequest = {
|
||||||
|
|
@ -43,7 +43,7 @@ describe('Claude Turn Events', () => {
|
||||||
} as unknown as Response;
|
} as unknown as Response;
|
||||||
|
|
||||||
// Create router
|
// Create router
|
||||||
eventsRouter = createEventsRouter(mockPtyManager);
|
eventsRouter = createEventsRouter(mockSessionMonitor);
|
||||||
|
|
||||||
// Get the /events handler
|
// Get the /events handler
|
||||||
interface RouteLayer {
|
interface RouteLayer {
|
||||||
|
|
@ -75,7 +75,12 @@ describe('Claude Turn Events', () => {
|
||||||
// Emit claude-turn event
|
// Emit claude-turn event
|
||||||
const sessionId = 'claude-session-123';
|
const sessionId = 'claude-session-123';
|
||||||
const sessionName = 'Claude Code Session';
|
const sessionName = 'Claude Code Session';
|
||||||
mockPtyManager.emit('claudeTurn', sessionId, sessionName);
|
mockSessionMonitor.emit('notification', {
|
||||||
|
type: 'claude-turn',
|
||||||
|
sessionId,
|
||||||
|
sessionName,
|
||||||
|
message: 'Claude has finished responding',
|
||||||
|
});
|
||||||
|
|
||||||
// Verify SSE was sent
|
// Verify SSE was sent
|
||||||
expect(mockResponse.write).toHaveBeenCalledWith(
|
expect(mockResponse.write).toHaveBeenCalledWith(
|
||||||
|
|
@ -97,9 +102,9 @@ describe('Claude Turn Events', () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
// Emit multiple claude-turn events
|
// Emit multiple claude-turn events
|
||||||
mockPtyManager.emit('claudeTurn', 'session-1', 'First Claude Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'session-1' });
|
||||||
mockPtyManager.emit('claudeTurn', 'session-2', 'Second Claude Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'session-2' });
|
||||||
mockPtyManager.emit('claudeTurn', 'session-3', 'Third Claude Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'session-3' });
|
||||||
|
|
||||||
// Should have written 3 events
|
// Should have written 3 events
|
||||||
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
|
|
@ -111,9 +116,13 @@ describe('Claude Turn Events', () => {
|
||||||
await eventHandler(mockRequest, mockResponse);
|
await eventHandler(mockRequest, mockResponse);
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
const beforeTime = new Date().toISOString();
|
const beforeTime = new Date();
|
||||||
mockPtyManager.emit('claudeTurn', 'test-session', 'Test Session');
|
mockSessionMonitor.emit('notification', {
|
||||||
const afterTime = new Date().toISOString();
|
type: 'claude-turn',
|
||||||
|
sessionId: 'test-session',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
const afterTime = new Date();
|
||||||
|
|
||||||
// Get the event data
|
// Get the event data
|
||||||
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
||||||
|
|
@ -121,8 +130,8 @@ describe('Claude Turn Events', () => {
|
||||||
|
|
||||||
expect(eventData.timestamp).toBeDefined();
|
expect(eventData.timestamp).toBeDefined();
|
||||||
expect(new Date(eventData.timestamp).toISOString()).toEqual(eventData.timestamp);
|
expect(new Date(eventData.timestamp).toISOString()).toEqual(eventData.timestamp);
|
||||||
expect(eventData.timestamp >= beforeTime).toBe(true);
|
expect(new Date(eventData.timestamp).getTime()).toBeGreaterThanOrEqual(beforeTime.getTime());
|
||||||
expect(eventData.timestamp <= afterTime).toBe(true);
|
expect(new Date(eventData.timestamp).getTime()).toBeLessThanOrEqual(afterTime.getTime());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should unsubscribe from claude-turn events on disconnect', async () => {
|
it('should unsubscribe from claude-turn events on disconnect', async () => {
|
||||||
|
|
@ -135,13 +144,13 @@ describe('Claude Turn Events', () => {
|
||||||
expect(closeHandler).toBeTruthy();
|
expect(closeHandler).toBeTruthy();
|
||||||
|
|
||||||
// Verify claude-turn listener is attached
|
// Verify claude-turn listener is attached
|
||||||
expect(mockPtyManager.listenerCount('claudeTurn')).toBe(1);
|
expect(mockSessionMonitor.listenerCount('notification')).toBe(1);
|
||||||
|
|
||||||
// Simulate client disconnect
|
// Simulate client disconnect
|
||||||
closeHandler();
|
closeHandler();
|
||||||
|
|
||||||
// Verify listener is removed
|
// Verify listener is removed
|
||||||
expect(mockPtyManager.listenerCount('claudeTurn')).toBe(0);
|
expect(mockSessionMonitor.listenerCount('notification')).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle claude-turn alongside other events', async () => {
|
it('should handle claude-turn alongside other events', async () => {
|
||||||
|
|
@ -149,15 +158,13 @@ describe('Claude Turn Events', () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
// Emit various events including claude-turn
|
// Emit various events including claude-turn
|
||||||
mockPtyManager.emit('sessionStarted', 'session-1', 'New Session');
|
mockSessionMonitor.emit('notification', { type: 'session-start', sessionId: 'session-1' });
|
||||||
mockPtyManager.emit('claudeTurn', 'session-1', 'New Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'session-1' });
|
||||||
mockPtyManager.emit('commandFinished', {
|
mockSessionMonitor.emit('notification', {
|
||||||
|
type: 'command-finished',
|
||||||
sessionId: 'session-1',
|
sessionId: 'session-1',
|
||||||
command: 'echo test',
|
|
||||||
duration: 100,
|
|
||||||
exitCode: 0,
|
|
||||||
});
|
});
|
||||||
mockPtyManager.emit('sessionExited', 'session-1', 'New Session', 0);
|
mockSessionMonitor.emit('notification', { type: 'session-exit', sessionId: 'session-1' });
|
||||||
|
|
||||||
// Verify all events were sent
|
// Verify all events were sent
|
||||||
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
|
|
@ -180,7 +187,13 @@ describe('Claude Turn Events', () => {
|
||||||
await eventHandler(mockRequest, mockResponse);
|
await eventHandler(mockRequest, mockResponse);
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
mockPtyManager.emit('claudeTurn', 'session-123', 'My Claude Session');
|
mockSessionMonitor.emit('notification', {
|
||||||
|
type: 'claude-turn',
|
||||||
|
sessionId: 'session-123',
|
||||||
|
sessionName: 'My Claude Session',
|
||||||
|
message: 'Claude has finished responding',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
|
||||||
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import type { PtyManager } from '../pty/index.js';
|
import type { SessionMonitor } from '../services/session-monitor.js';
|
||||||
import { createEventsRouter } from './events.js';
|
import { createEventsRouter } from './events.js';
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
|
|
@ -27,7 +27,7 @@ interface RouteLayer {
|
||||||
type ExpressRouter = { stack: RouteLayer[] };
|
type ExpressRouter = { stack: RouteLayer[] };
|
||||||
|
|
||||||
describe('Events Router', () => {
|
describe('Events Router', () => {
|
||||||
let mockPtyManager: PtyManager & EventEmitter;
|
let mockSessionMonitor: SessionMonitor & EventEmitter;
|
||||||
let mockRequest: Partial<Request> & {
|
let mockRequest: Partial<Request> & {
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
on: ReturnType<typeof vi.fn>;
|
on: ReturnType<typeof vi.fn>;
|
||||||
|
|
@ -36,8 +36,8 @@ describe('Events Router', () => {
|
||||||
let eventsRouter: ReturnType<typeof createEventsRouter>;
|
let eventsRouter: ReturnType<typeof createEventsRouter>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Create a mock PtyManager that extends EventEmitter
|
// Create a mock SessionMonitor that extends EventEmitter
|
||||||
mockPtyManager = new EventEmitter() as PtyManager & EventEmitter;
|
mockSessionMonitor = new EventEmitter() as SessionMonitor & EventEmitter;
|
||||||
|
|
||||||
// Create mock request
|
// Create mock request
|
||||||
mockRequest = {
|
mockRequest = {
|
||||||
|
|
@ -57,7 +57,7 @@ describe('Events Router', () => {
|
||||||
} as unknown as Response;
|
} as unknown as Response;
|
||||||
|
|
||||||
// Create router
|
// Create router
|
||||||
eventsRouter = createEventsRouter(mockPtyManager);
|
eventsRouter = createEventsRouter(mockSessionMonitor);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
@ -120,16 +120,13 @@ describe('Events Router', () => {
|
||||||
|
|
||||||
// Emit a sessionExit event
|
// Emit a sessionExit event
|
||||||
const eventData = {
|
const eventData = {
|
||||||
|
type: 'session-exit',
|
||||||
sessionId: 'test-123',
|
sessionId: 'test-123',
|
||||||
sessionName: 'Test Session',
|
sessionName: 'Test Session',
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
mockPtyManager.emit(
|
mockSessionMonitor.emit('notification', eventData);
|
||||||
'sessionExited',
|
|
||||||
eventData.sessionId,
|
|
||||||
eventData.sessionName,
|
|
||||||
eventData.exitCode
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify SSE was sent - check that the data contains our expected fields
|
// Verify SSE was sent - check that the data contains our expected fields
|
||||||
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
||||||
|
|
@ -165,12 +162,14 @@ describe('Events Router', () => {
|
||||||
|
|
||||||
// Emit a commandFinished event
|
// Emit a commandFinished event
|
||||||
const eventData = {
|
const eventData = {
|
||||||
|
type: 'command-finished',
|
||||||
sessionId: 'test-123',
|
sessionId: 'test-123',
|
||||||
command: 'npm test',
|
command: 'npm test',
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
duration: 5432,
|
duration: 5432,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
mockPtyManager.emit('commandFinished', eventData);
|
mockSessionMonitor.emit('notification', eventData);
|
||||||
|
|
||||||
// Verify SSE was sent - check that the data contains our expected fields
|
// Verify SSE was sent - check that the data contains our expected fields
|
||||||
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
const writeCall = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls[0][0];
|
||||||
|
|
@ -206,9 +205,13 @@ describe('Events Router', () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
// Emit multiple events
|
// Emit multiple events
|
||||||
mockPtyManager.emit('sessionExited', 'session-1');
|
mockSessionMonitor.emit('notification', { type: 'session-exit', sessionId: 'session-1' });
|
||||||
mockPtyManager.emit('commandFinished', { sessionId: 'session-2', command: 'ls' });
|
mockSessionMonitor.emit('notification', {
|
||||||
mockPtyManager.emit('claudeTurn', 'session-3', 'Session 3');
|
type: 'command-finished',
|
||||||
|
sessionId: 'session-2',
|
||||||
|
command: 'ls',
|
||||||
|
});
|
||||||
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'session-3' });
|
||||||
|
|
||||||
// Should have written 3 events
|
// Should have written 3 events
|
||||||
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
|
|
@ -255,17 +258,13 @@ describe('Events Router', () => {
|
||||||
expect(closeHandler).toBeTruthy();
|
expect(closeHandler).toBeTruthy();
|
||||||
|
|
||||||
// Verify listeners are attached
|
// Verify listeners are attached
|
||||||
expect(mockPtyManager.listenerCount('sessionExited')).toBeGreaterThan(0);
|
expect(mockSessionMonitor.listenerCount('notification')).toBeGreaterThan(0);
|
||||||
expect(mockPtyManager.listenerCount('commandFinished')).toBeGreaterThan(0);
|
|
||||||
expect(mockPtyManager.listenerCount('claudeTurn')).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
// Simulate client disconnect
|
// Simulate client disconnect
|
||||||
closeHandler();
|
closeHandler();
|
||||||
|
|
||||||
// Verify listeners are removed
|
// Verify listeners are removed
|
||||||
expect(mockPtyManager.listenerCount('sessionExited')).toBe(0);
|
expect(mockSessionMonitor.listenerCount('notification')).toBe(0);
|
||||||
expect(mockPtyManager.listenerCount('commandFinished')).toBe(0);
|
|
||||||
expect(mockPtyManager.listenerCount('claudeTurn')).toBe(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle response errors gracefully', async () => {
|
it('should handle response errors gracefully', async () => {
|
||||||
|
|
@ -287,7 +286,7 @@ describe('Events Router', () => {
|
||||||
|
|
||||||
// Should not throw even if write fails
|
// Should not throw even if write fails
|
||||||
expect(() => {
|
expect(() => {
|
||||||
mockPtyManager.emit('claudeTurn', 'test', 'Test Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'test' });
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -304,7 +303,7 @@ describe('Events Router', () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
// Emit an event
|
// Emit an event
|
||||||
mockPtyManager.emit('claudeTurn', 'test-123', 'Test Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'test-123' });
|
||||||
|
|
||||||
// Verify SSE format includes id
|
// Verify SSE format includes id
|
||||||
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
const writeCalls = (mockResponse.write as ReturnType<typeof vi.fn>).mock.calls;
|
||||||
|
|
@ -337,11 +336,11 @@ describe('Events Router', () => {
|
||||||
|
|
||||||
// Should not throw
|
// Should not throw
|
||||||
expect(() => {
|
expect(() => {
|
||||||
mockPtyManager.emit('claudeTurn', 'test-123', 'Test Session');
|
mockSessionMonitor.emit('notification', circularData);
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
|
|
||||||
// Should have attempted to write something
|
// Should not have written anything for the malformed event
|
||||||
expect(mockResponse.write).toHaveBeenCalled();
|
expect(mockResponse.write).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -378,7 +377,7 @@ describe('Events Router', () => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
// Emit an event
|
// Emit an event
|
||||||
mockPtyManager.emit('claudeTurn', 'test-123', 'Test Session');
|
mockSessionMonitor.emit('notification', { type: 'claude-turn', sessionId: 'test-123' });
|
||||||
|
|
||||||
// Both clients should receive the event
|
// Both clients should receive the event
|
||||||
expect(client1Response.write).toHaveBeenCalledWith(
|
expect(client1Response.write).toHaveBeenCalledWith(
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ describe('Socket Protocol Integration', () => {
|
||||||
|
|
||||||
// Set up status listener on client2
|
// Set up status listener on client2
|
||||||
let receivedStatus: { app: string; status: string } | null = null;
|
let receivedStatus: { app: string; status: string } | null = null;
|
||||||
client2.on('status', (status) => {
|
client2.on('STATUS_UPDATE', (status) => {
|
||||||
receivedStatus = status;
|
receivedStatus = status;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue