import { afterEach, describe, expect, test, vi } from 'vitest' import { generateConsolePipeCode } from './virtual-console' const TEST_VITE_URL = 'http://localhost:5173' afterEach(() => { vi.useRealTimers() vi.unstubAllGlobals() delete (window as any).__TSD_CONSOLE_PIPE_INITIALIZED__ }) function setupWarnConsolePipe() { const originalWarn = console.warn const originalWarnMock = vi.fn() const fetchMock = vi.fn().mockResolvedValue(undefined) const eventSourceUrls: Array = [] class MockEventSource { onmessage: ((event: MessageEvent) => void) | null = null onerror: (() => void) | null = null constructor(url: string) { eventSourceUrls.push(url) } } console.warn = originalWarnMock vi.stubGlobal('fetch', fetchMock) vi.stubGlobal('EventSource', MockEventSource) const code = generateConsolePipeCode(['warn'], TEST_VITE_URL) new Function(code)() return { eventSourceUrls, fetchMock, originalWarnMock, restore: () => { console.warn = originalWarn }, } } function getFirstFetchBody(fetchMock: ReturnType) { const [, init] = fetchMock.mock.calls[0]! return JSON.parse(init.body) } describe('virtual-console', () => { test('generates inline code with specified levels', () => { const code = generateConsolePipeCode(['log', 'error'], TEST_VITE_URL) expect(code).toContain('["log","error"]') expect(code).toContain('originalConsole') expect(code).toContain('__TSD_CONSOLE_PIPE_INITIALIZED__') }) test('uses fetch to send client logs', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain('/__tsd/console-pipe') expect(code).toContain("method: 'POST'") }) test('uses SSE to receive server logs', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain("new EventSource('/__tsd/console-pipe/sse')") }) test('includes environment detection', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain("typeof window === 'undefined'") expect(code).toContain('isServer') }) test('includes batcher configuration', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain('BATCH_WAIT') expect(code).toContain('BATCH_MAX_SIZE') }) test('includes flush functionality', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain('flushBatch') }) test('includes beforeunload listener for browser', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain('beforeunload') }) test('wraps code in IIFE', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain('(function __tsdConsolePipe()') expect(code).toContain('})();') }) test('has no external imports', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).not.toContain('import ') }) test('includes vite server URL for server piping', () => { const code = generateConsolePipeCode(['log'], TEST_VITE_URL) expect(code).toContain(TEST_VITE_URL) expect(code).toContain('/__tsd/console-pipe/server') }) test('serializes DOM elements before sending logs', async () => { vi.useFakeTimers() const { eventSourceUrls, fetchMock, originalWarnMock, restore } = setupWarnConsolePipe() try { const button = document.createElement('button') button.id = 'save' button.className = 'primary' button.type = 'button' button.setAttribute('data-testid', 'save-button') console.warn('gesture warning', button) await vi.advanceTimersByTimeAsync(100) expect(originalWarnMock).toHaveBeenCalledWith('gesture warning', button) expect(eventSourceUrls).toEqual(['/__tsd/console-pipe/sse']) expect(fetchMock).toHaveBeenCalledTimes(1) const body = getFirstFetchBody(fetchMock) expect(body.entries[0]).toMatchObject({ level: 'warn', source: 'client', args: [ 'gesture warning', '