// @vitest-environment jsdom /** * test/cell-monitor.test.ts — read-only monitor preview for a grid quadrant. * * Stubs xterm + preview-grid.fetchPreview so we can assert the poll→write loop and * the dispose teardown without a real terminal or server. */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' const terms: FakeTerm[] = [] class FakeTerm { cols = 80 rows = 24 open = vi.fn() write = vi.fn((_data: string, cb?: () => void) => cb?.()) reset = vi.fn() resize = vi.fn() dispose = vi.fn() constructor() { terms.push(this) } } vi.mock('@xterm/xterm', () => ({ Terminal: FakeTerm })) const fetchPreview = vi.fn() vi.mock('../public/preview-grid.js', () => ({ fetchPreview, PREVIEW_CLEAR: '', PREVIEW_THEME: {}, })) const { mountCellMonitor } = await import('../public/cell-monitor.js') beforeEach(() => { terms.length = 0 fetchPreview.mockReset() }) afterEach(() => vi.restoreAllMocks()) describe('cell-monitor', () => { it('opens a read-only term and writes the fetched preview into it', async () => { fetchPreview.mockResolvedValue({ id: 's1', cols: 100, rows: 30, data: 'HELLO' }) const host = document.createElement('div') const m = mountCellMonitor(host, 's1') expect(terms).toHaveLength(1) expect(terms[0]!.open).toHaveBeenCalledWith(host) expect(fetchPreview).toHaveBeenCalledWith('s1') await vi.waitFor(() => expect(terms[0]!.write).toHaveBeenCalled()) expect(terms[0]!.resize).toHaveBeenCalledWith(100, 30) expect(terms[0]!.write.mock.calls[0]![0]).toBe('HELLO') m.dispose() }) it('dispose() tears down the term', () => { fetchPreview.mockResolvedValue({ id: 's1', cols: 80, rows: 24, data: 'X' }) const m = mountCellMonitor(document.createElement('div'), 's1') m.dispose() expect(terms[0]!.dispose).toHaveBeenCalled() }) it('a failed preview fetch skips the write (best-effort)', async () => { fetchPreview.mockResolvedValue(null) const m = mountCellMonitor(document.createElement('div'), 's1') await Promise.resolve() await Promise.resolve() expect(terms[0]!.write).not.toHaveBeenCalled() m.dispose() }) it('does not write after dispose (guards a late resolve)', async () => { let resolve!: (v: unknown) => void fetchPreview.mockReturnValue(new Promise((r) => (resolve = r))) const m = mountCellMonitor(document.createElement('div'), 's1') m.dispose() // dispose BEFORE the fetch resolves resolve({ id: 's1', cols: 80, rows: 24, data: 'LATE' }) await Promise.resolve() await Promise.resolve() expect(terms[0]!.write).not.toHaveBeenCalled() }) })