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

DesktopEarlyElectronStartup.test.ts

199 lines6.5 KB

1// @effect-diagnostics nodeBuiltinImport:off - tests use POSIX path joining to match the Linux startup boundary.
2import * as NodePath from "node:path";
3import { assert, describe, it } from "@effect/vitest";
4​
5import {
6 restoreEarlyLinuxDeviceScaleFactor,
7 resolveEarlyLinuxPasswordStorePreference,
8 resolveLinuxDisableFeaturesSwitch,
9} from "./DesktopEarlyElectronStartup.ts";
10​
11describe("DesktopEarlyElectronStartup", () => {
12 const joinPath = NodePath.posix.join;
13​
14 it("reads the persisted linux password-store preference before Electron is ready", () => {
15 const preference = resolveEarlyLinuxPasswordStorePreference({
16 env: { T3CODE_HOME: "/home/user/.t3-test" },
17 homeDirectory: "/home/user",
18 joinPath,
19 readFileString: (path) => {
20 assert.equal(path, "/home/user/.t3-test/userdata/desktop-settings.json");
21 return JSON.stringify({ linuxPasswordStore: "kwallet6" });
22 },
23 });
24​
25 assert.equal(preference, "kwallet6");
26 });
27​
28 it("accepts JSONC in the early desktop settings file", () => {
29 const preference = resolveEarlyLinuxPasswordStorePreference({
30 env: { T3CODE_HOME: "/home/user/.t3-test" },
31 homeDirectory: "/home/user",
32 joinPath,
33 readFileString: () => `{
34 // manually edited setting
35 "linuxPasswordStore": "gnome-libsecret",
36 }`,
37 });
38​
39 assert.equal(preference, "gnome-libsecret");
40 });
41​
42 it("falls back to auto when the early settings document is missing or invalid", () => {
43 const preference = resolveEarlyLinuxPasswordStorePreference({
44 env: {},
45 homeDirectory: "/home/user",
46 joinPath,
47 readFileString: () => {
48 throw new Error("missing");
49 },
50 });
51​
52 assert.equal(preference, "auto");
53 });
54​
55 describe("resolveLinuxDisableFeaturesSwitch", () => {
56 const hyprland = { XDG_CURRENT_DESKTOP: "Hyprland", XDG_SESSION_TYPE: "wayland" };
57 const releaseCommits: Record<string, string> = {
58 "0.48.0": "5ee35f914f921e5696030698e74fb5566a804768",
59 "0.48.1": "29e2e59fdbab8ed2cc23a20e3c6043d5decb5cdc",
60 "0.50.1": "4e242d086e20b32951fdc0ebcbfb4d41b5be8dcc",
61 };
62 const hyprctlVersion =
63 (version: string, overrides: Record<string, unknown> = {}) =>
64 () =>
65 JSON.stringify({
66 commit: releaseCommits[version] ?? "0123456789abcdef0123456789abcdef01234567",
67 version,
68 dirty: false,
69 tag: `v${version}`,
70 flags: [],
71 ...overrides,
72 });
73 const brokenHyprland = {
74 env: hyprland,
75 ozonePlatform: "wayland",
76 enableFeatures: null,
77 disableFeatures: null,
78 readHyprctlVersionJson: hyprctlVersion("0.48.1"),
79 };
80​
81 it.each(["0.48.0", "0.50.1"])("disables the color manager on Hyprland %s", (version) => {
82 assert.equal(
83 resolveLinuxDisableFeaturesSwitch({
84 ...brokenHyprland,
85 readHyprctlVersionJson: hyprctlVersion(version),
86 }),
87 "WaylandWpColorManagerV1",
88 );
89 });
90​
91 it.each([
92 { label: "case-insensitive desktop tokens", env: { XDG_CURRENT_DESKTOP: "foo:HYPRLAND" } },
93 {
94 label: "XDG_SESSION_DESKTOP when XDG_CURRENT_DESKTOP is unset",
95 env: { XDG_SESSION_DESKTOP: "hyprland" },
96 },
97 ])("detects Hyprland via $label", ({ env }) => {
98 assert.equal(
99 resolveLinuxDisableFeaturesSwitch({ ...brokenHyprland, env }),
100 "WaylandWpColorManagerV1",
101 );
102 });
103​
104 it.each([
105 {
106 label: "a stale Hyprland signature in KDE",
107 env: { XDG_CURRENT_DESKTOP: "KDE", HYPRLAND_INSTANCE_SIGNATURE: "abc_123" },
108 },
109 {
110 label: "resolved X11 in a Wayland session",
111 ozonePlatform: "x11",
112 env: { ...hyprland, WAYLAND_DISPLAY: "wayland-1" },
113 },
114 { label: "a missing platform", ozonePlatform: null },
115 { label: "an unrelated platform", ozonePlatform: "headless" },
116 { label: "already disabled features", disableFeatures: "Vulkan, WaylandWpColorManagerV1" },
117 { label: "an explicitly enabled feature", enableFeatures: "Vulkan,WaylandWpColorManagerV1" },
118 {
119 label: "a feature enabled with trial parameters",
120 enableFeatures: "*WaylandWpColorManagerV1<Study.Group:mode/strict",
121 },
122 ])("skips the Hyprland probe for $label", (overrides) => {
123 assert.isNull(
124 resolveLinuxDisableFeaturesSwitch({
125 ...brokenHyprland,
126 ...overrides,
127 readHyprctlVersionJson: () => assert.fail("hyprctl should not run"),
128 }),
129 );
130 });
131 });
132});
133​
134describe("Linux device scale persistence failures", () => {
135 const input = {
136 env: { T3CODE_HOME: "/isolated" },
137 homeDirectory: "/home/user",
138 joinPath: NodePath.posix.join,
139 };
140​
141 it.each(["0", "Infinity", "garbage"])("ignores invalid persisted scale %j", (value) => {
142 const applied: Array<[string, string]> = [];
143 const writes: Array<string> = [];
144 restoreEarlyLinuxDeviceScaleFactor({
145 ...input,
146 commandLine: {
147 hasSwitch: () => false,
148 getSwitchValue: () => "",
149 appendSwitch: (name, scale) => applied.push([name, scale]),
150 },
151 readFileString: () => value,
152 writeFileString: (_path, contents) => writes.push(contents),
153 });
154 assert.deepEqual(applied, []);
155 assert.deepEqual(writes, []);
156 });
157​
158 it("keeps startup available with default scaling when saved state cannot be read", () => {
159 const applied: Array<[string, string]> = [];
160 restoreEarlyLinuxDeviceScaleFactor({
161 ...input,
162 commandLine: {
163 hasSwitch: () => false,
164 getSwitchValue: () => "",
165 appendSwitch: (name, value) => applied.push([name, value]),
166 },
167 readFileString: () => {
168 throw new Error("ENOENT");
169 },
170 writeFileString: () => {},
171 });
172 assert.deepEqual(applied, []);
173 });
174​
175 it("keeps an explicit scale when saving it fails, without falling back to saved state", () => {
176 const applied: Array<[string, string]> = [];
177 const reads: Array<string> = [];
178 const writes: Array<string> = [];
179 restoreEarlyLinuxDeviceScaleFactor({
180 ...input,
181 commandLine: {
182 hasSwitch: () => true,
183 getSwitchValue: () => "1",
184 appendSwitch: (name, value) => applied.push([name, value]),
185 },
186 readFileString: (path) => {
187 reads.push(path);
188 return "1.75";
189 },
190 writeFileString: (_path, value) => {
191 writes.push(value);
192 throw new Error("EACCES");
193 },
194 });
195 assert.deepEqual(writes, ["1"]);
196 assert.deepEqual(reads, []);
197 assert.deepEqual(applied, []);
198 });
199});