Opening an in-progress session that has a live Pi runtime now reconnects to its pending gate instead of the empty landing screen that read as "stopped". Cold/completed sessions keep the read-only documents panel with its explicit Resume, so a mere click never spawns a runtime. Backend GET /sessions now reports a per-session `active` flag (live runtime bound) to drive this. Also: - "New session" now closes any open session detail panel (left box). - The model-activity separator can be dragged to a full 50/50 split (was capped at 576px); central-min still guards narrow viewports. Test fixes uncovered along the way: - Node 25 ships an experimental global localStorage that shadows jsdom's and lacks clear(), failing every jsdom test at setup; install a spec-compliant in-memory Storage (feature-detected, inert on CI/LTS). - Fix 4 pre-existing session-mgmt tests that used an ambiguous getByText for a session shown in both nav and header; target the nav item by test id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
46 lines
2.1 KiB
TypeScript
46 lines
2.1 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import {
|
|
ACTIVITY_PANEL_DEFAULT_WIDTH,
|
|
ACTIVITY_PANEL_STORAGE_KEY,
|
|
clampActivityPanelWidth,
|
|
getActivityPanelBounds,
|
|
loadActivityPanelWidth,
|
|
resizeWidthFromKey,
|
|
saveActivityPanelWidth,
|
|
} from "./useActivityPanelResize";
|
|
|
|
describe("activity panel resize contract", () => {
|
|
test("lets the panel reach a 50/50 split while preserving 512px centrally when narrow", () => {
|
|
expect(getActivityPanelBounds(2000)).toEqual({ min: 288, max: 1000 }); // exactly 50%
|
|
expect(getActivityPanelBounds(1200)).toEqual({ min: 288, max: 600 }); // 50%, central 600 ≥ 512
|
|
expect(getActivityPanelBounds(1024)).toEqual({ min: 288, max: 512 }); // 50% == central-min
|
|
expect(getActivityPanelBounds(800)).toEqual({ min: 288, max: 288 }); // central-min binds before 50%
|
|
});
|
|
|
|
test("clamps finite values and falls back for invalid values", () => {
|
|
const bounds = { min: 288, max: 576 };
|
|
expect(clampActivityPanelWidth(200, bounds)).toBe(288);
|
|
expect(clampActivityPanelWidth(420, bounds)).toBe(420);
|
|
expect(clampActivityPanelWidth(900, bounds)).toBe(576);
|
|
expect(clampActivityPanelWidth(Number.NaN, bounds)).toBe(ACTIVITY_PANEL_DEFAULT_WIDTH);
|
|
});
|
|
|
|
test("maps keyboard controls to exact clamped increments", () => {
|
|
const bounds = { min: 288, max: 576 };
|
|
expect(resizeWidthFromKey(384, "ArrowLeft", false, bounds)).toBe(368);
|
|
expect(resizeWidthFromKey(384, "ArrowRight", true, bounds)).toBe(432);
|
|
expect(resizeWidthFromKey(384, "Home", false, bounds)).toBe(288);
|
|
expect(resizeWidthFromKey(384, "End", false, bounds)).toBe(576);
|
|
expect(resizeWidthFromKey(384, "Enter", false, bounds)).toBeNull();
|
|
});
|
|
|
|
test("loads, persists, and rejects corrupt browser values", () => {
|
|
localStorage.clear();
|
|
expect(loadActivityPanelWidth(localStorage)).toBe(ACTIVITY_PANEL_DEFAULT_WIDTH);
|
|
localStorage.setItem(ACTIVITY_PANEL_STORAGE_KEY, "corrupt");
|
|
expect(loadActivityPanelWidth(localStorage)).toBe(ACTIVITY_PANEL_DEFAULT_WIDTH);
|
|
saveActivityPanelWidth(448, localStorage);
|
|
expect(loadActivityPanelWidth(localStorage)).toBe(448);
|
|
});
|
|
});
|