aboutsummaryrefslogtreecommitdiffstats
path: root/cli/test/cli.test.ts
blob: 464ade4364c872aab5baeead114faefe3eb8804b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { describe, expect, test } from "bun:test";
import { parseArgs, passthroughArgs } from "../src/index.ts";
import { agentStateOf } from "../src/commands/workspace.ts";
import { withoutSessionEnv } from "../src/core/sl0ppij.ts";

describe("parseArgs", () => {
  test("defaults to up", () => {
    expect(parseArgs([]).command).toBe("up");
    expect(parseArgs(["--root", "/x"]).command).toBe("up");
  });

  test("recognises the verbs", () => {
    for (const verb of ["up", "ls", "open", "close", "help"]) {
      expect(parseArgs([verb]).command).toBe(verb);
    }
  });

  test("keeps the project name as an argument", () => {
    const args = parseArgs(["open", "myproj", "--root", "/x"]);
    expect(args.command).toBe("open");
    expect(args.rest).toEqual(["myproj"]);
    expect(args.rootFlag).toBe("/x");
  });

  test("accepts both flag spellings", () => {
    expect(parseArgs(["--root=/x"]).rootFlag).toBe("/x");
    expect(parseArgs(["--depth=3"]).depth).toBe(3);
    expect(parseArgs(["--depth", "2"]).depth).toBe(2);
    expect(parseArgs(["-n"]).dryRun).toBe(true);
  });

  test("a bad depth falls back to 1 rather than NaN", () => {
    expect(parseArgs(["--depth", "banana"]).depth).toBe(1);
  });
});

// Falling open is only useful if what we hand over is something sl0ppij
// understands. Passing `up` through just yields "unrecognized subcommand" and
// still leaves the user without a terminal.
describe("passthroughArgs", () => {
  test("strips our verbs and flags", () => {
    expect(passthroughArgs(["up", "--root", "/x"])).toEqual([]);
    expect(passthroughArgs(["ls", "--depth=2"])).toEqual([]);
    expect(passthroughArgs(["open", "proj", "-n"])).toEqual(["proj"]);
  });

  test("keeps arguments sl0ppij would understand", () => {
    expect(passthroughArgs(["attach", "mysession"])).toEqual(["attach", "mysession"]);
    expect(passthroughArgs(["--root", "/x", "list-sessions"])).toEqual(["list-sessions"]);
  });

  test("only the leading verb is dropped", () => {
    // `sl0ppij action ... close` style words further along must survive
    expect(passthroughArgs(["action", "close-tab"])).toEqual(["action", "close-tab"]);
  });
});

describe("agentStateOf", () => {
  // A start_suspended pane reports is_held, not exited: the command is staged
  // but has never run. Conflating the two made `ls` claim twelve agents were
  // running when none were.
  test("held means suspended", () => {
    expect(agentStateOf({ is_held: true })).toBe("suspended");
  });
  test("exited means exited", () => {
    expect(agentStateOf({ exited: true })).toBe("exited");
  });
  test("neither means running", () => {
    expect(agentStateOf({})).toBe("running");
  });
  test("absent means none", () => {
    expect(agentStateOf(undefined)).toBe("none");
  });
});

describe("withoutSessionEnv", () => {
  // `attach --create-background` fails with "There is no active session!" when
  // the caller is inside a session, and sl0ppi is nearly always run from one.
  test("drops both spellings of the session markers", () => {
    const cleaned = withoutSessionEnv({
      ZELLIJ: "0",
      ZELLIJ_SESSION_NAME: "inventive-drum",
      SL0PPIJ: "0",
      SL0PPIJ_SESSION_NAME: "dev",
      SL0PPIJ_PANE_ID: "3",
      PATH: "/usr/bin",
    });
    expect(cleaned.ZELLIJ).toBeUndefined();
    expect(cleaned.ZELLIJ_SESSION_NAME).toBeUndefined();
    expect(cleaned.SL0PPIJ).toBeUndefined();
    expect(cleaned.SL0PPIJ_SESSION_NAME).toBeUndefined();
    expect(cleaned.SL0PPIJ_PANE_ID).toBeUndefined();
    expect(cleaned.PATH).toBe("/usr/bin");
  });
});