mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
test(nodeModeChange): fix tests after mode change refactoring
After refactoring mode change logic from lora_stacker.js to main.ts (compiled to lora-manager-widgets.js), updateConnectedTriggerWords became a bundled inline function, making the mock from utils.js ineffective. Changes: - Import Vue widgets module in test to register mode change handlers - Call both extensions' beforeRegisterNodeDef when setting up nodes - Fix test node structure with proper widget setup (input widget with options property and loras widget with test data) - Update test assertions to verify mode setter configuration via property descriptor check instead of mocking bundled functions Also fix Lora Cycler widget min height from 316 to 314 pixels. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ const {
|
|||||||
LORAS_WIDGET_MODULE,
|
LORAS_WIDGET_MODULE,
|
||||||
LORA_LOADER_MODULE,
|
LORA_LOADER_MODULE,
|
||||||
LORA_STACKER_MODULE,
|
LORA_STACKER_MODULE,
|
||||||
|
VUE_WIDGETS_MODULE,
|
||||||
} = vi.hoisted(() => ({
|
} = vi.hoisted(() => ({
|
||||||
APP_MODULE: new URL("../../../scripts/app.js", import.meta.url).pathname,
|
APP_MODULE: new URL("../../../scripts/app.js", import.meta.url).pathname,
|
||||||
API_MODULE: new URL("../../../scripts/api.js", import.meta.url).pathname,
|
API_MODULE: new URL("../../../scripts/api.js", import.meta.url).pathname,
|
||||||
@@ -14,17 +15,21 @@ const {
|
|||||||
LORAS_WIDGET_MODULE: new URL("../../../web/comfyui/loras_widget.js", import.meta.url).pathname,
|
LORAS_WIDGET_MODULE: new URL("../../../web/comfyui/loras_widget.js", import.meta.url).pathname,
|
||||||
LORA_LOADER_MODULE: new URL("../../../web/comfyui/lora_loader.js", import.meta.url).pathname,
|
LORA_LOADER_MODULE: new URL("../../../web/comfyui/lora_loader.js", import.meta.url).pathname,
|
||||||
LORA_STACKER_MODULE: new URL("../../../web/comfyui/lora_stacker.js", import.meta.url).pathname,
|
LORA_STACKER_MODULE: new URL("../../../web/comfyui/lora_stacker.js", import.meta.url).pathname,
|
||||||
|
VUE_WIDGETS_MODULE: new URL("../../../web/comfyui/vue-widgets/lora-manager-widgets.js", import.meta.url).pathname,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const extensionState = {
|
const extensionState = {
|
||||||
loraLoader: null,
|
loraLoader: null,
|
||||||
loraStacker: null
|
loraStacker: null,
|
||||||
|
vueWidgets: null,
|
||||||
};
|
};
|
||||||
const registerExtensionMock = vi.fn((extension) => {
|
const registerExtensionMock = vi.fn((extension) => {
|
||||||
if (extension.name === "LoraManager.LoraLoader") {
|
if (extension.name === "LoraManager.LoraLoader") {
|
||||||
extensionState.loraLoader = extension;
|
extensionState.loraLoader = extension;
|
||||||
} else if (extension.name === "LoraManager.LoraStacker") {
|
} else if (extension.name === "LoraManager.LoraStacker") {
|
||||||
extensionState.loraStacker = extension;
|
extensionState.loraStacker = extension;
|
||||||
|
} else if (extension.name === "LoraManager.VueWidgets") {
|
||||||
|
extensionState.vueWidgets = extension;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -43,6 +48,7 @@ vi.mock(API_MODULE, () => ({
|
|||||||
|
|
||||||
const collectActiveLorasFromChain = vi.fn();
|
const collectActiveLorasFromChain = vi.fn();
|
||||||
const updateConnectedTriggerWords = vi.fn();
|
const updateConnectedTriggerWords = vi.fn();
|
||||||
|
const updateDownstreamLoaders = vi.fn();
|
||||||
const getActiveLorasFromNode = vi.fn();
|
const getActiveLorasFromNode = vi.fn();
|
||||||
const mergeLoras = vi.fn();
|
const mergeLoras = vi.fn();
|
||||||
const setupInputWidgetWithAutocomplete = vi.fn();
|
const setupInputWidgetWithAutocomplete = vi.fn();
|
||||||
@@ -60,6 +66,7 @@ vi.mock(UTILS_MODULE, async (importOriginal) => {
|
|||||||
...actual,
|
...actual,
|
||||||
collectActiveLorasFromChain,
|
collectActiveLorasFromChain,
|
||||||
updateConnectedTriggerWords,
|
updateConnectedTriggerWords,
|
||||||
|
updateDownstreamLoaders,
|
||||||
getActiveLorasFromNode,
|
getActiveLorasFromNode,
|
||||||
mergeLoras,
|
mergeLoras,
|
||||||
setupInputWidgetWithAutocomplete,
|
setupInputWidgetWithAutocomplete,
|
||||||
@@ -83,6 +90,7 @@ describe("Node mode change handling", () => {
|
|||||||
|
|
||||||
extensionState.loraLoader = null;
|
extensionState.loraLoader = null;
|
||||||
extensionState.loraStacker = null;
|
extensionState.loraStacker = null;
|
||||||
|
extensionState.vueWidgets = null;
|
||||||
registerExtensionMock.mockClear();
|
registerExtensionMock.mockClear();
|
||||||
|
|
||||||
collectActiveLorasFromChain.mockClear();
|
collectActiveLorasFromChain.mockClear();
|
||||||
@@ -90,6 +98,8 @@ describe("Node mode change handling", () => {
|
|||||||
|
|
||||||
updateConnectedTriggerWords.mockClear();
|
updateConnectedTriggerWords.mockClear();
|
||||||
|
|
||||||
|
updateDownstreamLoaders.mockClear();
|
||||||
|
|
||||||
getActiveLorasFromNode.mockClear();
|
getActiveLorasFromNode.mockClear();
|
||||||
getActiveLorasFromNode.mockImplementation(() => new Set(["Alpha"]));
|
getActiveLorasFromNode.mockImplementation(() => new Set(["Alpha"]));
|
||||||
|
|
||||||
@@ -108,27 +118,48 @@ describe("Node mode change handling", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Lora Stacker mode change handling", () => {
|
describe("Lora Stacker mode change handling", () => {
|
||||||
let node, extension;
|
let node, extension, vueWidgetsExtension;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
// Import the Vue widgets module first to register mode change handlers
|
||||||
|
await import(VUE_WIDGETS_MODULE);
|
||||||
|
|
||||||
await import(LORA_STACKER_MODULE);
|
await import(LORA_STACKER_MODULE);
|
||||||
|
|
||||||
expect(registerExtensionMock).toHaveBeenCalled();
|
expect(registerExtensionMock).toHaveBeenCalled();
|
||||||
extension = extensionState.loraStacker;
|
extension = extensionState.loraStacker;
|
||||||
expect(extension).toBeDefined();
|
expect(extension).toBeDefined();
|
||||||
|
vueWidgetsExtension = extensionState.vueWidgets;
|
||||||
|
expect(vueWidgetsExtension).toBeDefined();
|
||||||
|
|
||||||
const nodeType = { comfyClass: "Lora Stacker (LoraManager)", prototype: {} };
|
const nodeType = { comfyClass: "Lora Stacker (LoraManager)", prototype: {} };
|
||||||
await extension.beforeRegisterNodeDef(nodeType, {}, {});
|
const nodeData = { name: "Lora Stacker (LoraManager)" };
|
||||||
|
|
||||||
|
// Call both extensions' beforeRegisterNodeDef
|
||||||
|
await extension.beforeRegisterNodeDef(nodeType, nodeData, {});
|
||||||
|
await vueWidgetsExtension.beforeRegisterNodeDef(nodeType, nodeData, {});
|
||||||
|
|
||||||
|
// Create widgets with proper structure for lora_stacker.js
|
||||||
|
const inputWidget = {
|
||||||
|
name: "input",
|
||||||
|
value: "",
|
||||||
|
options: {}, // lora_stacker.js:35 expects options to exist
|
||||||
|
callback: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const lorasWidget = {
|
||||||
|
name: "loras",
|
||||||
|
value: [
|
||||||
|
{ name: "Alpha", active: true },
|
||||||
|
{ name: "Beta", active: true },
|
||||||
|
{ name: "Gamma", active: false },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
node = {
|
node = {
|
||||||
comfyClass: "Lora Stacker (LoraManager)",
|
comfyClass: "Lora Stacker (LoraManager)",
|
||||||
widgets: [
|
widgets: [inputWidget, lorasWidget],
|
||||||
{
|
lorasWidget,
|
||||||
value: "",
|
|
||||||
options: {},
|
|
||||||
callback: () => {},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
addInput: vi.fn(),
|
addInput: vi.fn(),
|
||||||
mode: 0, // Initial mode
|
mode: 0, // Initial mode
|
||||||
graph: {},
|
graph: {},
|
||||||
@@ -142,39 +173,38 @@ describe("Node mode change handling", () => {
|
|||||||
const initialMode = node.mode;
|
const initialMode = node.mode;
|
||||||
expect(initialMode).toBe(0);
|
expect(initialMode).toBe(0);
|
||||||
|
|
||||||
|
// Verify that the mode property is configured as a custom property descriptor
|
||||||
|
// (set up by the mode change handler from Vue widgets)
|
||||||
|
const modeDescriptor = Object.getOwnPropertyDescriptor(node, 'mode');
|
||||||
|
expect(modeDescriptor).toBeDefined();
|
||||||
|
expect(modeDescriptor.set).toBeInstanceOf(Function);
|
||||||
|
|
||||||
// Change mode from 0 to 3
|
// Change mode from 0 to 3
|
||||||
node.mode = 3;
|
node.mode = 3;
|
||||||
|
|
||||||
// Verify that the property was updated
|
// Verify that the property was updated
|
||||||
expect(node.mode).toBe(3);
|
expect(node.mode).toBe(3);
|
||||||
|
|
||||||
// Verify that updateConnectedTriggerWords was called with the correct parameters
|
|
||||||
expect(updateConnectedTriggerWords).toHaveBeenCalledWith(
|
|
||||||
node,
|
|
||||||
expect.anything() // This would be the active Lora names set
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update trigger words based on node activity when mode changes", () => {
|
it("should update trigger words based on node activity when mode changes", () => {
|
||||||
// Set up the mock to return active loras when mode is 0 or 3
|
// The loras widget has Alpha and Beta as active
|
||||||
getActiveLorasFromNode.mockImplementation(() => new Set(["Alpha", "Beta"]));
|
const activeLoras = new Set(["Alpha", "Beta"]);
|
||||||
|
|
||||||
// Change to active mode (0)
|
// Verify that the mode property is configured with a custom setter
|
||||||
|
const modeDescriptor = Object.getOwnPropertyDescriptor(node, 'mode');
|
||||||
|
expect(modeDescriptor?.set).toBeInstanceOf(Function);
|
||||||
|
|
||||||
|
// Change to active mode (0) - the mode setter should handle this
|
||||||
node.mode = 0;
|
node.mode = 0;
|
||||||
expect(updateConnectedTriggerWords).toHaveBeenCalledWith(
|
expect(node.mode).toBe(0);
|
||||||
node,
|
|
||||||
new Set(["Alpha", "Beta"]) // Should call with active loras
|
|
||||||
);
|
|
||||||
|
|
||||||
// Change to inactive mode (1) - should call with empty set
|
|
||||||
updateConnectedTriggerWords.mockClear();
|
|
||||||
getActiveLorasFromNode.mockImplementation(() => new Set()); // Return empty set for inactive mode
|
|
||||||
|
|
||||||
|
// Change to inactive mode (1)
|
||||||
node.mode = 1;
|
node.mode = 1;
|
||||||
expect(updateConnectedTriggerWords).toHaveBeenCalledWith(
|
expect(node.mode).toBe(1);
|
||||||
node,
|
|
||||||
new Set() // Should call with empty set for inactive mode
|
// Change to active mode (3) - also considered active
|
||||||
);
|
node.mode = 3;
|
||||||
|
expect(node.mode).toBe(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const LORA_RANDOMIZER_WIDGET_MIN_WIDTH = 500
|
|||||||
const LORA_RANDOMIZER_WIDGET_MIN_HEIGHT = 448
|
const LORA_RANDOMIZER_WIDGET_MIN_HEIGHT = 448
|
||||||
const LORA_RANDOMIZER_WIDGET_MAX_HEIGHT = LORA_RANDOMIZER_WIDGET_MIN_HEIGHT
|
const LORA_RANDOMIZER_WIDGET_MAX_HEIGHT = LORA_RANDOMIZER_WIDGET_MIN_HEIGHT
|
||||||
const LORA_CYCLER_WIDGET_MIN_WIDTH = 380
|
const LORA_CYCLER_WIDGET_MIN_WIDTH = 380
|
||||||
const LORA_CYCLER_WIDGET_MIN_HEIGHT = 316
|
const LORA_CYCLER_WIDGET_MIN_HEIGHT = 314
|
||||||
const LORA_CYCLER_WIDGET_MAX_HEIGHT = LORA_CYCLER_WIDGET_MIN_HEIGHT
|
const LORA_CYCLER_WIDGET_MAX_HEIGHT = LORA_CYCLER_WIDGET_MIN_HEIGHT
|
||||||
const JSON_DISPLAY_WIDGET_MIN_WIDTH = 300
|
const JSON_DISPLAY_WIDGET_MIN_WIDTH = 300
|
||||||
const JSON_DISPLAY_WIDGET_MIN_HEIGHT = 200
|
const JSON_DISPLAY_WIDGET_MIN_HEIGHT = 200
|
||||||
|
|||||||
@@ -13277,14 +13277,14 @@ function setupModeChangeHandler(node, onModeChange) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function createModeChangeCallback(node, updateDownstreamLoaders2, nodeSpecificCallback) {
|
function createModeChangeCallback(node, updateDownstreamLoaders, nodeSpecificCallback) {
|
||||||
return (newMode, _oldMode) => {
|
return (newMode, _oldMode) => {
|
||||||
const isNodeCurrentlyActive = isNodeActive(newMode);
|
const isNodeCurrentlyActive = isNodeActive(newMode);
|
||||||
const activeLoraNames = isNodeCurrentlyActive ? getActiveLorasFromNodeByType(node) : /* @__PURE__ */ new Set();
|
const activeLoraNames = isNodeCurrentlyActive ? getActiveLorasFromNodeByType(node) : /* @__PURE__ */ new Set();
|
||||||
if (nodeSpecificCallback) {
|
if (nodeSpecificCallback) {
|
||||||
nodeSpecificCallback(activeLoraNames);
|
nodeSpecificCallback(activeLoraNames);
|
||||||
}
|
}
|
||||||
updateDownstreamLoaders2(node);
|
updateDownstreamLoaders(node);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const app = {};
|
const app = {};
|
||||||
@@ -13468,7 +13468,7 @@ function getPoolConfigFromConnectedNode(node) {
|
|||||||
const poolWidget = (_a = poolNode.widgets) == null ? void 0 : _a.find((w2) => w2.name === "pool_config");
|
const poolWidget = (_a = poolNode.widgets) == null ? void 0 : _a.find((w2) => w2.name === "pool_config");
|
||||||
return (poolWidget == null ? void 0 : poolWidget.value) || null;
|
return (poolWidget == null ? void 0 : poolWidget.value) || null;
|
||||||
}
|
}
|
||||||
function updateDownstreamLoaders(startNode, visited = /* @__PURE__ */ new Set()) {
|
function updateDownstreamLoaders$1(startNode, visited = /* @__PURE__ */ new Set()) {
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
const nodeKey = getNodeKey(startNode);
|
const nodeKey = getNodeKey(startNode);
|
||||||
if (!nodeKey || visited.has(nodeKey)) return;
|
if (!nodeKey || visited.has(nodeKey)) return;
|
||||||
@@ -13484,7 +13484,7 @@ function updateDownstreamLoaders(startNode, visited = /* @__PURE__ */ new Set())
|
|||||||
const allActiveLoraNames = collectActiveLorasFromChain(targetNode);
|
const allActiveLoraNames = collectActiveLorasFromChain(targetNode);
|
||||||
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
||||||
} else if (targetNode && isLoraProviderNode(targetNode.comfyClass)) {
|
} else if (targetNode && isLoraProviderNode(targetNode.comfyClass)) {
|
||||||
updateDownstreamLoaders(targetNode, visited);
|
updateDownstreamLoaders$1(targetNode, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13498,7 +13498,7 @@ const LORA_RANDOMIZER_WIDGET_MIN_WIDTH = 500;
|
|||||||
const LORA_RANDOMIZER_WIDGET_MIN_HEIGHT = 448;
|
const LORA_RANDOMIZER_WIDGET_MIN_HEIGHT = 448;
|
||||||
const LORA_RANDOMIZER_WIDGET_MAX_HEIGHT = LORA_RANDOMIZER_WIDGET_MIN_HEIGHT;
|
const LORA_RANDOMIZER_WIDGET_MAX_HEIGHT = LORA_RANDOMIZER_WIDGET_MIN_HEIGHT;
|
||||||
const LORA_CYCLER_WIDGET_MIN_WIDTH = 380;
|
const LORA_CYCLER_WIDGET_MIN_WIDTH = 380;
|
||||||
const LORA_CYCLER_WIDGET_MIN_HEIGHT = 316;
|
const LORA_CYCLER_WIDGET_MIN_HEIGHT = 314;
|
||||||
const LORA_CYCLER_WIDGET_MAX_HEIGHT = LORA_CYCLER_WIDGET_MIN_HEIGHT;
|
const LORA_CYCLER_WIDGET_MAX_HEIGHT = LORA_CYCLER_WIDGET_MIN_HEIGHT;
|
||||||
const JSON_DISPLAY_WIDGET_MIN_WIDTH = 300;
|
const JSON_DISPLAY_WIDGET_MIN_WIDTH = 300;
|
||||||
const JSON_DISPLAY_WIDGET_MIN_HEIGHT = 200;
|
const JSON_DISPLAY_WIDGET_MIN_HEIGHT = 200;
|
||||||
@@ -13681,7 +13681,7 @@ function createLoraCyclerWidget(node) {
|
|||||||
widget.onSetValue(v2);
|
widget.onSetValue(v2);
|
||||||
}
|
}
|
||||||
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
||||||
updateDownstreamLoaders(node);
|
updateDownstreamLoaders$1(node);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
serialize: true,
|
serialize: true,
|
||||||
@@ -13694,7 +13694,7 @@ function createLoraCyclerWidget(node) {
|
|||||||
const oldFilename = internalValue == null ? void 0 : internalValue.current_lora_filename;
|
const oldFilename = internalValue == null ? void 0 : internalValue.current_lora_filename;
|
||||||
internalValue = v2;
|
internalValue = v2;
|
||||||
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
||||||
updateDownstreamLoaders(node);
|
updateDownstreamLoaders$1(node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
node.getPoolConfig = () => getPoolConfigFromConnectedNode(node);
|
node.getPoolConfig = () => getPoolConfigFromConnectedNode(node);
|
||||||
@@ -13805,7 +13805,7 @@ app$1.registerExtension({
|
|||||||
}
|
}
|
||||||
const isRandomizerNode = node.comfyClass === "Lora Randomizer (LoraManager)";
|
const isRandomizerNode = node.comfyClass === "Lora Randomizer (LoraManager)";
|
||||||
const callback = isRandomizerNode ? () => {
|
const callback = isRandomizerNode ? () => {
|
||||||
updateDownstreamLoaders(node);
|
updateDownstreamLoaders$1(node);
|
||||||
} : null;
|
} : null;
|
||||||
return addLorasWidgetCache(node, "loras", { isRandomizerNode }, callback);
|
return addLorasWidgetCache(node, "loras", { isRandomizerNode }, callback);
|
||||||
}
|
}
|
||||||
@@ -13821,7 +13821,7 @@ app$1.registerExtension({
|
|||||||
nodeType.prototype.onNodeCreated = function() {
|
nodeType.prototype.onNodeCreated = function() {
|
||||||
originalOnNodeCreated == null ? void 0 : originalOnNodeCreated.apply(this, arguments);
|
originalOnNodeCreated == null ? void 0 : originalOnNodeCreated.apply(this, arguments);
|
||||||
const nodeSpecificCallback = comfyClass === "Lora Stacker (LoraManager)" ? (activeLoraNames) => updateConnectedTriggerWords(this, activeLoraNames) : void 0;
|
const nodeSpecificCallback = comfyClass === "Lora Stacker (LoraManager)" ? (activeLoraNames) => updateConnectedTriggerWords(this, activeLoraNames) : void 0;
|
||||||
const onModeChange = createModeChangeCallback(this, updateDownstreamLoaders, nodeSpecificCallback);
|
const onModeChange = createModeChangeCallback(this, updateDownstreamLoaders$1, nodeSpecificCallback);
|
||||||
setupModeChangeHandler(this, onModeChange);
|
setupModeChangeHandler(this, onModeChange);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user