Files
paseo/packages/app/src/hooks/use-preferred-editor.test.ts
T
Mohamed BoudraandKino Roy 27d6b3b7ce feat(desktop): remember project editors and support Xcode (#7898)
Keep editor choices local to each project and shared across its worktrees. Reuse the Xcode target contribution while preserving explicit editor selection.

Co-authored-by: Kino Roy <kinoroy@me.com>
2026-10-26 13:36:00 +07:00

110 lines
4.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { QueryClient } from "@tanstack/react-query";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { createPreferredEditorPreference, resolvePreferredEditorId } from "./use-preferred-editor";
describe("resolvePreferredEditorId", () => {
it("keeps the stored editor when it is still available", () => {
expect(resolvePreferredEditorId(["cursor", "vscode"], "vscode")).toBe("vscode");
});
it("falls back to the first available editor when the stored one is missing", () => {
expect(resolvePreferredEditorId(["zed", "finder"], "cursor")).toBe("zed");
});
it("falls back when a platform-specific file manager target is unavailable", () => {
expect(resolvePreferredEditorId(["explorer", "vscode"], "finder")).toBe("explorer");
});
it("keeps unknown editor ids when they are still available", () => {
expect(resolvePreferredEditorId(["unknown-editor", "cursor"], "unknown-editor")).toBe(
"unknown-editor",
);
});
it("keeps custom script target ids as plain strings", () => {
expect(resolvePreferredEditorId(["script:open-in-nvim", "cursor"], "script:open-in-nvim")).toBe(
"script:open-in-nvim",
);
});
it("returns null when no editors are available", () => {
expect(resolvePreferredEditorId([], "cursor")).toBeNull();
});
});
describe("project editor preferences", () => {
it("changing one project leaves another project's cached and persisted choice unchanged", async () => {
await AsyncStorage.clear();
await AsyncStorage.setItem("@paseo:preferred-editor", "vscode");
const queryClient = new QueryClient();
const projectA = createPreferredEditorPreference({
scope: { serverId: "host", projectId: "project-a" },
queryClient,
storage: AsyncStorage,
});
const projectB = createPreferredEditorPreference({
scope: { serverId: "host", projectId: "project-b" },
queryClient,
storage: AsyncStorage,
});
expect(await queryClient.fetchQuery(projectA.queryOptions)).toBe("vscode");
expect(await queryClient.fetchQuery(projectB.queryOptions)).toBe("vscode");
await projectA.update("cursor");
expect(await queryClient.fetchQuery(projectA.queryOptions)).toBe("cursor");
expect(await queryClient.fetchQuery(projectB.queryOptions)).toBe("vscode");
queryClient.clear();
expect(await queryClient.fetchQuery(projectA.queryOptions)).toBe("cursor");
expect(await queryClient.fetchQuery(projectB.queryOptions)).toBe("vscode");
expect(await AsyncStorage.getItem("@paseo:preferred-editor")).toBe("vscode");
queryClient.clear();
});
it("shares a choice across workspaces of the same project while isolating hosts", async () => {
await AsyncStorage.clear();
const queryClient = new QueryClient();
const root = createPreferredEditorPreference({
scope: { serverId: "host-a", projectId: "project" },
queryClient,
storage: AsyncStorage,
});
const worktree = createPreferredEditorPreference({
scope: { serverId: "host-a", projectId: "project" },
queryClient,
storage: AsyncStorage,
});
const otherHost = createPreferredEditorPreference({
scope: { serverId: "host-b", projectId: "project" },
queryClient,
storage: AsyncStorage,
});
await root.update("zed");
expect(await queryClient.fetchQuery(worktree.queryOptions)).toBe("zed");
expect(await queryClient.fetchQuery(otherHost.queryOptions)).toBeNull();
queryClient.clear();
expect(await queryClient.fetchQuery(worktree.queryOptions)).toBe("zed");
expect(await queryClient.fetchQuery(otherHost.queryOptions)).toBeNull();
queryClient.clear();
});
it("preserves the previous choice when saving fails", async () => {
await AsyncStorage.clear();
await AsyncStorage.setItem("@paseo:preferred-editor", "vscode");
const queryClient = new QueryClient();
const preference = createPreferredEditorPreference({
scope: { serverId: "host", projectId: "project" },
queryClient,
storage: {
getItem: AsyncStorage.getItem,
removeItem: AsyncStorage.removeItem,
async setItem() {
throw new Error("Storage is full");
},
},
});
expect(await queryClient.fetchQuery(preference.queryOptions)).toBe("vscode");
await expect(preference.update("cursor")).rejects.toThrow("Storage is full");
expect(await queryClient.fetchQuery(preference.queryOptions)).toBe("vscode");
queryClient.clear();
});
});