anvilsign in

collin/strudel-claude

1// Geometry tests. `node --test node-tui/layout.test.ts`
2//
3// The property that matters for the mouse is coverage: every cell of the body
4// belongs to exactly one pane frame. A gap means a click that does nothing, and
5// an overlap means a click that focuses whichever pane the handler happens to
6// test first — both read as the mouse being broken.
7import { test } from 'node:test';
8import assert from 'node:assert/strict';
9
10import { computeLayout, contains } from './layout.ts';
11import type { Layout } from './layout.ts';
12
13const layout = (over: Partial<Parameters<typeof computeLayout>[0]> = {}): Layout =>
14 computeLayout({
15 rows: 40,
16 columns: 140,
17 sessionsWidth: 22,
18 chatWidth: 34,
19 logRows: 0,
20 wideEnough: 100,
21 lineCount: 8,
22 zoom: 'none',
23 ...over,
24 });
25
26test('every column of the body belongs to exactly one pane', () => {
27 const l = layout();
28 const bottom = l.editorFrame.top + l.editorFrame.height;
29 for (let row = l.editorFrame.top; row < bottom; row++) {
30 for (let column = 0; column < 140; column++) {
31 const hits = [l.sessionsFrame, l.chatFrame, l.editorFrame]
32 .filter((rect) => contains(rect, row, column)).length;
33 assert.equal(hits, 1, `row ${row}, column ${column} matched ${hits} panes`);
34 }
35 }
36});
37
38test('a pane frame includes the border its text area excludes', () => {
39 const l = layout();
40 // The chat's text area starts two columns inside its box (border, padding).
41 assert.ok(l.chat && l.chatFrame);
42 assert.equal(l.chat.left - l.chatFrame.left, 2);
43 assert.ok(contains(l.chatFrame, l.chat.top, l.chatFrame.left));
44 assert.ok(!contains(l.chat, l.chat.top, l.chatFrame.left));
45});
46
47test('narrow terminals have no side panes to click', () => {
48 const l = layout({ columns: 80 });
49 assert.equal(l.sessionsFrame, null);
50 assert.equal(l.chatFrame, null);
51 assert.equal(l.editorFrame.left, 0);
52 assert.equal(l.editorFrame.width, 80);
53});
54
55test('an open log takes its rows from the panes, not from the status bar', () => {
56 const closed = layout();
57 const open = layout({ logRows: 8 });
58 assert.equal(closed.editor.height - open.editor.height, 8);
59});