You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
3.2 KiB
TypeScript
115 lines
3.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { ScreenPoller } from '../../src/bridge/screen-poller.js';
|
|
|
|
// Mock CmuxClient
|
|
function createMockClient(screenContent = 'line1\nline2\nline3') {
|
|
return {
|
|
readScreen: vi.fn().mockResolvedValue(screenContent),
|
|
sendText: vi.fn(),
|
|
sendKey: vi.fn(),
|
|
} as any;
|
|
}
|
|
|
|
describe('ScreenPoller', () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
});
|
|
|
|
it('emits update on first poll', async () => {
|
|
const client = createMockClient();
|
|
const poller = new ScreenPoller(client, 200);
|
|
const updates: any[] = [];
|
|
|
|
poller.on('update', (u: any) => updates.push(u));
|
|
poller.subscribe('client1', 'workspace:1', 'surface:1');
|
|
|
|
// Fast-forward past first poll
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
|
|
expect(updates.length).toBe(1);
|
|
expect(updates[0].full).toBe(true);
|
|
expect(updates[0].lines).toEqual(['line1', 'line2', 'line3']);
|
|
|
|
poller.destroy();
|
|
});
|
|
|
|
it('does not emit when content is unchanged', async () => {
|
|
const client = createMockClient();
|
|
const poller = new ScreenPoller(client, 200);
|
|
const updates: any[] = [];
|
|
|
|
poller.on('update', (u: any) => updates.push(u));
|
|
poller.subscribe('client1', 'workspace:1', 'surface:1');
|
|
|
|
// First poll
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
expect(updates.length).toBe(1);
|
|
|
|
// Second poll — same content
|
|
await vi.advanceTimersByTimeAsync(250);
|
|
expect(updates.length).toBe(1);
|
|
|
|
poller.destroy();
|
|
});
|
|
|
|
it('sends diff patches when content changes', async () => {
|
|
const client = createMockClient('line1\nline2\nline3');
|
|
const poller = new ScreenPoller(client, 200);
|
|
const updates: any[] = [];
|
|
|
|
poller.on('update', (u: any) => updates.push(u));
|
|
poller.subscribe('client1', 'workspace:1', 'surface:1');
|
|
|
|
// First poll
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
expect(updates.length).toBe(1);
|
|
|
|
// Change content
|
|
client.readScreen.mockResolvedValue('line1\nline2-changed\nline3');
|
|
|
|
// Second poll
|
|
await vi.advanceTimersByTimeAsync(250);
|
|
expect(updates.length).toBe(2);
|
|
expect(updates[1].full).toBe(false);
|
|
expect(updates[1].patches).toBeDefined();
|
|
|
|
poller.destroy();
|
|
});
|
|
|
|
it('stops polling when all subscribers unsubscribe', async () => {
|
|
const client = createMockClient();
|
|
const poller = new ScreenPoller(client, 200);
|
|
|
|
poller.subscribe('client1', 'workspace:1', 'surface:1');
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
|
|
poller.unsubscribe('client1', 'surface:1');
|
|
|
|
const callCount = client.readScreen.mock.calls.length;
|
|
await vi.advanceTimersByTimeAsync(500);
|
|
|
|
// Should not have polled again
|
|
expect(client.readScreen.mock.calls.length).toBe(callCount);
|
|
|
|
poller.destroy();
|
|
});
|
|
|
|
it('resets to fast polling on resetToFast', async () => {
|
|
const client = createMockClient();
|
|
const poller = new ScreenPoller(client, 200);
|
|
|
|
poller.subscribe('client1', 'workspace:1', 'surface:1');
|
|
await vi.advanceTimersByTimeAsync(50);
|
|
|
|
// Simulate idle
|
|
for (let i = 0; i < 5; i++) {
|
|
await vi.advanceTimersByTimeAsync(250);
|
|
}
|
|
|
|
poller.resetToFast('surface:1');
|
|
|
|
// Should have reset idle count internally
|
|
poller.destroy();
|
|
});
|
|
});
|