mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 13:41:59 +00:00
[automated] Apply ESLint and Oxfmt fixes
This commit is contained in:
@@ -7,22 +7,22 @@
|
||||
* Each test documents which PR/commit it regresses and reproduces
|
||||
* the exact user scenario that triggered the original bug.
|
||||
*/
|
||||
import { expect } from "@playwright/test";
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test, comfyExpect } from "../fixtures/ComfyPage";
|
||||
import { comfyPageFixture as test, comfyExpect } from '../fixtures/ComfyPage'
|
||||
|
||||
test.describe("Workflow Persistence Regressions", () => {
|
||||
test.describe('Workflow Persistence Regressions', () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.settings.setSetting("Comfy.UseNewMenu", "Top");
|
||||
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Top')
|
||||
await comfyPage.settings.setSetting(
|
||||
"Comfy.Workflow.WorkflowTabsPosition",
|
||||
"Sidebar",
|
||||
);
|
||||
});
|
||||
'Comfy.Workflow.WorkflowTabsPosition',
|
||||
'Sidebar'
|
||||
)
|
||||
})
|
||||
|
||||
test.afterEach(async ({ comfyPage }) => {
|
||||
await comfyPage.workflow.setupWorkflowsDirectory({});
|
||||
});
|
||||
await comfyPage.workflow.setupWorkflowsDirectory({})
|
||||
})
|
||||
|
||||
/**
|
||||
* G1: PR #9531 (pythongosssss) — CRITICAL
|
||||
@@ -39,69 +39,69 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Register an extension that calls checkState during
|
||||
* afterConfigureGraph, open two workflows, switch tabs, and verify data.
|
||||
*/
|
||||
test("Switching workflow tabs does not corrupt workflow data via checkState during load (PR #9531)", async ({
|
||||
comfyPage,
|
||||
test('Switching workflow tabs does not corrupt workflow data via checkState during load (PR #9531)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Save first workflow with default nodes
|
||||
await comfyPage.menu.topbar.saveWorkflow("workflow-A");
|
||||
await comfyPage.menu.topbar.saveWorkflow('workflow-A')
|
||||
|
||||
// Get initial node count and types for workflow A
|
||||
const workflowANodeCount = await comfyPage.nodeOps.getNodeCount();
|
||||
const workflowAData = await comfyPage.workflow.getExportedWorkflow();
|
||||
const workflowANodeCount = await comfyPage.nodeOps.getNodeCount()
|
||||
const workflowAData = await comfyPage.workflow.getExportedWorkflow()
|
||||
|
||||
// Create second workflow with different content
|
||||
await comfyPage.command.executeCommand("Comfy.NewBlankWorkflow");
|
||||
await comfyPage.menu.topbar.saveWorkflow("workflow-B");
|
||||
const workflowBNodeCount = await comfyPage.nodeOps.getNodeCount();
|
||||
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
|
||||
await comfyPage.menu.topbar.saveWorkflow('workflow-B')
|
||||
const workflowBNodeCount = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Register an extension that forces checkState during graph configuration
|
||||
// This reproduces the exact scenario from PR #9531
|
||||
await comfyPage.page.evaluate(() => {
|
||||
window.app!.registerExtension({
|
||||
name: "test-checkstate-during-load",
|
||||
name: 'test-checkstate-during-load',
|
||||
async afterConfigureGraph() {
|
||||
const wfStore = (
|
||||
window.app!.extensionManager as unknown as Record<string, unknown>
|
||||
).workflow as Record<string, unknown> | undefined;
|
||||
).workflow as Record<string, unknown> | undefined
|
||||
const activeWorkflow = wfStore?.activeWorkflow as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
| undefined
|
||||
const changeTracker = activeWorkflow?.changeTracker as
|
||||
| { checkState: () => void }
|
||||
| undefined;
|
||||
changeTracker?.checkState();
|
||||
},
|
||||
});
|
||||
});
|
||||
| undefined
|
||||
changeTracker?.checkState()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Switch back to workflow A
|
||||
await tab.switchToWorkflow("workflow-A");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('workflow-A')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify workflow A still has its original nodes (not corrupted by B's data)
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount())
|
||||
.toBe(workflowANodeCount);
|
||||
.toBe(workflowANodeCount)
|
||||
|
||||
// Switch to workflow B
|
||||
await tab.switchToWorkflow("workflow-B");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('workflow-B')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify workflow B still has its original nodes (not corrupted by A's data)
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount())
|
||||
.toBe(workflowBNodeCount);
|
||||
.toBe(workflowBNodeCount)
|
||||
|
||||
// Switch back to A one more time to verify no corruption accumulated
|
||||
await tab.switchToWorkflow("workflow-A");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('workflow-A')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
const restoredData = await comfyPage.workflow.getExportedWorkflow();
|
||||
expect(restoredData.nodes.length).toBe(workflowAData.nodes.length);
|
||||
});
|
||||
const restoredData = await comfyPage.workflow.getExportedWorkflow()
|
||||
expect(restoredData.nodes.length).toBe(workflowAData.nodes.length)
|
||||
})
|
||||
|
||||
/**
|
||||
* G2: Commit 0f763b523 (PR #9533)
|
||||
@@ -113,28 +113,28 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Open two workflows, rapidly switch between them, verify
|
||||
* each tab shows correct content after settling.
|
||||
*/
|
||||
test("Rapid tab switching does not desync workflow and graph state (PR #9533)", async ({
|
||||
comfyPage,
|
||||
test('Rapid tab switching does not desync workflow and graph state (PR #9533)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Save workflow A with default nodes (7 nodes)
|
||||
await comfyPage.menu.topbar.saveWorkflow("rapid-A");
|
||||
const nodeCountA = await comfyPage.nodeOps.getNodeCount();
|
||||
await comfyPage.menu.topbar.saveWorkflow('rapid-A')
|
||||
const nodeCountA = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Create workflow B with a single KSampler
|
||||
await comfyPage.workflow.loadWorkflow("nodes/single_ksampler");
|
||||
await comfyPage.menu.topbar.saveWorkflow("rapid-B");
|
||||
const nodeCountB = await comfyPage.nodeOps.getNodeCount();
|
||||
await comfyPage.workflow.loadWorkflow('nodes/single_ksampler')
|
||||
await comfyPage.menu.topbar.saveWorkflow('rapid-B')
|
||||
const nodeCountB = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Ensure different node counts so we can distinguish
|
||||
expect(nodeCountA).not.toBe(nodeCountB);
|
||||
expect(nodeCountA).not.toBe(nodeCountB)
|
||||
|
||||
// Rapidly switch between tabs multiple times
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await tab.switchToWorkflow("rapid-A");
|
||||
await tab.switchToWorkflow("rapid-B");
|
||||
await tab.switchToWorkflow('rapid-A')
|
||||
await tab.switchToWorkflow('rapid-B')
|
||||
}
|
||||
|
||||
// Wait for everything to settle
|
||||
@@ -148,17 +148,17 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
return !wf?.isBusy
|
||||
},
|
||||
undefined,
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
await comfyPage.nextFrame();
|
||||
{ timeout: 5000 }
|
||||
)
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify we're on workflow B with correct node count
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 5000 })
|
||||
.toBe(nodeCountB);
|
||||
.toBe(nodeCountB)
|
||||
|
||||
// Switch to A and verify
|
||||
await tab.switchToWorkflow("rapid-A");
|
||||
await tab.switchToWorkflow('rapid-A')
|
||||
await comfyPage.page.waitForFunction(
|
||||
() => {
|
||||
const em = window.app?.extensionManager as
|
||||
@@ -167,12 +167,12 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
return !em?.workflow?.isBusy
|
||||
},
|
||||
undefined,
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
{ timeout: 5000 }
|
||||
)
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 5000 })
|
||||
.toBe(nodeCountA);
|
||||
});
|
||||
.toBe(nodeCountA)
|
||||
})
|
||||
|
||||
/**
|
||||
* G3: PR #9380 (kaili-yang)
|
||||
@@ -187,29 +187,29 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Store node outputs on a workflow, switch tabs, switch back,
|
||||
* verify outputs are still present.
|
||||
*/
|
||||
test("Node outputs are preserved when switching workflow tabs (PR #9380)", async ({
|
||||
comfyPage,
|
||||
test('Node outputs are preserved when switching workflow tabs (PR #9380)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Save a workflow
|
||||
await comfyPage.menu.topbar.saveWorkflow("outputs-test");
|
||||
await comfyPage.menu.topbar.saveWorkflow('outputs-test')
|
||||
|
||||
// Simulate node outputs being set (as if execution completed)
|
||||
const firstNode = await comfyPage.nodeOps.getFirstNodeRef();
|
||||
expect(firstNode).toBeTruthy();
|
||||
const nodeId = firstNode!.id;
|
||||
const firstNode = await comfyPage.nodeOps.getFirstNodeRef()
|
||||
expect(firstNode).toBeTruthy()
|
||||
const nodeId = firstNode!.id
|
||||
|
||||
await comfyPage.page.evaluate((id) => {
|
||||
// Simulate outputs like what happens after execution
|
||||
const outputStore = window.app!.nodeOutputs;
|
||||
const outputStore = window.app!.nodeOutputs
|
||||
if (outputStore) {
|
||||
outputStore[id] = {
|
||||
images: [{ filename: "test.png", subfolder: "", type: "output" }],
|
||||
};
|
||||
images: [{ filename: 'test.png', subfolder: '', type: 'output' }]
|
||||
}
|
||||
}
|
||||
}, String(nodeId));
|
||||
}, String(nodeId))
|
||||
|
||||
// Trigger changeTracker to store the state (including outputs)
|
||||
await comfyPage.page.evaluate(() => {
|
||||
@@ -218,30 +218,30 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
{ activeWorkflow?: { changeTracker?: { checkState(): void } } }
|
||||
>
|
||||
em.workflow?.activeWorkflow?.changeTracker?.checkState()
|
||||
});
|
||||
await comfyPage.nextFrame();
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify outputs exist before switching
|
||||
const outputsBefore = await comfyPage.page.evaluate((id) => {
|
||||
return window.app!.nodeOutputs?.[id];
|
||||
}, String(nodeId));
|
||||
expect(outputsBefore).toBeTruthy();
|
||||
return window.app!.nodeOutputs?.[id]
|
||||
}, String(nodeId))
|
||||
expect(outputsBefore).toBeTruthy()
|
||||
|
||||
// Create a new workflow and switch to it
|
||||
await comfyPage.command.executeCommand("Comfy.NewBlankWorkflow");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Switch back to original workflow
|
||||
await tab.switchToWorkflow("outputs-test");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('outputs-test')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify node outputs are preserved
|
||||
const outputsAfter = await comfyPage.page.evaluate((id) => {
|
||||
return window.app!.nodeOutputs?.[id];
|
||||
}, String(nodeId));
|
||||
expect(outputsAfter).toBeTruthy();
|
||||
expect(outputsAfter?.images).toBeDefined();
|
||||
});
|
||||
return window.app!.nodeOutputs?.[id]
|
||||
}, String(nodeId))
|
||||
expect(outputsAfter).toBeTruthy()
|
||||
expect(outputsAfter?.images).toBeDefined()
|
||||
})
|
||||
|
||||
/**
|
||||
* G5: Commit 44bb6f13 (DrJKL)
|
||||
@@ -253,26 +253,26 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Load workflow A (7 nodes) → load workflow B (1 node) →
|
||||
* verify only B's nodes are on the canvas.
|
||||
*/
|
||||
test("Loading a new workflow cleanly replaces the previous graph (commit 44bb6f13)", async ({
|
||||
comfyPage,
|
||||
test('Loading a new workflow cleanly replaces the previous graph (commit 44bb6f13)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Start with default workflow (7 nodes)
|
||||
const defaultNodeCount = await comfyPage.nodeOps.getNodeCount();
|
||||
expect(defaultNodeCount).toBeGreaterThan(1);
|
||||
const defaultNodeCount = await comfyPage.nodeOps.getNodeCount()
|
||||
expect(defaultNodeCount).toBeGreaterThan(1)
|
||||
|
||||
// Load a single-node workflow
|
||||
await comfyPage.workflow.loadWorkflow("nodes/single_ksampler");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.workflow.loadWorkflow('nodes/single_ksampler')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify only the new workflow's nodes are present (no leakage from previous)
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
|
||||
.toBe(1);
|
||||
.toBe(1)
|
||||
|
||||
// Verify the node is the correct type
|
||||
const nodes = await comfyPage.nodeOps.getNodes();
|
||||
expect(nodes[0].type).toBe("KSampler");
|
||||
});
|
||||
const nodes = await comfyPage.nodeOps.getNodes()
|
||||
expect(nodes[0].type).toBe('KSampler')
|
||||
})
|
||||
|
||||
/**
|
||||
* G4: PR #7648 (tomm1e)
|
||||
@@ -285,63 +285,59 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Set widget values on nodes → switch to different workflow →
|
||||
* switch back → verify widget values preserved.
|
||||
*/
|
||||
test("Widget values on nodes are preserved across workflow tab switches (PR #7648)", async ({
|
||||
comfyPage,
|
||||
test('Widget values on nodes are preserved across workflow tab switches (PR #7648)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Load default workflow and save
|
||||
await comfyPage.menu.topbar.saveWorkflow("widget-state-test");
|
||||
await comfyPage.menu.topbar.saveWorkflow('widget-state-test')
|
||||
|
||||
// Get a node and read its widget values
|
||||
const widgetValuesBefore = await comfyPage.page.evaluate(() => {
|
||||
const nodes = window.app!.graph.nodes;
|
||||
const results: Record<string, unknown[]> = {};
|
||||
const nodes = window.app!.graph.nodes
|
||||
const results: Record<string, unknown[]> = {}
|
||||
for (const node of nodes) {
|
||||
if (node.widgets && node.widgets.length > 0) {
|
||||
results[node.id] = node.widgets.map(
|
||||
(w) => ({
|
||||
name: w.name,
|
||||
value: w.value,
|
||||
}),
|
||||
);
|
||||
results[node.id] = node.widgets.map((w) => ({
|
||||
name: w.name,
|
||||
value: w.value
|
||||
}))
|
||||
}
|
||||
}
|
||||
return results;
|
||||
});
|
||||
return results
|
||||
})
|
||||
|
||||
// Verify we captured some widget values
|
||||
expect(Object.keys(widgetValuesBefore).length).toBeGreaterThan(0);
|
||||
expect(Object.keys(widgetValuesBefore).length).toBeGreaterThan(0)
|
||||
|
||||
// Create another workflow
|
||||
await comfyPage.command.executeCommand("Comfy.NewBlankWorkflow");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Switch back
|
||||
await tab.switchToWorkflow("widget-state-test");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('widget-state-test')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Read widget values after switching back
|
||||
const widgetValuesAfter = await comfyPage.page.evaluate(() => {
|
||||
const nodes = window.app!.graph.nodes;
|
||||
const results: Record<string, unknown[]> = {};
|
||||
const nodes = window.app!.graph.nodes
|
||||
const results: Record<string, unknown[]> = {}
|
||||
for (const node of nodes) {
|
||||
if (node.widgets && node.widgets.length > 0) {
|
||||
results[node.id] = node.widgets.map(
|
||||
(w) => ({
|
||||
name: w.name,
|
||||
value: w.value,
|
||||
}),
|
||||
);
|
||||
results[node.id] = node.widgets.map((w) => ({
|
||||
name: w.name,
|
||||
value: w.value
|
||||
}))
|
||||
}
|
||||
}
|
||||
return results;
|
||||
});
|
||||
return results
|
||||
})
|
||||
|
||||
// Verify widget values match
|
||||
expect(widgetValuesAfter).toEqual(widgetValuesBefore);
|
||||
});
|
||||
expect(widgetValuesAfter).toEqual(widgetValuesBefore)
|
||||
})
|
||||
|
||||
/**
|
||||
* G8: PR #9694 (viva-jinyi)
|
||||
@@ -356,61 +352,61 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Load an API-format workflow containing unknown node types →
|
||||
* verify remaining known nodes still load onto the canvas.
|
||||
*/
|
||||
test("API format workflow with missing node types partially loads (PR #9694)", async ({
|
||||
comfyPage,
|
||||
test('API format workflow with missing node types partially loads (PR #9694)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Create an API-format workflow JSON with a mix of known and unknown nodes
|
||||
const apiWorkflow = {
|
||||
"1": {
|
||||
class_type: "KSampler",
|
||||
'1': {
|
||||
class_type: 'KSampler',
|
||||
inputs: {
|
||||
seed: 42,
|
||||
steps: 20,
|
||||
cfg: 8.0,
|
||||
sampler_name: "euler",
|
||||
scheduler: "normal",
|
||||
denoise: 1.0,
|
||||
sampler_name: 'euler',
|
||||
scheduler: 'normal',
|
||||
denoise: 1.0
|
||||
},
|
||||
_meta: { title: "KSampler" },
|
||||
_meta: { title: 'KSampler' }
|
||||
},
|
||||
"2": {
|
||||
class_type: "NonExistentCustomNode_XYZ_12345",
|
||||
'2': {
|
||||
class_type: 'NonExistentCustomNode_XYZ_12345',
|
||||
inputs: {
|
||||
input1: "test",
|
||||
input1: 'test'
|
||||
},
|
||||
_meta: { title: "Missing Node" },
|
||||
_meta: { title: 'Missing Node' }
|
||||
},
|
||||
"3": {
|
||||
class_type: "EmptyLatentImage",
|
||||
'3': {
|
||||
class_type: 'EmptyLatentImage',
|
||||
inputs: {
|
||||
width: 512,
|
||||
height: 512,
|
||||
batch_size: 1,
|
||||
batch_size: 1
|
||||
},
|
||||
_meta: { title: "Empty Latent Image" },
|
||||
},
|
||||
};
|
||||
_meta: { title: 'Empty Latent Image' }
|
||||
}
|
||||
}
|
||||
|
||||
// Load the API format workflow via page.evaluate
|
||||
await comfyPage.page.evaluate(async (workflow) => {
|
||||
await window.app!.loadApiJson(workflow, "test-api-workflow.json");
|
||||
}, apiWorkflow);
|
||||
await comfyPage.nextFrame();
|
||||
await window.app!.loadApiJson(workflow, 'test-api-workflow.json')
|
||||
}, apiWorkflow)
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// The known nodes (KSampler, EmptyLatentImage) should load
|
||||
// The unknown node (NonExistentCustomNode) should be skipped
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount(), { timeout: 3000 })
|
||||
.toBeGreaterThanOrEqual(2);
|
||||
.toBeGreaterThanOrEqual(2)
|
||||
|
||||
// Verify the known node types are present
|
||||
const nodeTypes = await comfyPage.page.evaluate(() => {
|
||||
return window.app!.graph.nodes.map((n: { type: string }) => n.type);
|
||||
});
|
||||
expect(nodeTypes).toContain("KSampler");
|
||||
expect(nodeTypes).toContain("EmptyLatentImage");
|
||||
expect(nodeTypes).not.toContain("NonExistentCustomNode_XYZ_12345");
|
||||
});
|
||||
return window.app!.graph.nodes.map((n: { type: string }) => n.type)
|
||||
})
|
||||
expect(nodeTypes).toContain('KSampler')
|
||||
expect(nodeTypes).toContain('EmptyLatentImage')
|
||||
expect(nodeTypes).not.toContain('NonExistentCustomNode_XYZ_12345')
|
||||
})
|
||||
|
||||
/**
|
||||
* G9: PR #8259
|
||||
@@ -423,24 +419,24 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
*
|
||||
* Reproduction: Verify auxclick event handler is registered on the canvas.
|
||||
*/
|
||||
test("Canvas has auxclick handler to prevent middle-click paste (PR #8259)", async ({
|
||||
comfyPage,
|
||||
test('Canvas has auxclick handler to prevent middle-click paste (PR #8259)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Verify that the canvas element has an auxclick event listener registered
|
||||
// by checking that middle-clicking does not trigger paste behavior
|
||||
const initialNodeCount = await comfyPage.nodeOps.getNodeCount();
|
||||
const initialNodeCount = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Simulate a middle click (auxclick) on the canvas
|
||||
await comfyPage.canvas.click({
|
||||
button: "middle",
|
||||
position: { x: 100, y: 100 },
|
||||
});
|
||||
await comfyPage.nextFrame();
|
||||
button: 'middle',
|
||||
position: { x: 100, y: 100 }
|
||||
})
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify no nodes were duplicated
|
||||
const nodeCountAfter = await comfyPage.nodeOps.getNodeCount();
|
||||
expect(nodeCountAfter).toBe(initialNodeCount);
|
||||
});
|
||||
const nodeCountAfter = await comfyPage.nodeOps.getNodeCount()
|
||||
expect(nodeCountAfter).toBe(initialNodeCount)
|
||||
})
|
||||
|
||||
/**
|
||||
* G10: PR #8715 (jtydhr88)
|
||||
@@ -455,24 +451,24 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Verify exported workflow does not contain blob: or
|
||||
* transient URLs in any widget values.
|
||||
*/
|
||||
test("Exported workflow does not contain transient blob: URLs (PR #8715)", async ({
|
||||
comfyPage,
|
||||
test('Exported workflow does not contain transient blob: URLs (PR #8715)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Load default workflow
|
||||
const exportedWorkflow = await comfyPage.workflow.getExportedWorkflow();
|
||||
const exportedWorkflow = await comfyPage.workflow.getExportedWorkflow()
|
||||
|
||||
// Check all nodes' widget values for blob: URLs
|
||||
for (const node of exportedWorkflow.nodes) {
|
||||
if (node.widgets_values && Array.isArray(node.widgets_values)) {
|
||||
for (const value of node.widgets_values) {
|
||||
if (typeof value === "string") {
|
||||
expect(value).not.toMatch(/^blob:/);
|
||||
expect(value).not.toMatch(/^https?:\/\/.*\/api\/view/);
|
||||
if (typeof value === 'string') {
|
||||
expect(value).not.toMatch(/^blob:/)
|
||||
expect(value).not.toMatch(/^https?:\/\/.*\/api\/view/)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/**
|
||||
* G11: PR #8963 (Myestery)
|
||||
@@ -484,33 +480,33 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Change locale setting and verify templates update.
|
||||
* (Simplified test: verify locale change doesn't error and settings persist)
|
||||
*/
|
||||
test("Changing locale does not break workflow operations (PR #8963)", async ({
|
||||
comfyPage,
|
||||
test('Changing locale does not break workflow operations (PR #8963)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Save current workflow
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
await comfyPage.menu.topbar.saveWorkflow("locale-test");
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
await comfyPage.menu.topbar.saveWorkflow('locale-test')
|
||||
|
||||
// Get initial node count
|
||||
const initialNodeCount = await comfyPage.nodeOps.getNodeCount();
|
||||
const initialNodeCount = await comfyPage.nodeOps.getNodeCount()
|
||||
|
||||
// Change locale (this should trigger template reload)
|
||||
await comfyPage.settings.setSetting("Comfy.Locale", "zh");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.settings.setSetting('Comfy.Locale', 'zh')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Change back to English
|
||||
await comfyPage.settings.setSetting("Comfy.Locale", "en");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.settings.setSetting('Comfy.Locale', 'en')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Verify the current workflow is still intact
|
||||
await expect
|
||||
.poll(() => comfyPage.nodeOps.getNodeCount())
|
||||
.toBe(initialNodeCount);
|
||||
.toBe(initialNodeCount)
|
||||
|
||||
// Verify workflow is still accessible
|
||||
await expect.poll(() => tab.getActiveWorkflowName()).toBe("locale-test");
|
||||
});
|
||||
await expect.poll(() => tab.getActiveWorkflowName()).toBe('locale-test')
|
||||
})
|
||||
|
||||
/**
|
||||
* G1 extended: Verify the ChangeTracker.isLoadingGraph guard works correctly.
|
||||
@@ -518,14 +514,14 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* This test directly verifies the fix mechanism from PR #9531 by checking
|
||||
* that checkState is a no-op while a graph is being loaded.
|
||||
*/
|
||||
test("checkState is blocked during graph loading (PR #9531 guard)", async ({
|
||||
comfyPage,
|
||||
test('checkState is blocked during graph loading (PR #9531 guard)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Save workflow with known state
|
||||
await comfyPage.menu.topbar.saveWorkflow("guard-test");
|
||||
await comfyPage.menu.topbar.saveWorkflow('guard-test')
|
||||
|
||||
// Verify isLoadingGraph is false during normal operation
|
||||
const isLoadingNormally = await comfyPage.page.evaluate(() => {
|
||||
@@ -538,26 +534,26 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
}
|
||||
}
|
||||
>
|
||||
const activeWf = em.workflow?.activeWorkflow;
|
||||
if (!activeWf?.changeTracker) return null;
|
||||
const activeWf = em.workflow?.activeWorkflow
|
||||
if (!activeWf?.changeTracker) return null
|
||||
// checkState should work normally (isLoadingGraph should be false)
|
||||
const undoBefore = activeWf.changeTracker.undoQueue.length;
|
||||
return { undoBefore, isLoading: false };
|
||||
});
|
||||
expect(isLoadingNormally).toBeTruthy();
|
||||
const undoBefore = activeWf.changeTracker.undoQueue.length
|
||||
return { undoBefore, isLoading: false }
|
||||
})
|
||||
expect(isLoadingNormally).toBeTruthy()
|
||||
|
||||
// Verify that during a workflow load, the graph doesn't get corrupted
|
||||
// by making a modification, saving, loading another workflow, then
|
||||
// switching back
|
||||
const node = await comfyPage.nodeOps.getFirstNodeRef();
|
||||
const node = await comfyPage.nodeOps.getFirstNodeRef()
|
||||
if (node) {
|
||||
await node.click("title");
|
||||
await node.click("collapse");
|
||||
await comfyExpect(node).toBeCollapsed();
|
||||
await node.click('title')
|
||||
await node.click('collapse')
|
||||
await comfyExpect(node).toBeCollapsed()
|
||||
}
|
||||
|
||||
// Save modified state (workflow already named, use Ctrl+S to avoid dialog)
|
||||
await comfyPage.page.keyboard.press("Control+s");
|
||||
await comfyPage.page.keyboard.press('Control+s')
|
||||
await comfyPage.page.waitForFunction(
|
||||
() => {
|
||||
const em = window.app?.extensionManager as
|
||||
@@ -566,29 +562,29 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
return !em?.workflow?.isBusy
|
||||
},
|
||||
undefined,
|
||||
{ timeout: 3000 },
|
||||
);
|
||||
{ timeout: 3000 }
|
||||
)
|
||||
|
||||
// Switch to another workflow
|
||||
await comfyPage.command.executeCommand("Comfy.NewBlankWorkflow");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Switch back — during this load, checkState must not corrupt data
|
||||
await tab.switchToWorkflow("guard-test");
|
||||
await comfyPage.nextFrame();
|
||||
await tab.switchToWorkflow('guard-test')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// The collapsed state should be preserved
|
||||
if (node) {
|
||||
const nodeId = node.id;
|
||||
const nodeId = node.id
|
||||
const isStillCollapsed = await comfyPage.page.evaluate((id) => {
|
||||
const n = window.app!.graph.nodes.find(
|
||||
(node) => String(node.id) === String(id),
|
||||
);
|
||||
return n?.flags?.collapsed === true;
|
||||
}, nodeId);
|
||||
expect(isStillCollapsed).toBe(true);
|
||||
(node) => String(node.id) === String(id)
|
||||
)
|
||||
return n?.flags?.collapsed === true
|
||||
}, nodeId)
|
||||
expect(isStillCollapsed).toBe(true)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/**
|
||||
* G2 extended: Verify workflow data integrity across multiple save/load cycles.
|
||||
@@ -596,28 +592,28 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Tests that node links are preserved correctly through serialization
|
||||
* roundtrips, which is the core concern of the graph sync bugs.
|
||||
*/
|
||||
test("Node links survive save/load/switch cycles (graph sync integrity)", async ({
|
||||
comfyPage,
|
||||
test('Node links survive save/load/switch cycles (graph sync integrity)', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const tab = comfyPage.menu.workflowsTab;
|
||||
await tab.open();
|
||||
const tab = comfyPage.menu.workflowsTab
|
||||
await tab.open()
|
||||
|
||||
// Get link count from default workflow
|
||||
const linkCountBefore = await comfyPage.page.evaluate(() => {
|
||||
return window.app!.graph.links
|
||||
? Object.keys(window.app!.graph.links).length
|
||||
: 0;
|
||||
});
|
||||
expect(linkCountBefore).toBeGreaterThan(0);
|
||||
: 0
|
||||
})
|
||||
expect(linkCountBefore).toBeGreaterThan(0)
|
||||
|
||||
// Save the workflow
|
||||
await comfyPage.menu.topbar.saveWorkflow("links-test");
|
||||
await comfyPage.menu.topbar.saveWorkflow('links-test')
|
||||
|
||||
// Create new workflow and switch back
|
||||
await comfyPage.command.executeCommand("Comfy.NewBlankWorkflow");
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.command.executeCommand('Comfy.NewBlankWorkflow')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
await tab.switchToWorkflow("links-test");
|
||||
await tab.switchToWorkflow('links-test')
|
||||
await comfyPage.page.waitForFunction(
|
||||
() => {
|
||||
const em = window.app?.extensionManager as
|
||||
@@ -626,17 +622,17 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
return !em?.workflow?.isBusy
|
||||
},
|
||||
undefined,
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
{ timeout: 5000 }
|
||||
)
|
||||
|
||||
// Verify links are intact
|
||||
const linkCountAfter = await comfyPage.page.evaluate(() => {
|
||||
return window.app!.graph.links
|
||||
? Object.keys(window.app!.graph.links).length
|
||||
: 0;
|
||||
});
|
||||
expect(linkCountAfter).toBe(linkCountBefore);
|
||||
});
|
||||
: 0
|
||||
})
|
||||
expect(linkCountAfter).toBe(linkCountBefore)
|
||||
})
|
||||
|
||||
/**
|
||||
* G12: Commits 91f197d9d + a1b7e57bc
|
||||
@@ -648,40 +644,37 @@ test.describe("Workflow Persistence Regressions", () => {
|
||||
* Reproduction: Store panel sizes in localStorage, reload, verify sizes
|
||||
* are normalized and don't drift.
|
||||
*/
|
||||
test("Splitter panel sizes persist correctly in localStorage", async ({
|
||||
comfyPage,
|
||||
test('Splitter panel sizes persist correctly in localStorage', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Set known panel sizes via localStorage
|
||||
await comfyPage.page.evaluate(() => {
|
||||
// Normalize: sizes should sum to 100
|
||||
const sizes = [30, 70];
|
||||
localStorage.setItem(
|
||||
"Comfy.Splitter.MainSplitter",
|
||||
JSON.stringify(sizes),
|
||||
);
|
||||
});
|
||||
const sizes = [30, 70]
|
||||
localStorage.setItem('Comfy.Splitter.MainSplitter', JSON.stringify(sizes))
|
||||
})
|
||||
|
||||
// Reload the page
|
||||
await comfyPage.setup({ clearStorage: false });
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.setup({ clearStorage: false })
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Read back the stored sizes
|
||||
const storedSizes = await comfyPage.page.evaluate(() => {
|
||||
const raw = localStorage.getItem("Comfy.Splitter.MainSplitter");
|
||||
return raw ? JSON.parse(raw) : null;
|
||||
});
|
||||
const raw = localStorage.getItem('Comfy.Splitter.MainSplitter')
|
||||
return raw ? JSON.parse(raw) : null
|
||||
})
|
||||
|
||||
// If sizes are stored, they should be valid (sum to ~100, no NaN, no negative)
|
||||
if (storedSizes && Array.isArray(storedSizes)) {
|
||||
for (const size of storedSizes) {
|
||||
expect(typeof size).toBe("number");
|
||||
expect(size).toBeGreaterThanOrEqual(0);
|
||||
expect(size).not.toBeNaN();
|
||||
expect(typeof size).toBe('number')
|
||||
expect(size).toBeGreaterThanOrEqual(0)
|
||||
expect(size).not.toBeNaN()
|
||||
}
|
||||
const total = storedSizes.reduce((a: number, b: number) => a + b, 0);
|
||||
const total = storedSizes.reduce((a: number, b: number) => a + b, 0)
|
||||
// Allow some tolerance for rounding
|
||||
expect(total).toBeGreaterThan(90);
|
||||
expect(total).toBeLessThanOrEqual(101);
|
||||
expect(total).toBeGreaterThan(90)
|
||||
expect(total).toBeLessThanOrEqual(101)
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user