import { describe, it, expect, vi, beforeEach } from "vitest"; const invoke = vi.fn(); const listen = vi.fn(); vi.mock("@tauri-apps/api/core", () => ({ invoke: (...args: unknown[]) => invoke(...args), })); vi.mock("@tauri-apps/api/event", () => ({ listen: (...args: unknown[]) => listen(...args), })); import { TauriWindowGateway } from "./window"; describe("TauriWindowGateway (#23)", () => { beforeEach(() => { invoke.mockReset().mockResolvedValue({}); listen.mockReset(); }); it("open/close relay panel-only payloads to the backend commands (#47)", async () => { const gw = new TauriWindowGateway(); await gw.openViewWindow("tickets"); expect(invoke).toHaveBeenCalledWith("open_view_window", { panel: "tickets", }); await gw.closeViewWindow("git"); expect(invoke).toHaveBeenCalledWith("close_view_window", { panel: "git", }); }); it("maps project settings to the backend's historical context window id", async () => { const gw = new TauriWindowGateway(); await gw.openViewWindow("projectSettings"); expect(invoke).toHaveBeenLastCalledWith("open_view_window", { panel: "context", }); await gw.closeViewWindow("projectSettings"); expect(invoke).toHaveBeenLastCalledWith("close_view_window", { panel: "context", }); }); it("opens plugin layout windows through the backend command", async () => { invoke.mockResolvedValueOnce({ label: "view-plugin-layout", url: "index.html?pluginLayout=1", alreadyOpen: false, providerPluginDisplayName: "Plugin", layoutLabel: "Dashboard", surface: { pluginId: "dev.acme.plugin", layoutType: "dev.acme.plugin.dashboard", state: { tab: "overview" }, }, }); const gw = new TauriWindowGateway(); await expect( gw.openPluginLayoutWindow({ pluginId: "dev.acme.plugin", layoutType: "dev.acme.plugin.dashboard", state: { tab: "overview" }, }), ).resolves.toMatchObject({ label: "view-plugin-layout", surface: { layoutType: "dev.acme.plugin.dashboard" }, }); expect(invoke).toHaveBeenCalledWith("open_plugin_layout_window", { input: { pluginId: "dev.acme.plugin", layoutType: "dev.acme.plugin.dashboard", state: { tab: "overview" }, }, }); }); it("onViewWindowClosed listens on the lifecycle channel and forwards only closes", async () => { // Capture the raw Tauri listener so we can drive lifecycle events at will. let raw: ((e: { payload: unknown }) => void) | undefined; const unlisten = vi.fn(); listen.mockImplementation((_name: string, cb: typeof raw) => { raw = cb; return Promise.resolve(unlisten); }); const gw = new TauriWindowGateway(); const handler = vi.fn(); const off = await gw.onViewWindowClosed(handler); expect(listen).toHaveBeenCalledWith( "view-window://lifecycle", expect.any(Function), ); // opened / focused are dropped… raw?.({ payload: { kind: "opened", panel: "git", label: "view-git" }, }); raw?.({ payload: { kind: "focused", panel: "git", label: "view-git" }, }); expect(handler).not.toHaveBeenCalled(); // …only closed reaches the port handler, narrowed to { panel } (#47). raw?.({ payload: { kind: "closed", panel: "git", label: "view-git" }, }); expect(handler).toHaveBeenCalledTimes(1); expect(handler).toHaveBeenCalledWith({ panel: "git" }); raw?.({ payload: { kind: "closed", panel: "context", label: "view-context" }, }); expect(handler).toHaveBeenLastCalledWith({ panel: "projectSettings" }); off(); expect(unlisten).toHaveBeenCalled(); }); });