- Move the read-only OpenAPI compat surface from /api/v2/assets to /mjr/am/compat/assets so it never squats ComfyUI core's /api namespace; the legacy alias is opt-in via MJR_AM_LEGACY_API_V2_ASSETS=1. - Allow Python 3.14 (requires-python <3.15) and add 3.14 to CI and tox. - Stop wrapping api.queuePrompt: progress tracking now resolves the running prompt from the core Jobs API (getJobDetail), then /queue and /history, driven by websocket events. Remove wrapHostQueuePrompt. - Add opt-in Majoor.Integration.HideNativeAssetsTab setting that hides ComfyUI's native Assets sidebar tab through the official getSidebarTabs/unregisterSidebarTab API and restores it when disabled. - Fix all 913 type errors in tsconfig.test.json and type-check tests in CI; drop a duplicated `stubs` key in asset_card_inner test; make addToastHistory's type argument optional for the object form. - Update audit report, changelog, API reference and env var docs.
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { createPinia, setActivePinia } from "pinia";
|
|
|
|
import { createBrowserNavigationController } from "../features/panel/controllers/browserNavigationController.js";
|
|
import { usePanelStore } from "../stores/usePanelStore.js";
|
|
|
|
vi.mock("../app/i18n.js", () => ({
|
|
t: (_key, fallback) => fallback || "",
|
|
}));
|
|
|
|
function createNode() {
|
|
const listeners = new Map();
|
|
return {
|
|
style: { display: "" },
|
|
dataset: {},
|
|
disabled: false,
|
|
children: [],
|
|
className: "",
|
|
textContent: "",
|
|
value: "",
|
|
selectedOptions: [],
|
|
addEventListener(type, handler) {
|
|
const list = listeners.get(type) || [];
|
|
list.push(handler);
|
|
listeners.set(type, list);
|
|
},
|
|
removeEventListener(type, handler) {
|
|
const list = listeners.get(type) || [];
|
|
listeners.set(
|
|
type,
|
|
list.filter((item) => item !== handler),
|
|
);
|
|
},
|
|
dispatchEvent(event) {
|
|
for (const handler of listeners.get(event.type) || []) {
|
|
handler(event);
|
|
}
|
|
},
|
|
appendChild(child) {
|
|
this.children.push(child);
|
|
return child;
|
|
},
|
|
replaceChildren(...nodes) {
|
|
this.children = nodes;
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("browserNavigationController", () => {
|
|
it("syncs navigated folder path into Pinia", async () => {
|
|
globalThis.window = { addEventListener: vi.fn(), removeEventListener: vi.fn() } as any;
|
|
globalThis.document = {
|
|
createElement: () => createNode() as any,
|
|
} as any;
|
|
setActivePinia(createPinia());
|
|
const panelStore = usePanelStore();
|
|
|
|
const gridContainer = createNode();
|
|
const folderBreadcrumb = createNode();
|
|
const folderBreadcrumbController = { setFolderBreadcrumb: vi.fn() };
|
|
const customSelect = createNode();
|
|
const reloadGrid = vi.fn(async () => ({}));
|
|
const onContextChanged = vi.fn();
|
|
|
|
const state = {
|
|
scope: "output",
|
|
customRootId: "",
|
|
currentFolderRelativePath: "",
|
|
};
|
|
|
|
const controller = createBrowserNavigationController({
|
|
state,
|
|
gridContainer,
|
|
folderBreadcrumb,
|
|
folderBreadcrumbController,
|
|
customSelect,
|
|
reloadGrid,
|
|
onContextChanged,
|
|
});
|
|
|
|
const unbind = controller.bindGridFolderNavigation();
|
|
gridContainer.dispatchEvent({
|
|
type: "mjr:open-folder-asset",
|
|
detail: { asset: { kind: "folder", filepath: "animals/cats" } },
|
|
});
|
|
|
|
expect(panelStore.currentFolderRelativePath).toBe("animals/cats");
|
|
expect((gridContainer.dataset as any).mjrSubfolder).toBe("animals/cats");
|
|
expect(reloadGrid).toHaveBeenCalledTimes(1);
|
|
expect(onContextChanged).toHaveBeenCalledTimes(1);
|
|
expect(folderBreadcrumbController.setFolderBreadcrumb).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
visible: true,
|
|
items: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Computer" }),
|
|
expect.objectContaining({ label: "animals" }),
|
|
expect.objectContaining({ label: "cats", current: true }),
|
|
]),
|
|
}),
|
|
);
|
|
|
|
unbind();
|
|
});
|
|
});
|