1import { describe, expect, it } from "vite-plus/test";
2
3import type { TerminalSummary } from "@t3tools/contracts";
4import { DEFAULT_TERMINAL_ID, TerminalOpenInput } from "@t3tools/contracts";
5import * as Schema from "effect/Schema";
6
7import { getTerminalLabel, nextTerminalId, resolveTerminalSessionLabel } from "./terminalLabels.ts";
8
9const decodeTerminalOpen = Schema.decodeUnknownSync(TerminalOpenInput);
10
11describe("getTerminalLabel", () => {
12 it("uses the numeric suffix for term-* ids", () => {
13 expect(getTerminalLabel(DEFAULT_TERMINAL_ID)).toBe("Terminal 1");
14 expect(getTerminalLabel("term-2")).toBe("Terminal 2");
15 expect(getTerminalLabel("term-12")).toBe("Terminal 12");
16 expect(getTerminalLabel("terminal-3")).toBe("Terminal 3");
17 });
18
19 it("falls back to the raw id for unknown shapes", () => {
20 expect(getTerminalLabel("custom-session")).toBe("custom-session");
21 });
22
23 it("keeps a numbered label for terminals allocated without host metadata", () => {
24 expect(getTerminalLabel("term-2-783c91cc-a413-47c7-8312-c2a5a1f05e40")).toBe("Terminal 2");
25 });
26});
27
28describe("resolveTerminalSessionLabel", () => {
29 it("prefers a non-empty summary label", () => {
30 const summary = { label: " bun " } as Pick<TerminalSummary, "label">;
31 expect(resolveTerminalSessionLabel("term-1", summary)).toBe("bun");
32 });
33
34 it("falls back to getTerminalLabel when summary is missing or blank", () => {
35 expect(resolveTerminalSessionLabel(DEFAULT_TERMINAL_ID, { label: " " })).toBe("Terminal 1");
36 expect(resolveTerminalSessionLabel(DEFAULT_TERMINAL_ID, null)).toBe("Terminal 1");
37 expect(resolveTerminalSessionLabel("term-2", undefined)).toBe("Terminal 2");
38 });
39});
40
41describe("nextTerminalId", () => {
42 it("allocates term-1 when no terminals are listed yet", () => {
43 expect(nextTerminalId([])).toBe(DEFAULT_TERMINAL_ID);
44 });
45
46 it("allocates term-2 when only term-1 exists", () => {
47 expect(nextTerminalId([DEFAULT_TERMINAL_ID])).toBe("term-2");
48 });
49
50 it("skips over taken term-N slots", () => {
51 expect(nextTerminalId([DEFAULT_TERMINAL_ID, "term-2", "term-3"])).toBe("term-4");
52 expect(nextTerminalId([DEFAULT_TERMINAL_ID, "term-3"])).toBe("term-2");
53 expect(nextTerminalId(["term-2", "term-3"])).toBe("term-1");
54 });
55
56 it("ignores blank/whitespace-only ids", () => {
57 expect(nextTerminalId(["", " ", DEFAULT_TERMINAL_ID])).toBe("term-2");
58 expect(nextTerminalId(["", " "])).toBe("term-1");
59 });
60
61 it("avoids unseen sessions when metadata is unavailable and resumes normal numbering", () => {
62 const first = nextTerminalId([], "783c91cc-a413-47c7-8312-c2a5a1f05e40");
63 const second = nextTerminalId([first], "102315fc-ceef-45c4-b978-c4d4947d3c26");
64 expect(first).not.toBe(DEFAULT_TERMINAL_ID);
65 expect(second).not.toBe(first);
66 expect(getTerminalLabel(second)).toBe("Terminal 2");
67 expect(nextTerminalId([first, second])).toBe("term-3");
68 expect(
69 decodeTerminalOpen({
70 threadId: "thread",
71 terminalId: second,
72 cwd: "/workspace",
73 }),
74 ).toMatchObject({ terminalId: second });
75 });
76});