| 1 | import { describe, expect, it } from "vite-plus/test"; |
| 2 | |
| 3 | import type { TerminalSummary } from "@t3tools/contracts"; |
| 4 | import { DEFAULT_TERMINAL_ID, TerminalOpenInput } from "@t3tools/contracts"; |
| 5 | import * as Schema from "effect/Schema"; |
| 6 | |
| 7 | import { getTerminalLabel, nextTerminalId, resolveTerminalSessionLabel } from "./terminalLabels.ts"; |
| 8 | |
| 9 | const decodeTerminalOpen = Schema.decodeUnknownSync(TerminalOpenInput); |
| 10 | |
| 11 | describe("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 | |
| 28 | describe("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 | |
| 41 | describe("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 | }); |