jevstrudel.git / worker / src / tab-hub-core.test.ts
1import { describe, expect, it } from 'vitest';
2import { MAX_FRAME_BYTES, MAX_LOG_CHARS, MAX_LOG_LINES, parseReply, pickTab } from './tab-hub-core';
3
4describe("a tab's reply", () => {
5  it('is rebuilt from the fields the MCP reads, each bounded', () => {
6    const logs = Array.from({ length: MAX_LOG_LINES + 10 }, (_, i) => ({ at: i, message: i < 20 ? 'x'.repeat(MAX_LOG_CHARS + 5) : 'y', kind: 'warning', count: 2, extra: 1 }));
7    const parsed = parseReply(
8      JSON.stringify({ type: 'reply', id: '1-0', ok: true, logs, status: { playing: true, cycle: 2.5, code: 'ai', evil: 1 }, html: '<b>' }),
9    )!;
10    expect(parsed.id).toBe('1-0');
11    expect(parsed.reply.ok).toBe(true);
12    expect(parsed.reply.logs).toHaveLength(MAX_LOG_LINES);
13    expect(parsed.reply.logs![0]).toEqual({ at: 10, message: 'x'.repeat(MAX_LOG_CHARS), kind: 'warning', count: 2 });
14    expect(parsed.reply.status).toEqual({ playing: true, cycle: 2.5, code: 'ai' });
15    expect(parsed.reply).not.toHaveProperty('html');
16  });
17
18  it('drops what is not a reply, or too large', () => {
19    expect(parseReply('nope')).toBeNull();
20    expect(parseReply(JSON.stringify({ type: 'command', id: '1' }))).toBeNull();
21    expect(parseReply(JSON.stringify({ type: 'reply', id: 5 }))).toBeNull();
22    expect(parseReply(JSON.stringify({ type: 'reply', id: '1', code: 'x'.repeat(MAX_FRAME_BYTES) }))).toBeNull();
23    expect(parseReply(new ArrayBuffer(8))).toBeNull();
24    expect(parseReply(JSON.stringify({ type: 'reply', id: '1', status: { code: 'root' } }))!.reply.status!.code).toBe('none');
25  });
26});
27
28describe('which tab a command goes to', () => {
29  it('is the one named, or the only one open', () => {
30    expect(pickTab(['abc1'], undefined)).toBe('abc1');
31    expect(pickTab(['abc1', 'def2'], 'def2')).toBe('def2');
32    expect(() => pickTab([], undefined)).toThrow(/no jevstrudel tab open/);
33    expect(() => pickTab(['abc1', 'def2'], undefined)).toThrow(/pass session_id/);
34    expect(() => pickTab(['abc1'], 'zzz9')).toThrow(/no open tab zzz9/);
35    expect(() => pickTab(['abc1'], '../x')).toThrow(/session_id/);
36  });
37});