electron/cua-hyprland.test.mjs
Rama main · réplica de lectura del repositorio original.
import { describe, expect, it, vi } from "vitest";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const {
HYPRCTL,
PACMAN,
PLUGIN_REQUIRED_MESSAGE,
isHyprlandSession,
parseCuaPluginStatus,
probeCuaHyprlandPlugin,
runBounded,
systemDriverPackageVersion,
} = require("./cua-hyprland.cjs");
const HYPRLAND = {
XDG_SESSION_TYPE: "wayland",
WAYLAND_DISPLAY: "wayland-1",
XDG_CURRENT_DESKTOP: "Hyprland",
HYPRLAND_INSTANCE_SIGNATURE: "6f2a0c1e_1762560000_123456789",
};
/** `hyprctl -j cua:status` from an input build with input enabled (libs/cua-driver/hyprland-plugin/src/plugin.cpp). */
function activeStatus(overrides = {}) {
return {
name: "cua-hyprland-plugin",
plugin_version: "0.41.3",
state: "input_v3_candidate",
protocol: { major: 1, minor: 0, max_frame_bytes: 65536 },
compositor_epoch: 1,
abi: { compiled_hash: "abc", runtime_hash: "abc", match: true },
configured: true,
transport: { ready: true, socket: "/run/user/1000/hypr/x/.cua.sock", mode: "0600", peer_policy: "same_uid", last_error: "" },
capabilities: { supported: ["discovery"], enabled: ["discovery"], mutation: "trusted_local_per_action" },
input: { protocol: 3, test_only: false, transport_ready: true, lanes: [] },
...overrides,
};
}
describe("isHyprlandSession", () => {
it("needs Hyprland's instance signature and a desktop named Hyprland", () => {
expect(isHyprlandSession(HYPRLAND)).toBe(true);
expect(isHyprlandSession({ ...HYPRLAND, XDG_CURRENT_DESKTOP: "", XDG_SESSION_DESKTOP: "hyprland" })).toBe(true);
expect(isHyprlandSession({ ...HYPRLAND, XDG_CURRENT_DESKTOP: "ubuntu:GNOME" })).toBe(false);
expect(isHyprlandSession({ ...HYPRLAND, XDG_CURRENT_DESKTOP: "sway" })).toBe(false);
expect(isHyprlandSession({ ...HYPRLAND, HYPRLAND_INSTANCE_SIGNATURE: "" })).toBe(false);
expect(isHyprlandSession({ ...HYPRLAND, HYPRLAND_INSTANCE_SIGNATURE: "../../evil" })).toBe(false);
expect(isHyprlandSession({})).toBe(false);
});
});
describe("parseCuaPluginStatus", () => {
it("is active only for a configured input build with a ready transport and matching ABI", () => {
expect(parseCuaPluginStatus(JSON.stringify(activeStatus()))).toBe("active");
for (const status of [
activeStatus({ state: "discovery_only" }),
activeStatus({ state: "input_experiment" }),
activeStatus({ configured: false }),
activeStatus({ abi: { compiled_hash: "a", runtime_hash: "b", match: false } }),
activeStatus({ transport: { ready: false } }),
activeStatus({ input: { protocol: 3, test_only: false, transport_ready: false } }),
activeStatus({ input: { protocol: 3, test_only: true, transport_ready: true } }),
activeStatus({ input: { protocol: 2, test_only: false, transport_ready: true } }),
activeStatus({ input: undefined }),
activeStatus({ name: "some-other-plugin" }),
]) {
expect(parseCuaPluginStatus(JSON.stringify(status)), JSON.stringify(status)).toBe("inactive");
}
});
it("treats hyprctl's text for an unknown request and malformed output as inactive", () => {
for (const output of ["unknown request", "", "null", "[]", "{", '"active"', undefined]) {
expect(parseCuaPluginStatus(output)).toBe("inactive");
}
});
});
describe("probeCuaHyprlandPlugin", () => {
it("asks the system hyprctl, never one from PATH, with the session's instance signature", async () => {
const run = vi.fn(async () => ({ exitCode: 0, stdout: JSON.stringify(activeStatus()) }));
await expect(probeCuaHyprlandPlugin({ env: { ...HYPRLAND, PATH: "/tmp/evil" }, run, exists: () => true })).resolves.toBe("active");
expect(run).toHaveBeenCalledOnce();
const [command, args, options] = run.mock.calls[0];
expect(command).toBe(HYPRCTL);
expect(args).toEqual(["-j", "cua:status"]);
expect(options.env.HYPRLAND_INSTANCE_SIGNATURE).toBe(HYPRLAND.HYPRLAND_INSTANCE_SIGNATURE);
expect(options.env.LC_ALL).toBe("C");
});
it("does not run anything outside a Hyprland session or without the system hyprctl", async () => {
const run = vi.fn();
await expect(probeCuaHyprlandPlugin({ env: { XDG_SESSION_TYPE: "wayland", XDG_CURRENT_DESKTOP: "GNOME" }, run, exists: () => true })).resolves.toBe("inactive");
await expect(probeCuaHyprlandPlugin({ env: HYPRLAND, run, exists: () => false })).resolves.toBe("inactive");
expect(run).not.toHaveBeenCalled();
});
it("is inactive when hyprctl fails or times out", async () => {
await expect(probeCuaHyprlandPlugin({ env: HYPRLAND, run: async () => ({ exitCode: 1, stdout: JSON.stringify(activeStatus()) }), exists: () => true })).resolves.toBe("inactive");
await expect(probeCuaHyprlandPlugin({ env: HYPRLAND, run: async () => ({ exitCode: null, stdout: "" }), exists: () => true })).resolves.toBe("inactive");
});
});
describe("systemDriverPackageVersion", () => {
const owned = (stdout, exitCode = 0) => vi.fn(async () => ({ exitCode, stdout }));
it("returns the version only when cua-driver-bin owns exactly that file", async () => {
const run = owned("/usr/bin/cua-driver is owned by cua-driver-bin 0.41.3-1\n");
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run, exists: () => true })).resolves.toBe("0.41.3-1");
const [command, args, options] = run.mock.calls[0];
expect(command).toBe(PACMAN);
expect(args).toEqual(["-Qo", "/usr/bin/cua-driver"]);
expect(options.env).toEqual({ PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" });
});
it("refuses another owner, another file, a failed query or a relative path", async () => {
const exists = () => true;
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run: owned("/usr/bin/cua-driver is owned by cua-driver-git 9.9.9-1"), exists })).resolves.toBeNull();
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run: owned("/usr/bin/cua-driverx is owned by cua-driver-bin 0.41.3-1"), exists })).resolves.toBeNull();
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run: owned("error: No package owns /usr/bin/cua-driver", 1), exists })).resolves.toBeNull();
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run: owned("/usr/bin/cua-driver is owned by cua-driver-bin 0.41.3-1\nextra"), exists })).resolves.toBeNull();
const never = vi.fn();
await expect(systemDriverPackageVersion("usr/bin/cua-driver", { run: never, exists })).resolves.toBeNull();
await expect(systemDriverPackageVersion("/usr/bin/cua-driver", { run: never, exists: () => false })).resolves.toBeNull();
expect(never).not.toHaveBeenCalled();
});
});
describe("runBounded", () => {
it("kills a command that runs past its deadline", async () => {
const started = Date.now();
await expect(runBounded(process.execPath, ["-e", "setTimeout(() => {}, 10_000)"], { timeoutMs: 200 })).resolves.toEqual({ exitCode: null, stdout: "" });
expect(Date.now() - started).toBeLessThan(5_000);
});
it("returns a quick command's output", async () => {
await expect(runBounded(process.execPath, ["-e", "process.stdout.write('ok')"])).resolves.toEqual({ exitCode: 0, stdout: "ok" });
});
});
it("tells the person how to turn the plugin on in one sentence with Cua's guide", () => {
expect(PLUGIN_REQUIRED_MESSAGE).toMatch(/cua-hyprland-plugin/);
expect(PLUGIN_REQUIRED_MESSAGE).toMatch(/https:\/\/cua\.ai\/docs\/cua-sdk\/guides\/omarchy/);
expect(PLUGIN_REQUIRED_MESSAGE.split(/\.\s/).length).toBe(1);
});