Files
MajoorWaldi-ComfyUI-Majoor-…/ui/tests/comfy_api_bridge.vitest.ts
T

255 lines
10 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
beforeEach(() => {
vi.resetModules();
globalThis.window = {};
globalThis.globalThis = globalThis;
});
describe("comfyApiBridge", () => {
it("discovers extension manager native surfaces from the app", async () => {
const toast = { add: vi.fn() };
const dialog = { confirm: vi.fn(), prompt: vi.fn() };
const registerSidebarTab = vi.fn();
const app = {
ui: {},
extensionManager: {
toast,
dialog,
registerSidebarTab,
activateSidebarTab: vi.fn(),
registerCommand: vi.fn(),
registerKeybinding: vi.fn(),
registerBottomPanelTab: vi.fn(),
},
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.getExtensionToastApi()).toBe(toast);
expect(mod.getExtensionDialogApi()).toBe(dialog);
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(app.extensionManager.activateSidebarTab).toHaveBeenCalledWith("majoor-assets");
expect(mod.registerSidebarTabCompat(app, { id: "majoor-assets" })).toBe(true);
expect(registerSidebarTab).toHaveBeenCalledWith({ id: "majoor-assets" });
expect(mod.registerCommandCompat(app, { id: "mjr.test" })).toBe(true);
expect(mod.registerKeybindingCompat(app, { commandId: "mjr.test" })).toBe(true);
expect(mod.registerBottomPanelTabCompat(app, { id: "mjr.feed" })).toBe(true);
});
it("supports nested sidebar and bottom panel controllers from newer ComfyUI runtimes", async () => {
const toggleSidebarTab = vi.fn();
const registerSidebarTab = vi.fn();
const registerBottomPanelTab = vi.fn();
const activateBottomPanelTab = vi.fn();
const app = {
ui: {},
extensionManager: {
sidebarTab: {
activeSidebarTabId: "",
toggleSidebarTab,
registerSidebarTab,
},
bottomPanel: {
registerBottomPanelTab,
activateBottomPanelTab,
},
},
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(toggleSidebarTab).toHaveBeenCalledWith("majoor-assets");
expect(mod.registerSidebarTabCompat(app, { id: "majoor-assets" })).toBe(true);
expect(registerSidebarTab).toHaveBeenCalledWith({ id: "majoor-assets" });
expect(mod.registerBottomPanelTabCompat(app, { id: "mjr.feed" })).toBe(true);
expect(registerBottomPanelTab).toHaveBeenCalledWith({ id: "mjr.feed" });
expect(mod.activateBottomPanelTabCompat(app, "mjr.feed")).toBe(true);
expect(activateBottomPanelTab).toHaveBeenCalledWith("mjr.feed");
});
it("prefers sidebarTabStore and supports workspaceStore sidebar fallback", async () => {
const storeToggle = vi.fn();
const legacyToggle = vi.fn();
const workspaceToggle = vi.fn();
const appWorkspaceToggle = vi.fn();
const app = {
ui: {
workspaceStore: { sidebarTab: { toggleSidebarTab: appWorkspaceToggle } },
},
extensionManager: {
sidebarTab: { toggleSidebarTab: legacyToggle },
sidebarTabStore: { toggleSidebarTab: storeToggle },
workspaceStore: { sidebarTab: { toggleSidebarTab: workspaceToggle } },
},
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.getSidebarController(app)).toBe(app.extensionManager.sidebarTabStore);
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(storeToggle).toHaveBeenCalledWith("majoor-assets");
expect(legacyToggle).not.toHaveBeenCalled();
expect(workspaceToggle).not.toHaveBeenCalled();
delete app.extensionManager.sidebarTabStore;
delete app.extensionManager.sidebarTab;
expect(mod.getSidebarController(app)).toBe(app.extensionManager.workspaceStore.sidebarTab);
delete app.extensionManager.workspaceStore;
expect(mod.getSidebarController(app)).toBe(app.ui.workspaceStore.sidebarTab);
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(appWorkspaceToggle).toHaveBeenCalledWith("majoor-assets");
});
it("registers and activates sidebar tabs through current App mode workspace stores", async () => {
const registerSidebarTab = vi.fn();
const toggleSidebarTab = vi.fn();
const app = {
ui: {},
workspaceStore: {
sidebarTab: {
activeSidebarTabId: "",
registerSidebarTab,
toggleSidebarTab,
},
},
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.registerSidebarTabCompat(app, { id: "majoor-assets" })).toBe(true);
expect(registerSidebarTab).toHaveBeenCalledWith({ id: "majoor-assets" });
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(toggleSidebarTab).toHaveBeenCalledWith("majoor-assets");
});
it("does not toggle a sidebar tab that is already active", async () => {
const toggleSidebarTab = vi.fn();
const app = {
ui: {},
extensionManager: {
sidebarTab: {
activeSidebarTabId: "majoor-assets",
toggleSidebarTab,
},
},
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.activateSidebarTabCompat(app, "majoor-assets")).toBe(true);
expect(toggleSidebarTab).not.toHaveBeenCalled();
});
it("returns false when native manager APIs are unavailable", async () => {
const app = { ui: {} };
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.getExtensionToastApi()).toBeNull();
expect(mod.getExtensionDialogApi()).toBeNull();
expect(mod.activateSidebarTabCompat(app, "missing")).toBe(false);
expect(mod.registerSidebarTabCompat(app, { id: "missing" })).toBe(false);
expect(mod.registerCommandCompat(app, { id: "mjr.test" })).toBe(false);
expect(mod.registerBottomPanelTabCompat(app, { id: "mjr.feed" })).toBe(false);
});
it("accepts alert-only extension dialog APIs", async () => {
const dialog = { alert: vi.fn() };
const app = {
ui: {},
extensionManager: { dialog },
};
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApp(app);
expect(mod.getExtensionDialogApi(app)).toBe(dialog);
});
it("reads and writes settings through current and legacy ComfyUI settings APIs", async () => {
const setSettingValue = vi.fn();
const app = {
ui: {
settings: {
getSettingValue: vi.fn((key) => (key === "Majoor.Test" ? true : undefined)),
setSettingValue,
},
},
};
const mod = await import("../app/comfyApiBridge.js");
expect(mod.getSettingValue(app, "Majoor.Test")).toBe(true);
expect(mod.setSettingValue(app, "Majoor.Test", false)).toBe(true);
expect(setSettingValue).toHaveBeenCalledWith("Majoor.Test", false);
});
it("prefers extensionManager.setting over legacy settings APIs", async () => {
const set = vi.fn(async () => undefined);
const legacyGet = vi.fn(() => "legacy");
const app = {
extensionManager: {
setting: {
get: vi.fn((key: string) => (key === "Majoor.Test" ? "native" : undefined)),
set,
},
},
ui: { settings: { getSettingValue: legacyGet } },
};
const mod = await import("../app/comfyApiBridge.js");
expect(mod.getSettingsApi(app)).toBe(app.extensionManager.setting);
expect(mod.getSettingValue(app, "Majoor.Test")).toBe("native");
expect(mod.setSettingValue(app, "Majoor.Test", "next")).toBe(true);
expect(set).toHaveBeenCalledWith("Majoor.Test", "next");
expect(legacyGet).not.toHaveBeenCalled();
});
it("falls back to map-like settings stores when helper methods are unavailable", async () => {
const app = {
settings: {
settings: new Map([["Majoor.Test", "from-map"]]),
},
};
const mod = await import("../app/comfyApiBridge.js");
expect(mod.getSettingValue(app, "Majoor.Test")).toBe("from-map");
expect(mod.setSettingValue(app, "Majoor.Test", "next")).toBe(true);
expect(app.settings.settings.get("Majoor.Test")).toBe("next");
});
it("prefers ComfyUI api.fetchApi for HTTP calls and falls back to same-origin fetch", async () => {
const fetchApi = vi.fn(() => Promise.resolve({ ok: true, source: "comfy" }));
const fallbackFetch = vi.fn(() => Promise.resolve({ ok: true, source: "fallback" }));
globalThis.fetch = fallbackFetch;
const mod = await import("../app/comfyApiBridge.js");
mod.setComfyApi({ fetchApi });
await expect(mod.fetchComfyApi("/object_info")).resolves.toMatchObject({
source: "comfy",
});
expect(fetchApi).toHaveBeenCalledWith("/object_info", undefined);
expect(fallbackFetch).not.toHaveBeenCalled();
vi.resetModules();
const modWithoutApi = await import("../app/comfyApiBridge.js");
await expect(modWithoutApi.fetchComfyApi("/object_info")).resolves.toMatchObject({
source: "fallback",
});
expect(fallbackFetch).toHaveBeenCalledWith("/object_info", {
credentials: "include",
});
});
});