import { execFile } from "node:child_process"; import { promisify } from "node:util"; import { describe, expect, it } from "vitest"; const execFileAsync = promisify(execFile); const scriptPath = "scripts/install-native-sync-host.mjs"; async function showDir(args: string[]): Promise<{ dir: string; registryHint: string | null }> { const { stdout } = await execFileAsync(process.execPath, [ scriptPath, "--show-dir", "--browser", args[0]!, "--platform-override", args[1]!, "--home-override", args[2]!, ]); return JSON.parse(stdout) as { dir: string; registryHint: string | null }; } describe("native sync installer path resolution", () => { const home = "/home/test"; it("resolves macOS Chrome under Application Support/Google/Chrome", async () => { const { dir } = await showDir(["chrome", "darwin", home]); expect(dir).toBe("/home/test/Library/Application Support/Google/Chrome/NativeMessagingHosts"); }); it("resolves macOS Firefox under Application Support/Mozilla", async () => { const { dir } = await showDir(["firefox", "darwin", home]); expect(dir).toBe("/home/test/Library/Application Support/Mozilla/NativeMessagingHosts"); }); it("resolves Linux Chrome under .config/google-chrome", async () => { const { dir } = await showDir(["chrome", "linux", home]); expect(dir).toBe("/home/test/.config/google-chrome/NativeMessagingHosts"); }); it("resolves Linux Firefox under .mozilla/native-messaging-hosts", async () => { const { dir } = await showDir(["firefox", "linux", home]); expect(dir).toBe("/home/test/.mozilla/native-messaging-hosts"); }); it("resolves Windows with a registry hint", async () => { const { dir, registryHint } = await showDir(["chrome", "win32", "C:\\Users\\test"]); expect(dir).toContain("Peach"); expect(registryHint).toContain("HKEY_CURRENT_USER"); expect(registryHint).toContain("com.peachpasswords.sync"); }); it("rejects unsupported platforms", async () => { await expect(showDir(["chrome", "freebsd", home])).rejects.toThrow("unsupported platform"); }); }); describe("native sync installer script", () => { it("--dry-run prints destination + manifest without writing", async () => { const { stdout } = await execFileAsync(process.execPath, [ scriptPath, "--browser", "chrome", "--extension-id", "abcdefghijklmnopabcdefghijklmnop", "--host-path", "/opt/peach/peach-sync-host", "--dry-run", ]); expect(stdout).toMatch(/Would write .*com\.peachpasswords\.sync\.json/); expect(stdout).toContain('"name": "com.peachpasswords.sync"'); expect(stdout).toContain("/opt/peach/peach-sync-host"); }); it("rejects missing --browser", async () => { await expect( execFileAsync(process.execPath, [scriptPath, "--dry-run"]) ).rejects.toThrow("--browser is required"); }); });