Skip to content
Source
Sign inSign up
Open History to see the last commit

SnapShotSetupDialog.logic.test.ts

242 lines9.0 KB

1import { DEFAULT_CLIENT_SETTINGS, type DesktopSnapShotState } from "@t3tools/contracts";
2import { expect, it } from "vite-plus/test";
3import {
4 captureSetupAccessReady,
5 captureSetupBackend,
6 captureSetupCheckMessage,
7 captureSetupDesktopName,
8 captureSetupInitialStep,
9 captureSetupMacPermissionsReady,
10 captureSetupShortcutReady,
11 captureSetupShouldDisableOnClose,
12} from "./SnapShotSetupDialog.logic";
13​
14const gnome: DesktopSnapShotState = {
15 mode: "portal",
16 linuxBackend: "gnome-extension",
17 shortcut: DEFAULT_CLIENT_SETTINGS.snapShotShortcut,
18 shortcutRegistered: true,
19 shortcutMessage: "Requested",
20 shortcutVerified: false,
21 message: null,
22 gnomeExtension: { status: "enabled", message: "Running" },
23};
24​
25it("derives Hyprland setup from its own helper and registered action, not old GNOME approval", () => {
26 const state: DesktopSnapShotState = {
27 ...gnome,
28 linuxBackend: "hyprland",
29 linuxDesktop: "hyprland",
30 shortcutRegistered: false,
31 hyprlandHelper: { status: "not-installed", message: "Install" },
32 };
33 expect(captureSetupBackend(state)).toBe("hyprland");
34 expect(captureSetupDesktopName(state)).toBe("Hyprland");
35 expect(captureSetupAccessReady(state)).toBe(false);
36 expect(captureSetupInitialStep(state)).toBe("access");
37 const installed = { ...state, hyprlandHelper: { status: "ready" as const, message: "Ready" } };
38 expect(captureSetupInitialStep(installed)).toBe("shortcut");
39 expect(captureSetupShortcutReady(installed, false)).toBe(false);
40 expect(captureSetupShortcutReady({ ...installed, shortcutPending: true }, false)).toBe(false);
41 expect(captureSetupShortcutReady({ ...installed, shortcutActionRegistered: true }, false)).toBe(
42 true,
43 );
44 expect(captureSetupAccessReady({ ...installed, message: "Check access" })).toBe(false);
45});
46​
47it.each(["disabled", "error"] as const)(
48 "keeps %s GNOME setup on the access step, even with a previously verified shortcut",
49 (status) => {
50 const state = {
51 ...gnome,
52 shortcutVerified: true,
53 gnomeExtension: { status, message: "Needs setup" },
54 };
55 expect(captureSetupInitialStep(state)).toBe("access");
56 expect(captureSetupInitialStep(state, "shortcut")).toBe("access");
57 expect(captureSetupAccessReady(state)).toBe(false);
58 expect(captureSetupShortcutReady(state, false)).toBe(false);
59 },
60);
61​
62it("does not declare access ready before the enabled extension's capture endpoint is available", () => {
63 expect(captureSetupAccessReady({ ...gnome, linuxBackend: "picker" })).toBe(false);
64 expect(captureSetupAccessReady(gnome)).toBe(true);
65});
66​
67it("resumes after login from real extension state without an onboarding-completed flag", () => {
68 expect(
69 captureSetupInitialStep({
70 ...gnome,
71 gnomeExtension: { status: "disabled", message: "Enable it" },
72 }),
73 ).toBe("access");
74 expect(captureSetupInitialStep({ ...gnome, shortcutRegistered: false })).toBe("shortcut");
75 expect(captureSetupInitialStep(gnome)).toBe("shortcut");
76});
77​
78it("does not skip native permission setup when capture has not been enabled", () => {
79 expect(
80 captureSetupInitialStep({
81 ...gnome,
82 mode: "direct",
83 linuxBackend: undefined,
84 gnomeExtension: undefined,
85 shortcutRegistered: false,
86 }),
87 ).toBe("access");
88});
89​
90it("offers manual capture on an unsupported GNOME version instead of trapping setup", () => {
91 const state = {
92 ...gnome,
93 linuxBackend: "picker" as const,
94 gnomeExtension: { status: "unsupported" as const, message: "New GNOME version" },
95 };
96 expect(captureSetupBackend(state)).toBe("picker");
97 expect(captureSetupAccessReady(state)).toBe(true);
98 expect(captureSetupInitialStep(state)).toBe("access");
99 expect(captureSetupCheckMessage(state)).toContain("choose a window each time");
100});
101​
102it.each(["not-installed", "error"] as const)(
103 "requires KDE helper access for %s even with a saved shortcut",
104 (status) => {
105 const state = {
106 ...gnome,
107 linuxBackend: "kde" as const,
108 gnomeExtension: undefined,
109 kdeHelper: { status, message: "Needs setup" },
110 shortcutVerified: true,
111 };
112 expect(captureSetupBackend(state)).toBe("kde");
113 expect(captureSetupAccessReady(state)).toBe(false);
114 expect(captureSetupInitialStep(state, "shortcut")).toBe("access");
115 expect(captureSetupShortcutReady(state, false)).toBe(false);
116 },
117);
118​
119it("resumes KDE setup after the helper passes its real permission check", () => {
120 const state = {
121 ...gnome,
122 linuxBackend: "kde" as const,
123 gnomeExtension: undefined,
124 kdeHelper: { status: "ready" as const, message: "Ready" },
125 };
126 expect(captureSetupAccessReady(state)).toBe(true);
127 expect(captureSetupInitialStep(state)).toBe("shortcut");
128 expect(captureSetupInitialStep({ ...state, shortcutRegistered: false })).toBe("shortcut");
129});
130​
131it("does not report a successful check when capture support could not be read", () => {
132 expect(captureSetupCheckMessage({ ...gnome, message: "Desktop disconnected" })).toContain(
133 "Still unable to check access",
134 );
135 expect(
136 captureSetupCheckMessage({
137 ...gnome,
138 gnomeExtension: { status: "error", message: "Could not read extension state" },
139 }),
140 ).toContain("Still unable to check access");
141});
142​
143it("uses a capable portal without requiring the optional GNOME extension", () => {
144 const state = {
145 ...gnome,
146 linuxBackend: "screenshot-portal" as const,
147 gnomeExtension: { status: "not-installed" as const, message: "Not installed" },
148 };
149 expect(captureSetupBackend(state)).toBe("portal");
150 expect(captureSetupAccessReady(state)).toBe(true);
151 expect(captureSetupInitialStep(state)).toBe("shortcut");
152 expect(
153 captureSetupCheckMessage({
154 ...state,
155 gnomeExtension: { status: "error", message: "Optional extension failed" },
156 }),
157 ).toBe("Ready. Continue to choose your shortcut.");
158});
159​
160it("lets Niri setup finish with configuration instructions without claiming the binding was verified", () => {
161 const niri = {
162 ...gnome,
163 linuxBackend: "niri" as const,
164 gnomeExtension: undefined,
165 shortcutRegistered: false,
166 };
167 expect(captureSetupBackend(niri)).toBe("niri");
168 expect(captureSetupAccessReady(niri)).toBe(true);
169 expect(captureSetupShortcutReady(niri, false)).toBe(false);
170 const withEndpoint = { ...niri, shortcutBinding: "Ctrl+Shift+2 { spawn ...; }" };
171 expect(captureSetupInitialStep(withEndpoint)).toBe("shortcut");
172 expect(captureSetupShortcutReady(withEndpoint, false)).toBe(true);
173 expect(withEndpoint.shortcutRegistered).toBe(false);
174 expect(withEndpoint.shortcutVerified).toBe(false);
175});
176​
177it("requires saving a changed chord before finishing setup", () => {
178 expect(captureSetupShortcutReady(gnome, true)).toBe(false);
179 expect(captureSetupShortcutReady(gnome, false)).toBe(true);
180 expect(captureSetupShortcutReady({ ...gnome, shortcutRegistered: false }, false)).toBe(false);
181});
182​
183it("allows leaving setup while the desktop prompt is pending but never after an explicit denial", () => {
184 const pending = { ...gnome, shortcutRegistered: false, shortcutPending: true };
185 expect(captureSetupShortcutReady(pending, false)).toBe(true);
186 expect(captureSetupShortcutReady(pending, true)).toBe(false);
187 expect(captureSetupShortcutReady({ ...pending, shortcutPending: false }, false)).toBe(false);
188});
189​
190it("blocks finishing if desktop access is lost during the wizard", () => {
191 expect(
192 captureSetupShortcutReady(
193 {
194 ...gnome,
195 shortcutVerified: true,
196 message: "Desktop disconnected",
197 },
198 false,
199 ),
200 ).toBe(false);
201 expect(captureSetupAccessReady({ ...gnome, mode: "unavailable" })).toBe(false);
202});
203​
204it.each([
205 [false, false, true],
206 [true, false, false],
207] as const)(
208 "closing setup (previously enabled=%s, completed=%s) disables only an unfinished first opt-in",
209 (wasEnabled, completed, disable) => {
210 expect(captureSetupShouldDisableOnClose(wasEnabled, completed)).toBe(disable);
211 },
212);
213​
214it("gates Continue on macOS permissions, requiring accessibility only when app text is on", () => {
215 const mac: DesktopSnapShotState = {
216 ...gnome,
217 mode: "direct",
218 linuxBackend: undefined,
219 gnomeExtension: undefined,
220 macPermissions: { screenRecording: true, accessibility: false },
221 };
222 expect(captureSetupMacPermissionsReady(mac, true)).toBe(false);
223 expect(captureSetupMacPermissionsReady(mac, false)).toBe(true);
224 expect(
225 captureSetupMacPermissionsReady(
226 { ...mac, macPermissions: { screenRecording: false, accessibility: true } },
227 false,
228 ),
229 ).toBe(false);
230 expect(captureSetupMacPermissionsReady({ ...mac, macPermissions: undefined }, true)).toBe(true);
231});
232​
233it.each(["kde", "hyprland"] as const)("ignores errors from inactive helpers on %s", (backend) => {
234 const state: DesktopSnapShotState = {
235 ...gnome,
236 linuxBackend: backend,
237 kdeHelper: { status: backend === "kde" ? "ready" : "error", message: "KDE" },
238 hyprlandHelper: { status: backend === "hyprland" ? "ready" : "error", message: "Hyprland" },
239 };
240 expect(captureSetupAccessReady(state)).toBe(true);
241 expect(captureSetupCheckMessage(state)).toBe("Ready. Continue to choose your shortcut.");
242});