Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
96 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { type OnboardingFacts, STEP_ORDER, finished, firstOpenStep, opensByItself, progressOf, setupPath, stepsFrom, withSkipped } from "./onboarding.ts";
5
6const nothing: OnboardingFacts = {
7 providers: { total: 0, working: 0 },
8 askReady: false,
9 askWith: null,
10 projects: 0,
11 github: { configured: true, connected: false },
12 cli: false,
13 harnessApp: false,
14 people: { others: 0, pending: 0 },
15 invitesNeedPlan: false,
16 runners: 0,
17};
18
19const everything: OnboardingFacts = {
20 providers: { total: 1, working: 1 },
21 askReady: true,
22 askWith: "Anthropic · Auto",
23 projects: 3,
24 github: { configured: true, connected: true },
25 cli: true,
26 harnessApp: true,
27 people: { others: 2, pending: 0 },
28 invitesNeedPlan: false,
29 runners: 1,
30};
31
32const fresh = { dismissed_at: null, skipped: [], updated_at: null };
33
34test("a new workspace has every step to do, in the guide's order", () => {
35 const steps = stepsFrom(nothing, fresh);
36 assert.deepEqual(steps.map((step) => step.key), STEP_ORDER);
37 assert.ok(steps.every((step) => !step.done && !step.skipped));
38 assert.equal(firstOpenStep(steps), "ai");
39 assert.deepEqual(progressOf(steps), { settled: 0, total: 6, percent: 0 });
40 assert.equal(finished(steps), false);
41});
42
43test("a step is done from the workspace's state, not from clicks", () => {
44 const steps = stepsFrom(everything, fresh);
45 assert.ok(steps.every((step) => step.done));
46 assert.equal(finished(steps), true);
47 assert.equal(steps.find((step) => step.key === "ask")?.summary, "Anthropic · Auto");
48 assert.equal(steps.find((step) => step.key === "code")?.summary, "3 projects");
49});
50
51test("a provider whose check failed is not a working one", () => {
52 const steps = stepsFrom({ ...nothing, providers: { total: 1, working: 0 } }, fresh);
53 const ai = steps.find((step) => step.key === "ai")!;
54 assert.equal(ai.done, false);
55 assert.equal(ai.summary, "Added, but its check failed");
56 // A service that did not answer leaves the step to do.
57 assert.equal(stepsFrom({ ...nothing, providers: null }, fresh)[0]!.done, false);
58});
59
60test("code is brought by a project or a connected GitHub; people by a member or an invitation", () => {
61 const github = stepsFrom({ ...nothing, github: { configured: true, connected: true } }, fresh);
62 assert.equal(github.find((step) => step.key === "code")?.done, true);
63 const invited = stepsFrom({ ...nothing, people: { others: 0, pending: 1 } }, fresh);
64 assert.equal(invited.find((step) => step.key === "people")?.summary, "1 invitation sent");
65 const free = stepsFrom({ ...nothing, invitesNeedPlan: true }, fresh);
66 assert.equal(free.find((step) => step.key === "people")?.summary, "Invites come with the plan");
67});
68
69test("either the CLI or the plugin signed in connects the harness", () => {
70 assert.equal(stepsFrom({ ...nothing, cli: true }, fresh).find((step) => step.key === "harness")?.done, true);
71 assert.equal(stepsFrom({ ...nothing, harnessApp: true }, fresh).find((step) => step.key === "harness")?.summary, "Plugin signed in");
72});
73
74test("skipped steps count as settled, but the AI provider cannot be skipped and a done step is not skipped", () => {
75 const steps = stepsFrom({ ...nothing, runners: 1 }, { ...fresh, skipped: ["ai", "people", "runner"] });
76 assert.equal(steps.find((step) => step.key === "ai")?.skipped, false);
77 assert.equal(steps.find((step) => step.key === "people")?.skipped, true);
78 assert.equal(steps.find((step) => step.key === "runner")?.skipped, false);
79 assert.equal(progressOf(steps).settled, 2);
80 assert.equal(firstOpenStep(steps), "ai");
81});
82
83test("skipping keeps the guide's order and takes a skip back", () => {
84 assert.deepEqual(withSkipped(["runner"], "people", true), ["people", "runner"]);
85 assert.deepEqual(withSkipped(["people", "runner"], "people", false), ["runner"]);
86 assert.deepEqual(withSkipped([], "ask", true), ["ask"]);
87});
88
89test("it opens by itself until dismissed, and whenever it is asked for", () => {
90 assert.equal(opensByItself({ state: fresh }, false), true);
91 const dismissed = { state: { ...fresh, dismissed_at: "2026-10-14T21:05:00.000Z" } };
92 assert.equal(opensByItself(dismissed, false), false);
93 assert.equal(opensByItself(dismissed, true), true);
94 assert.equal(opensByItself(null, true), false);
95 assert.equal(setupPath("flagon-io"), "/flagon-io/-/home?setup=1");
96});