244 lines
8.0 KiB
TypeScript
244 lines
8.0 KiB
TypeScript
// @vitest-environment happy-dom
|
|
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { setComfyApp } from "../app/comfyApiBridge.js";
|
|
import { findWorkflowNode, resolveAssetWorkflow } from "../features/viewer/workflowGraphMap/workflowGraphMapData.js";
|
|
import {
|
|
copyNodeJson,
|
|
importNodeToCurrentGraph,
|
|
transferNodeParamsToSelectedCanvasNode,
|
|
} from "../features/viewer/workflowGraphMap/workflowGraphMapActions.js";
|
|
|
|
describe("workflow graph map actions", () => {
|
|
beforeEach(() => {
|
|
setComfyApp({
|
|
canvas: {
|
|
selected_nodes: {},
|
|
setDirty: vi.fn(),
|
|
draw: vi.fn(),
|
|
},
|
|
graph: {
|
|
setDirtyCanvas: vi.fn(),
|
|
change: vi.fn(),
|
|
},
|
|
});
|
|
});
|
|
|
|
it("transfers source widget values to the selected canvas node by widget name", () => {
|
|
const target = {
|
|
id: 104,
|
|
type: "WanMoekSamplerAdvanced",
|
|
widgets: [
|
|
{ name: "boundary", type: "float", value: 0 },
|
|
{ name: "add_noise", type: "combo", value: "disable" },
|
|
{ name: "noise_seed", type: "int", value: 1 },
|
|
{ name: "control_after_generate", type: "combo", value: "fixed" },
|
|
{ name: "steps", type: "int", value: 1 },
|
|
],
|
|
};
|
|
const app = setComfyApp({
|
|
canvas: {
|
|
selected_nodes: { 104: target },
|
|
setDirty: vi.fn(),
|
|
draw: vi.fn(),
|
|
},
|
|
graph: {
|
|
setDirtyCanvas: vi.fn(),
|
|
change: vi.fn(),
|
|
},
|
|
});
|
|
|
|
const result = transferNodeParamsToSelectedCanvasNode({
|
|
id: 12,
|
|
type: "WanMoekSamplerAdvanced",
|
|
inputs: [
|
|
{ name: "model_high_noise", link: 1 },
|
|
{ name: "positive", link: 2 },
|
|
{ name: "boundary", widget: true },
|
|
{ name: "add_noise", widget: true },
|
|
{ name: "noise_seed", widget: true },
|
|
{ name: "control_after_generate", widget: true },
|
|
{ name: "steps", widget: true },
|
|
],
|
|
widgets_values: [0.9, "enable", 131289120546304, "randomize", 20],
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.count).toBe(5);
|
|
expect(target.widgets.map((widget) => widget.value)).toEqual([
|
|
0.9,
|
|
"enable",
|
|
131289120546304,
|
|
"randomize",
|
|
20,
|
|
]);
|
|
expect(app.canvas.setDirty).toHaveBeenCalled();
|
|
expect(app.graph.change).toHaveBeenCalled();
|
|
});
|
|
|
|
it("transfers prompt-enriched subgraph sampler values instead of ambiguous widgets_values", () => {
|
|
const target = {
|
|
id: 3,
|
|
type: "KSampler",
|
|
widgets: [
|
|
{ name: "seed", type: "number", value: 0 },
|
|
{ name: "control_after_generate", type: "combo", value: "fixed" },
|
|
{ name: "steps", type: "number", value: 1 },
|
|
{ name: "cfg", type: "number", value: 0 },
|
|
{ name: "sampler_name", type: "combo", value: "euler" },
|
|
{ name: "scheduler", type: "combo", value: "normal" },
|
|
{ name: "denoise", type: "number", value: 0 },
|
|
],
|
|
};
|
|
setComfyApp({
|
|
canvas: {
|
|
selected_nodes: { 3: target },
|
|
setDirty: vi.fn(),
|
|
draw: vi.fn(),
|
|
},
|
|
graph: {
|
|
setDirtyCanvas: vi.fn(),
|
|
change: vi.fn(),
|
|
},
|
|
});
|
|
const workflow = _makePromptEnrichedSamplerWorkflow();
|
|
|
|
const result = transferNodeParamsToSelectedCanvasNode(findWorkflowNode(workflow, "95::3"));
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.count).toBe(6);
|
|
expect(target.widgets.map((widget) => widget.value)).toEqual([
|
|
1088132929177955,
|
|
"fixed",
|
|
8,
|
|
1,
|
|
"res_multistep",
|
|
"simple",
|
|
1,
|
|
]);
|
|
});
|
|
|
|
it("copies prompt-enriched sampler nodes with normalized widgets and no internal fields", async () => {
|
|
const writeText = vi.fn().mockResolvedValue(undefined);
|
|
Object.defineProperty(navigator, "clipboard", {
|
|
configurable: true,
|
|
value: { writeText },
|
|
});
|
|
const workflow = _makePromptEnrichedSamplerWorkflow();
|
|
const node = findWorkflowNode(workflow, "95::3");
|
|
|
|
await expect(copyNodeJson(node)).resolves.toBe(true);
|
|
|
|
const copied = JSON.parse(writeText.mock.calls[0][0]);
|
|
expect(copied.widgets_values).toEqual([
|
|
1088132929177955,
|
|
"randomize",
|
|
8,
|
|
1,
|
|
"res_multistep",
|
|
"simple",
|
|
1,
|
|
]);
|
|
expect(copied._mjrPromptInputs).toBeUndefined();
|
|
expect(copied._mjrSubgraphProxyParams).toBeUndefined();
|
|
});
|
|
|
|
it("imports a workflow node through the host adapter node factory", () => {
|
|
const created = {
|
|
type: "KSampler",
|
|
configure: vi.fn(function configure(payload) {
|
|
Object.assign(this, payload);
|
|
}),
|
|
};
|
|
const graph = {
|
|
add: vi.fn(),
|
|
setDirtyCanvas: vi.fn(),
|
|
change: vi.fn(),
|
|
};
|
|
const app = setComfyApp({
|
|
LiteGraph: {
|
|
createNode: vi.fn((type) => (type === "KSampler" ? created : null)),
|
|
},
|
|
canvas: {
|
|
selected_nodes: {},
|
|
setDirty: vi.fn(),
|
|
draw: vi.fn(),
|
|
},
|
|
graph,
|
|
});
|
|
|
|
expect(
|
|
importNodeToCurrentGraph({
|
|
id: 12,
|
|
type: "KSampler",
|
|
pos: [10, 20],
|
|
widgets_values: [1, "fixed"],
|
|
}),
|
|
).toBe(true);
|
|
|
|
expect(app.LiteGraph.createNode).toHaveBeenCalledWith("KSampler");
|
|
expect(created.configure).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
type: "KSampler",
|
|
pos: [42, 52],
|
|
widgets_values: [1, "fixed"],
|
|
}),
|
|
);
|
|
expect(created.id).toBeUndefined();
|
|
expect(graph.add).toHaveBeenCalledWith(created);
|
|
});
|
|
});
|
|
|
|
function _makePromptEnrichedSamplerWorkflow() {
|
|
return resolveAssetWorkflow({
|
|
workflow: {
|
|
nodes: [
|
|
{
|
|
id: 95,
|
|
type: "c20beb1e-2a45-4872-913e-21018c09c578",
|
|
},
|
|
],
|
|
definitions: {
|
|
subgraphs: [
|
|
{
|
|
id: "c20beb1e-2a45-4872-913e-21018c09c578",
|
|
nodes: [
|
|
{
|
|
id: 3,
|
|
type: "KSampler",
|
|
inputs: [
|
|
{ name: "seed", type: "INT", link: 71, widget: { name: "seed" } },
|
|
{ name: "steps", type: "INT", link: 72, widget: { name: "steps" } },
|
|
],
|
|
widgets_values: [
|
|
1088132929177955,
|
|
"randomize",
|
|
8,
|
|
1,
|
|
"res_multistep",
|
|
"simple",
|
|
1,
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
prompt: {
|
|
"95:3": {
|
|
class_type: "KSampler",
|
|
inputs: {
|
|
seed: 1088132929177955,
|
|
steps: 8,
|
|
cfg: 1,
|
|
sampler_name: "res_multistep",
|
|
scheduler: "simple",
|
|
denoise: 1,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|