Skip to content
89 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { HEARTBEAT_MS, type DesktopRunnerView, backendOf, diagnosisOf, reportDue, reportKey, reportOf } from "./desktop-runner.ts";
5
6function view(over: Partial<DesktopRunnerView> = {}): DesktopRunnerView {
7 return {
8 diagnosis: { code: "no_docker", tone: "problem", title: "Not running: Docker isn't running", cause: "Docker isn't running.", fix: "Start Docker Desktop.", actions: [{ id: "open_docker", label: "Open Docker" }] },
9 closed: { code: "off", tone: "off", title: "g1t is closed on build-box", cause: null, fix: "Open g1t on build-box.", actions: [] },
10 running: false,
11 version: "0.2.3",
12 backend: "docker",
13 workspace: "acme",
14 workspaces: [{ slug: "acme", name: "Acme" }],
15 enabled: true,
16 paused: false,
17 link: "https://g1t.sh/acme/-/runners",
18 machine: "build-box",
19 platform: "windows",
20 log: ["2026-10-12T08:00:00Z a line"],
21 ...over,
22 };
23}
24
25test("a report carries the app's words, without its buttons or log", () => {
26 const report = reportOf(view());
27 assert.deepEqual(report, {
28 workspace: "acme",
29 machine: "build-box",
30 backend: "docker",
31 version: "0.2.3",
32 diagnosis: { code: "no_docker", tone: "problem", title: "Not running: Docker isn't running", cause: "Docker isn't running.", fix: "Start Docker Desktop." },
33 closed: { code: "off", tone: "off", title: "g1t is closed on build-box", cause: null, fix: "Open g1t on build-box." },
34 });
35 assert.equal(reportOf(view({ workspace: null })), null);
36});
37
38test("a report goes when what the page shows changes, and as a heartbeat", () => {
39 const report = reportOf(view())!;
40 const at = 1_000_000;
41 assert.equal(reportDue(null, report, at), true);
42 const last = { key: reportKey(report), at };
43 assert.equal(reportDue(last, report, at + 1000), false);
44 assert.equal(reportDue(last, report, at + HEARTBEAT_MS), true);
45 const busy = reportOf(view({ diagnosis: { ...view().diagnosis, code: "busy", tone: "working", title: "Running Build (acme/web)" } }))!;
46 assert.equal(reportDue(last, busy, at + 1000), true);
47});
48
49test("a sandboxed desktop reports each kind of job, without its buttons", () => {
50 const linux = { id: "linux", label: "Linux jobs", tone: "ok" as const, title: "Waiting for jobs", cause: null, fix: null, actions: [] };
51 const windows = {
52 id: "windows",
53 label: "Windows jobs",
54 tone: "off" as const,
55 title: "Not available",
56 cause: "Windows Sandbox is off, or this edition of Windows has none: Home doesn't.",
57 fix: "Linux jobs still run.",
58 actions: [{ id: "windows_features", label: "Open Windows features" }],
59 };
60 const sandboxed = view({ backend: "sandboxed", diagnosis: { code: "idle", tone: "ok", title: "Waiting for jobs", cause: null, fix: null, actions: [], capabilities: [linux, windows] } });
61 const report = reportOf(sandboxed)!;
62 assert.deepEqual(report.diagnosis.capabilities, [
63 { id: "linux", label: "Linux jobs", tone: "ok", title: "Waiting for jobs", cause: null, fix: null },
64 { id: "windows", label: "Windows jobs", tone: "off", title: "Not available", cause: windows.cause, fix: "Linux jobs still run." },
65 ]);
66 // One kind of job changing is a report due.
67 const last = { key: reportKey(report), at: 0 };
68 const running = reportOf(view({ ...sandboxed, diagnosis: { ...sandboxed.diagnosis, capabilities: [linux, { ...windows, tone: "ok", title: "Waiting for jobs", cause: null, fix: null }] } }))!;
69 assert.equal(reportDue(last, running, 1000), true);
70 // What the server keeps: only kinds of job that read, and none for a desktop without any.
71 const kept = diagnosisOf({ ...report.diagnosis, capabilities: [...report.diagnosis.capabilities!, { id: "x", tone: "loud" }, "linux"] })!;
72 assert.equal(kept.capabilities?.length, 2);
73 assert.equal(diagnosisOf({ code: "idle", tone: "ok", title: "Waiting for jobs" })!.capabilities, undefined);
74 assert.equal(reportOf(view())!.diagnosis.capabilities, undefined);
75});
76
77test("only a diagnosis and a backend the app makes are kept", () => {
78 assert.deepEqual(diagnosisOf({ code: "idle", tone: "ok", title: "Waiting for jobs", cause: "Running sandboxed.", extra: 1 }), {
79 code: "idle",
80 tone: "ok",
81 title: "Waiting for jobs",
82 cause: "Running sandboxed.",
83 fix: null,
84 });
85 assert.equal(diagnosisOf({ code: "idle", tone: "loud", title: "x" }), null);
86 assert.equal(diagnosisOf("idle"), null);
87 assert.equal(backendOf("host"), "host");
88 assert.equal(backendOf("vm"), null);
89});