import { ThreadId } from "@t3tools/contracts";import { beforeEach, describe, expect, it } from "vitest"; import { selectThreadTerminalState, useTerminalStateStore } from "./terminalStateStore"; const THREAD_ID = ThreadId.makeUnsafe("thread-1"); describe("terminalStateStore actions", () => { beforeEach(() => { if (typeof localStorage !== "undefined") { localStorage.clear(); } useTerminalStateStore.setState({ terminalStateByThreadId: {} }); }); it("returns a closed default terminal state for unknown threads", () => { const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState).toEqual({ terminalOpen: false, terminalHeight: 280, terminalIds: ["default"], runningTerminalIds: [], activeTerminalId: "default", terminalGroups: [{ id: "group-default", terminalIds: ["default"] }], activeTerminalGroupId: "group-default", }); }); it("opens and splits terminals into the active group", () => { const store = useTerminalStateStore.getState(); store.setTerminalOpen(THREAD_ID, true); store.splitTerminal(THREAD_ID, "terminal-2"); const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState.terminalOpen).toBe(true); expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]); expect(terminalState.activeTerminalId).toBe("terminal-2"); expect(terminalState.terminalGroups).toEqual([ { id: "group-default", terminalIds: ["default", "terminal-2"] }, ]); }); it("caps splits at four terminals per group", () => { const store = useTerminalStateStore.getState(); store.splitTerminal(THREAD_ID, "terminal-2"); store.splitTerminal(THREAD_ID, "terminal-3"); store.splitTerminal(THREAD_ID, "terminal-4"); store.splitTerminal(THREAD_ID, "terminal-5"); const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState.terminalIds).toEqual([ "default", "terminal-2", "terminal-3", "terminal-4", ]); expect(terminalState.terminalGroups).toEqual([ { id: "group-default", terminalIds: ["default", "terminal-2", "terminal-3", "terminal-4"] }, ]); }); it("creates new terminals in a separate group", () => { useTerminalStateStore.getState().newTerminal(THREAD_ID, "terminal-2"); const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]); expect(terminalState.activeTerminalId).toBe("terminal-2"); expect(terminalState.activeTerminalGroupId).toBe("group-terminal-2"); expect(terminalState.terminalGroups).toEqual([ { id: "group-default", terminalIds: ["default"] }, { id: "group-terminal-2", terminalIds: ["terminal-2"] }, ]); }); it("allows unlimited groups while keeping each group capped at four terminals", () => { const store = useTerminalStateStore.getState(); store.splitTerminal(THREAD_ID, "terminal-2"); store.splitTerminal(THREAD_ID, "terminal-3"); store.splitTerminal(THREAD_ID, "terminal-4"); store.newTerminal(THREAD_ID, "terminal-5"); store.newTerminal(THREAD_ID, "terminal-6"); const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState.terminalIds).toEqual([ "default", "terminal-2", "terminal-3", "terminal-4", "terminal-5", "terminal-6", ]); expect(terminalState.terminalGroups).toEqual([ { id: "group-default", terminalIds: ["default", "terminal-2", "terminal-3", "terminal-4"] }, { id: "group-terminal-5", terminalIds: ["terminal-5"] }, { id: "group-terminal-6", terminalIds: ["terminal-6"] }, ]); }); it("tracks and clears terminal subprocess activity", () => { const store = useTerminalStateStore.getState(); store.splitTerminal(THREAD_ID, "terminal-2"); store.setTerminalActivity(THREAD_ID, "terminal-2", true); expect( selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID) .runningTerminalIds, ).toEqual(["terminal-2"]); store.setTerminalActivity(THREAD_ID, "terminal-2", false); expect( selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID) .runningTerminalIds, ).toEqual([]); }); it("resets to default and clears persisted entry when closing the last terminal", () => { const store = useTerminalStateStore.getState(); store.closeTerminal(THREAD_ID, "default"); expect(useTerminalStateStore.getState().terminalStateByThreadId[THREAD_ID]).toBeUndefined(); expect( selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID) .terminalIds, ).toEqual(["default"]); }); it("keeps a valid active terminal after closing an active split terminal", () => { const store = useTerminalStateStore.getState(); store.splitTerminal(THREAD_ID, "terminal-2"); store.splitTerminal(THREAD_ID, "terminal-3"); store.closeTerminal(THREAD_ID, "terminal-3"); const terminalState = selectThreadTerminalState( useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID, ); expect(terminalState.activeTerminalId).toBe("terminal-2"); expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]); expect(terminalState.terminalGroups).toEqual([ { id: "group-default", terminalIds: ["default", "terminal-2"] }, ]); });});
import { ThreadId } from "@t3tools/contracts";
import { beforeEach, describe, expect, it } from "vitest";
import { selectThreadTerminalState, useTerminalStateStore } from "./terminalStateStore";
const THREAD_ID = ThreadId.makeUnsafe("thread-1");
describe("terminalStateStore actions", () => {
beforeEach(() => {
if (typeof localStorage !== "undefined") {
localStorage.clear();
}
useTerminalStateStore.setState({ terminalStateByThreadId: {} });
});
it("returns a closed default terminal state for unknown threads", () => {
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState).toEqual({
terminalOpen: false,
terminalHeight: 280,
terminalIds: ["default"],
runningTerminalIds: [],
activeTerminalId: "default",
terminalGroups: [{ id: "group-default", terminalIds: ["default"] }],
activeTerminalGroupId: "group-default",
});
});
it("opens and splits terminals into the active group", () => {
const store = useTerminalStateStore.getState();
store.setTerminalOpen(THREAD_ID, true);
store.splitTerminal(THREAD_ID, "terminal-2");
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState.terminalOpen).toBe(true);
expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]);
expect(terminalState.activeTerminalId).toBe("terminal-2");
expect(terminalState.terminalGroups).toEqual([
{ id: "group-default", terminalIds: ["default", "terminal-2"] },
]);
});
it("caps splits at four terminals per group", () => {
const store = useTerminalStateStore.getState();
store.splitTerminal(THREAD_ID, "terminal-2");
store.splitTerminal(THREAD_ID, "terminal-3");
store.splitTerminal(THREAD_ID, "terminal-4");
store.splitTerminal(THREAD_ID, "terminal-5");
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState.terminalIds).toEqual([
"default",
"terminal-2",
"terminal-3",
"terminal-4",
]);
expect(terminalState.terminalGroups).toEqual([
{ id: "group-default", terminalIds: ["default", "terminal-2", "terminal-3", "terminal-4"] },
]);
});
it("creates new terminals in a separate group", () => {
useTerminalStateStore.getState().newTerminal(THREAD_ID, "terminal-2");
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]);
expect(terminalState.activeTerminalId).toBe("terminal-2");
expect(terminalState.activeTerminalGroupId).toBe("group-terminal-2");
expect(terminalState.terminalGroups).toEqual([
{ id: "group-default", terminalIds: ["default"] },
{ id: "group-terminal-2", terminalIds: ["terminal-2"] },
]);
});
it("allows unlimited groups while keeping each group capped at four terminals", () => {
const store = useTerminalStateStore.getState();
store.splitTerminal(THREAD_ID, "terminal-2");
store.splitTerminal(THREAD_ID, "terminal-3");
store.splitTerminal(THREAD_ID, "terminal-4");
store.newTerminal(THREAD_ID, "terminal-5");
store.newTerminal(THREAD_ID, "terminal-6");
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState.terminalIds).toEqual([
"default",
"terminal-2",
"terminal-3",
"terminal-4",
"terminal-5",
"terminal-6",
]);
expect(terminalState.terminalGroups).toEqual([
{ id: "group-default", terminalIds: ["default", "terminal-2", "terminal-3", "terminal-4"] },
{ id: "group-terminal-5", terminalIds: ["terminal-5"] },
{ id: "group-terminal-6", terminalIds: ["terminal-6"] },
]);
});
it("tracks and clears terminal subprocess activity", () => {
const store = useTerminalStateStore.getState();
store.splitTerminal(THREAD_ID, "terminal-2");
store.setTerminalActivity(THREAD_ID, "terminal-2", true);
expect(
selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID)
.runningTerminalIds,
).toEqual(["terminal-2"]);
store.setTerminalActivity(THREAD_ID, "terminal-2", false);
expect(
selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID)
.runningTerminalIds,
).toEqual([]);
});
it("resets to default and clears persisted entry when closing the last terminal", () => {
const store = useTerminalStateStore.getState();
store.closeTerminal(THREAD_ID, "default");
expect(useTerminalStateStore.getState().terminalStateByThreadId[THREAD_ID]).toBeUndefined();
expect(
selectThreadTerminalState(useTerminalStateStore.getState().terminalStateByThreadId, THREAD_ID)
.terminalIds,
).toEqual(["default"]);
});
it("keeps a valid active terminal after closing an active split terminal", () => {
const store = useTerminalStateStore.getState();
store.splitTerminal(THREAD_ID, "terminal-2");
store.splitTerminal(THREAD_ID, "terminal-3");
store.closeTerminal(THREAD_ID, "terminal-3");
const terminalState = selectThreadTerminalState(
useTerminalStateStore.getState().terminalStateByThreadId,
THREAD_ID,
);
expect(terminalState.activeTerminalId).toBe("terminal-2");
expect(terminalState.terminalIds).toEqual(["default", "terminal-2"]);
expect(terminalState.terminalGroups).toEqual([
{ id: "group-default", terminalIds: ["default", "terminal-2"] },
]);
});
});