import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { buildClientUserAgent, connectWebSocket, DEFAULT_WEBSOCKET_USER_AGENT, MAX_SOCKET_PAYLOAD_BYTES } from './util.js'; const constructorSpy = vi.fn(); // isomorphic-ws resolves to the `ws` package on Node; capture its constructor args. // vitest hoists this mock above the static import above, so `util.ts` picks it up. vi.mock('isomorphic-ws', () => ({ default: class MockWebSocket { constructor(url: string, protocol: unknown, options: unknown) { constructorSpy(url, protocol, options); } addEventListener(): void { // no-op; the connect promise stays pending, which is fine for these assertions } } })); describe('connectWebSocket User-Agent', () => { beforeEach(() => { vi.useFakeTimers(); constructorSpy.mockClear(); }); afterEach(() => { vi.clearAllTimers(); vi.useRealTimers(); }); it('sends a default User-Agent and preserves maxPayload on the handshake', () => { void connectWebSocket('wss://example.com/api/v1/rpc-ws'); expect(constructorSpy).toHaveBeenCalledWith( 'wss://example.com/api/v1/rpc-ws', undefined, expect.objectContaining({ maxPayload: MAX_SOCKET_PAYLOAD_BYTES, headers: expect.objectContaining({ 'User-Agent': DEFAULT_WEBSOCKET_USER_AGENT }) }) ); }); it('lets callers override the User-Agent via options.headers', () => { void connectWebSocket('wss://example.com/api/v1/rpc-ws', { headers: { 'User-Agent': 'superblocks-cli/9.9.9' } }); expect(constructorSpy).toHaveBeenCalledWith( 'wss://example.com/api/v1/rpc-ws', undefined, expect.objectContaining({ headers: expect.objectContaining({ 'User-Agent': 'superblocks-cli/9.9.9' }) }) ); }); it('forwards options.protocol as the WebSocket subprotocol', () => { void connectWebSocket('wss://example.com/api/v1/rpc-ws', { protocol: 'editor' }); expect(constructorSpy).toHaveBeenCalledWith('wss://example.com/api/v1/rpc-ws', 'editor', expect.anything()); }); }); describe('buildClientUserAgent', () => { it('joins component and version with a slash', () => { expect(buildClientUserAgent('superblocks-cli', '2.0.0-next.1')).toBe('superblocks-cli/2.0.0-next.1'); }); it('returns the bare component when no version is given', () => { expect(buildClientUserAgent('superblocks-dev-server')).toBe('superblocks-dev-server'); }); });