mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-11-09 07:23:14 +00:00
130 lines
4.9 KiB
TypeScript
130 lines
4.9 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
const mocks = vi.hoisted(() => ({
|
|
read: vi.fn(),
|
|
write: vi.fn(),
|
|
windows: vi.fn(),
|
|
sources: vi.fn(),
|
|
current: null as unknown,
|
|
displays: [{ id: 1, bounds: { x: 0, y: 0, width: 1440, height: 1000 } }],
|
|
}));
|
|
vi.mock("../appSettingsStore", () => ({
|
|
readAppSetting: mocks.read,
|
|
writeAppSetting: mocks.write,
|
|
}));
|
|
vi.mock("./capturePickerSources", () => ({ listCapturePickerWindows: mocks.windows }));
|
|
vi.mock("./register/sources", () => ({ getDesktopSources: mocks.sources }));
|
|
vi.mock("./state", () => ({
|
|
get selectedSource() {
|
|
return mocks.current;
|
|
},
|
|
setSelectedSource: (value: unknown) => {
|
|
mocks.current = value;
|
|
},
|
|
}));
|
|
vi.mock("./utils", () => ({ getScreen: () => ({ getAllDisplays: () => mocks.displays }) }));
|
|
import { getSessionCaptureSource, validateCaptureSource } from "./captureSelection";
|
|
const platform = process.platform;
|
|
const source = { id: "window:101:0", name: "Document", windowTitle: "Document", appName: "Notes" };
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
Object.defineProperty(process, "platform", { value: "darwin" });
|
|
mocks.current = null;
|
|
mocks.read.mockReturnValue({ platform: "darwin", source });
|
|
mocks.windows.mockResolvedValue([
|
|
{ id: source.id, appName: "Notes", title: "Document", x: 0, y: 0, width: 100, height: 100 },
|
|
]);
|
|
});
|
|
afterEach(() => {
|
|
Object.defineProperty(process, "platform", { value: platform });
|
|
vi.unstubAllEnvs();
|
|
});
|
|
describe("session capture selection", () => {
|
|
it("starts without a capture source even when the previous window is still available", async () => {
|
|
expect(await getSessionCaptureSource()).toBeNull();
|
|
expect(mocks.current).toBeNull();
|
|
});
|
|
it("ignores persisted selection without enumerating capture sources on startup", () => {
|
|
expect(getSessionCaptureSource()).toBeNull();
|
|
expect(mocks.read).not.toHaveBeenCalled();
|
|
expect(mocks.windows).not.toHaveBeenCalled();
|
|
expect(mocks.sources).not.toHaveBeenCalled();
|
|
});
|
|
it("rejects a recycled window ID with a different title", async () => {
|
|
mocks.windows.mockResolvedValue([
|
|
{ id: source.id, title: "Another document", appName: "Notes" },
|
|
]);
|
|
expect(await validateCaptureSource(source)).toBeNull();
|
|
});
|
|
it("rejects disconnected screens and areas that would be resized", async () => {
|
|
expect(
|
|
await validateCaptureSource({ id: "screen:2:0", name: "Gone", display_id: "2" }),
|
|
).toBeNull();
|
|
expect(
|
|
await validateCaptureSource({
|
|
id: "area:1",
|
|
name: "Area",
|
|
display_id: "1",
|
|
area: { x: 1300, y: 0, width: 400, height: 300 },
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
it("does not broaden window capture when detection fails", async () => {
|
|
mocks.windows.mockRejectedValue(new Error("permission denied"));
|
|
await expect(validateCaptureSource(source)).rejects.toThrow("permission denied");
|
|
expect(mocks.sources).not.toHaveBeenCalled();
|
|
});
|
|
it("keeps a selection only within the current app session", () => {
|
|
mocks.current = source;
|
|
expect(getSessionCaptureSource()).toEqual(source);
|
|
// A fresh main process initializes its in-memory selection to null.
|
|
mocks.current = null;
|
|
expect(getSessionCaptureSource()).toBeNull();
|
|
expect(mocks.read).not.toHaveBeenCalled();
|
|
expect(mocks.write).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("Linux selection", () => {
|
|
beforeEach(() => {
|
|
Object.defineProperty(process, "platform", { value: "linux" });
|
|
vi.stubEnv("XDG_SESSION_TYPE", "x11");
|
|
mocks.sources.mockResolvedValue([{ ...source, display_id: "1" }]);
|
|
});
|
|
it("validates X11 windows using live sources without geometry helpers", async () => {
|
|
expect(await validateCaptureSource(source)).toMatchObject({
|
|
id: source.id,
|
|
name: source.name,
|
|
windowTitle: source.windowTitle,
|
|
display_id: "1",
|
|
sourceType: "window",
|
|
});
|
|
expect(mocks.windows).not.toHaveBeenCalled();
|
|
expect(mocks.sources).toHaveBeenCalledWith(
|
|
{ types: ["window"], thumbnailSize: { width: 0, height: 0 } },
|
|
{ strict: true },
|
|
);
|
|
});
|
|
it("rejects missing and recycled X11 windows without substitution", async () => {
|
|
mocks.sources.mockResolvedValue([{ id: source.id, name: "Different document" }]);
|
|
expect(await validateCaptureSource(source)).toBeNull();
|
|
mocks.sources.mockResolvedValue([{ ...source, id: "window:102:0" }]);
|
|
expect(await validateCaptureSource(source)).toBeNull();
|
|
});
|
|
it("starts Wayland unselected without opening the portal", () => {
|
|
vi.stubEnv("XDG_SESSION_TYPE", "wayland");
|
|
expect(getSessionCaptureSource()).toBeNull();
|
|
expect(mocks.read).not.toHaveBeenCalled();
|
|
expect(mocks.sources).not.toHaveBeenCalled();
|
|
expect(mocks.windows).not.toHaveBeenCalled();
|
|
});
|
|
it("rejects old X11 IDs on Wayland without enumerating portal sources", async () => {
|
|
vi.stubEnv("XDG_SESSION_TYPE", "wayland");
|
|
expect(await validateCaptureSource(source)).toBeNull();
|
|
expect(
|
|
await validateCaptureSource({ id: "screen:1:0", name: "Screen", display_id: "1" }),
|
|
).toBeNull();
|
|
expect(mocks.sources).not.toHaveBeenCalled();
|
|
expect(mocks.windows).not.toHaveBeenCalled();
|
|
});
|
|
});
|