splitLeaf always halved just the target pane, so repeated splits left one pane at 50% and the rest squeezed into shrinking fractions instead of equal columns. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
108 lines
3.1 KiB
TypeScript
108 lines
3.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
emptyLayout,
|
|
equalizeRatios,
|
|
leaves,
|
|
locateSession,
|
|
openSessions,
|
|
removeLeaf,
|
|
splitLeaf,
|
|
type Tab,
|
|
} from "./layout.js";
|
|
|
|
function tabWithOneLeaf(sessionId: string | null = null): Tab {
|
|
const layout = emptyLayout();
|
|
const tab = layout.tabs[0];
|
|
splitLeaf(tab, "", sessionId, "row", true);
|
|
return tab;
|
|
}
|
|
|
|
describe("splitLeaf", () => {
|
|
it("seeds an empty tab with a single leaf", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
expect(leaves(tab.root)).toHaveLength(1);
|
|
expect(leaves(tab.root)[0].sessionId).toBe("s1");
|
|
});
|
|
|
|
it("splits a leaf in two and returns the new id", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
const target = leaves(tab.root)[0].id;
|
|
|
|
const fresh = splitLeaf(tab, target, "s2", "row", true);
|
|
|
|
const ids = leaves(tab.root).map((l) => l.id);
|
|
expect(ids).toHaveLength(2);
|
|
expect(ids).toContain(fresh);
|
|
});
|
|
|
|
it("honours the side the caller asked for", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
const target = leaves(tab.root)[0].id;
|
|
const fresh = splitLeaf(tab, target, "s2", "row", false);
|
|
|
|
expect(leaves(tab.root)[0].id).toBe(fresh);
|
|
});
|
|
});
|
|
|
|
describe("equalizeRatios", () => {
|
|
it("resets nested splits to equal width, not just the newest one", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
const first = leaves(tab.root)[0].id;
|
|
splitLeaf(tab, first, "s2", "row", true); // A|B, 0.5/0.5
|
|
const second = leaves(tab.root)[1].id;
|
|
splitLeaf(tab, second, "s3", "row", true); // A(0.5) | (B|C, 0.5/0.5) -> B,C at 0.25 each
|
|
|
|
equalizeRatios(tab.root);
|
|
|
|
const root = tab.root as Extract<typeof tab.root, { kind: "split" }>;
|
|
expect(root.ratio).toBeCloseTo(1 / 3);
|
|
const inner = root.b as Extract<typeof root.b, { kind: "split" }>;
|
|
expect(inner.ratio).toBeCloseTo(1 / 2);
|
|
});
|
|
});
|
|
|
|
describe("removeLeaf", () => {
|
|
it("collapses the parent split into the surviving sibling", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
const first = leaves(tab.root)[0].id;
|
|
splitLeaf(tab, first, "s2", "row", true);
|
|
|
|
removeLeaf(tab, first);
|
|
|
|
const remaining = leaves(tab.root);
|
|
expect(remaining).toHaveLength(1);
|
|
expect(remaining[0].sessionId).toBe("s2");
|
|
expect(tab.root?.kind).toBe("leaf");
|
|
});
|
|
|
|
it("empties the tab when the last leaf goes", () => {
|
|
const tab = tabWithOneLeaf("s1");
|
|
removeLeaf(tab, leaves(tab.root)[0].id);
|
|
expect(tab.root).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("locateSession / openSessions", () => {
|
|
it("finds the tab and leaf showing a session", () => {
|
|
const layout = emptyLayout();
|
|
const tab = layout.tabs[0];
|
|
splitLeaf(tab, "", "s1", "row", true);
|
|
|
|
const hit = locateSession(layout, "s1");
|
|
expect(hit?.tab.id).toBe(tab.id);
|
|
expect(hit?.leaf.sessionId).toBe("s1");
|
|
expect(locateSession(layout, "nope")).toBeNull();
|
|
});
|
|
|
|
it("reports every open session once", () => {
|
|
const layout = emptyLayout();
|
|
const tab = layout.tabs[0];
|
|
splitLeaf(tab, "", "s1", "row", true);
|
|
const first = leaves(tab.root)[0].id;
|
|
splitLeaf(tab, first, "s2", "row", true);
|
|
|
|
expect(openSessions(layout)).toEqual(new Set(["s1", "s2"]));
|
|
});
|
|
});
|