diff --git a/browser_tests/ComfyPage.ts b/browser_tests/ComfyPage.ts index 6bc078da..5cde8632 100644 --- a/browser_tests/ComfyPage.ts +++ b/browser_tests/ComfyPage.ts @@ -707,7 +707,6 @@ export class ComfyPage { }) await this.canvas.press('Control+a') const node = await this.getFirstNodeRef() - expect(node).not.toBeNull() await node!.clickContextMenuOption('Convert to Group Node') await this.nextFrame() } @@ -874,7 +873,7 @@ class NodeReference { await this.clickContextMenuOption('Convert to Group Node') await this.comfyPage.nextFrame() const nodes = await this.comfyPage.getNodeRefsByType( - `workflow/${groupNodeName}` + `workflow>${groupNodeName}` ) if (nodes.length !== 1) { throw new Error(`Did not find single group node (found=${nodes.length})`) diff --git a/browser_tests/groupNode.spec.ts b/browser_tests/groupNode.spec.ts index dcd12a14..f0cd8d8a 100644 --- a/browser_tests/groupNode.spec.ts +++ b/browser_tests/groupNode.spec.ts @@ -7,36 +7,82 @@ test.describe('Group Node', () => { }) test.describe('Node library sidebar', () => { + const groupNodeName = 'DefautWorkflowGroupNode' + const groupNodeCategory = 'group nodes>workflow' + const groupNodeBookmarkName = `workflow>${groupNodeName}` + let libraryTab + test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') + libraryTab = comfyPage.menu.nodeLibraryTab + await comfyPage.convertAllNodesToGroupNode(groupNodeName) + await libraryTab.open() }) test('Is added to node library sidebar', async ({ comfyPage }) => { - const groupNodeName = 'DefautWorkflowGroupNode' - await comfyPage.convertAllNodesToGroupNode(groupNodeName) - const tab = comfyPage.menu.nodeLibraryTab - await tab.open() - expect(await tab.getFolder('group nodes').count()).toBe(1) + expect(await libraryTab.getFolder('group nodes').count()).toBe(1) }) test('Can be added to canvas using node library sidebar', async ({ comfyPage }) => { - const groupNodeName = 'DefautWorkflowGroupNode' - await comfyPage.convertAllNodesToGroupNode(groupNodeName) const initialNodeCount = await comfyPage.getGraphNodesCount() // Add group node from node library sidebar - const tab = comfyPage.menu.nodeLibraryTab - await tab.open() - await tab.getFolder('group nodes').click() - await tab.getFolder('workflow').click() - await tab.getFolder('workflow').last().click() - await tab.getNode(groupNodeName).click() + await libraryTab.getFolder(groupNodeCategory).first().click() + await libraryTab.getNode(groupNodeName).first().click() // Verify the node is added to the canvas expect(await comfyPage.getGraphNodesCount()).toBe(initialNodeCount + 1) }) + + test('Can be bookmarked and unbookmarked', async ({ comfyPage }) => { + await libraryTab.getFolder(groupNodeCategory).click() + await libraryTab + .getNode(groupNodeName) + .locator('.bookmark-button') + .first() + .click() + + // Verify the node is added to the bookmarks tab + expect( + await comfyPage.getSetting('Comfy.NodeLibrary.Bookmarks.V2') + ).toEqual([groupNodeBookmarkName]) + // Verify the bookmark node with the same name is added to the tree + expect(await libraryTab.getNode(groupNodeName).count()).not.toBe(0) + + // Unbookmark the node + await libraryTab + .getNode(groupNodeName) + .locator('.bookmark-button') + .first() + .click() + + // Verify the node is removed from the bookmarks tab + expect( + await comfyPage.getSetting('Comfy.NodeLibrary.Bookmarks.V2') + ).toHaveLength(0) + await comfyPage.setSetting('Comfy.NodeLibrary.Bookmarks.V2', []) + }) + + test('Displays preview on bookmark hover', async ({ comfyPage }) => { + await libraryTab.getFolder(groupNodeCategory).click() + await libraryTab + .getNode(groupNodeName) + .locator('.bookmark-button') + .first() + .click() + await comfyPage.page.hover('.p-tree-node-label.tree-explorer-node-label') + expect(await comfyPage.page.isVisible('.node-lib-node-preview')).toBe( + true + ) + await libraryTab + .getNode(groupNodeName) + .locator('.bookmark-button') + .first() + .click() + await comfyPage.setSetting('Comfy.NodeLibrary.Bookmarks.V2', []) + }) }) test('Can be added to canvas using search', async ({ comfyPage }) => { diff --git a/src/extensions/core/groupNode.ts b/src/extensions/core/groupNode.ts index 34e743dd..31d662ab 100644 --- a/src/extensions/core/groupNode.ts +++ b/src/extensions/core/groupNode.ts @@ -15,7 +15,7 @@ const Workflow = { InWorkflow: 2 }, isInUseGroupNode(name) { - const id = `workflow/${name}` + const id = `workflow>${name}` // Check if lready registered/in use in this workflow if (app.graph.extra?.groupNodes?.[name]) { if (app.graph.nodes.find((n) => n.type === id)) { @@ -191,9 +191,9 @@ export class GroupNodeConfig { output_name: [], output_is_list: [], output_is_hidden: [], - name: source + '/' + this.name, + name: source + '>' + this.name, display_name: this.name, - category: 'group nodes' + ('/' + source), + category: 'group nodes' + ('>' + source), input: { required: {} }, description: `Group node combining ${this.nodeData.nodes .map((n) => n.type) @@ -216,7 +216,7 @@ export class GroupNodeConfig { p() } this.#convertedToProcess = null - await app.registerNodeDef('workflow/' + this.name, this.nodeDef) + await app.registerNodeDef('workflow>' + this.name, this.nodeDef) useNodeDefStore().addNodeDef(this.nodeDef) } @@ -1380,7 +1380,7 @@ export class GroupNodeHandler { const config = new GroupNodeConfig(name, nodeData) await config.registerType() - const groupNode = LiteGraph.createNode(`workflow/${name}`) + const groupNode = LiteGraph.createNode(`workflow>${name}`) // Reuse the existing nodes for this instance groupNode.setInnerNodes(builder.nodes) groupNode[GROUP].populateWidgets() diff --git a/src/extensions/core/groupNodeManage.ts b/src/extensions/core/groupNodeManage.ts index 933353fe..cf68be0b 100644 --- a/src/extensions/core/groupNodeManage.ts +++ b/src/extensions/core/groupNodeManage.ts @@ -102,7 +102,7 @@ export class ManageGroupDialog extends ComfyDialog { getGroupData() { this.groupNodeType = - LiteGraph.registered_node_types['workflow/' + this.selectedGroup] + LiteGraph.registered_node_types['workflow>' + this.selectedGroup] this.groupNodeDef = this.groupNodeType.nodeData this.groupData = GroupNodeHandler.getGroupData(this.groupNodeType) } @@ -367,7 +367,7 @@ export class ManageGroupDialog extends ComfyDialog { groupNodes.map((g) => $el('option', { textContent: g, - selected: 'workflow/' + g === type, + selected: 'workflow>' + g === type, value: g }) ) @@ -389,7 +389,7 @@ export class ManageGroupDialog extends ComfyDialog { { onclick: (e) => { const node = app.graph.nodes.find( - (n) => n.type === 'workflow/' + this.selectedGroup + (n) => n.type === 'workflow>' + this.selectedGroup ) if (node) { alert( @@ -403,7 +403,7 @@ export class ManageGroupDialog extends ComfyDialog { ) ) { delete app.graph.extra.groupNodes[this.selectedGroup] - LiteGraph.unregisterNodeType('workflow/' + this.selectedGroup) + LiteGraph.unregisterNodeType('workflow>' + this.selectedGroup) } this.show() } @@ -476,7 +476,7 @@ export class ManageGroupDialog extends ComfyDialog { }, {}) } - const nodes = nodesByType['workflow/' + g] + const nodes = nodesByType['workflow>' + g] if (nodes) recreateNodes.push(...nodes) } @@ -503,7 +503,7 @@ export class ManageGroupDialog extends ComfyDialog { this.element.replaceChildren(outer) this.changeGroup( - type ? groupNodes.find((g) => 'workflow/' + g === type) : groupNodes[0] + type ? groupNodes.find((g) => 'workflow>' + g === type) : groupNodes[0] ) this.element.showModal() diff --git a/tests-ui/tests/groupNode.test.ts b/tests-ui/tests/groupNode.test.ts index a206cc8d..894954bb 100644 --- a/tests-ui/tests/groupNode.test.ts +++ b/tests-ui/tests/groupNode.test.ts @@ -46,7 +46,7 @@ describe('group node', () => { expect(n.isRemoved).toBeTruthy() } - expect(groupNode.type).toEqual('workflow/' + name) + expect(groupNode.type).toEqual('workflow>' + name) return graph.find(groupNode) } @@ -520,7 +520,7 @@ describe('group node', () => { group1.menu.Clone.call() expect(app.graph.nodes).toHaveLength(4) const group2 = graph.find(app.graph.nodes[3]) - expect(group2.node.type).toEqual('workflow/test') + expect(group2.node.type).toEqual('workflow>test') expect(group2.id).not.toEqual(group1.id) group1.outputs.VAE.connectTo(group2.inputs.VAE) @@ -681,7 +681,7 @@ describe('group node', () => { group1.menu.Clone.call() expect(app.graph.nodes).toHaveLength(3) const group2 = graph.find(app.graph.nodes[2]) - expect(group2.node.type).toEqual('workflow/test') + expect(group2.node.type).toEqual('workflow>test') expect(group2.id).not.toEqual(group1.id) // Reconnect ckpt @@ -741,7 +741,7 @@ describe('group node', () => { resetEnv: true })) // Ensure the node isnt registered - expect(() => ez['workflow/test']).toThrow() + expect(() => ez['workflow>test']).toThrow() // Reload the workflow await app.loadGraphData(JSON.parse(workflow)) @@ -768,7 +768,7 @@ describe('group node', () => { nodes: [ { id: 3, - type: 'workflow/testerror' + type: 'workflow>testerror' } ], links: [], @@ -796,7 +796,7 @@ describe('group node', () => { expect(call).toContain('the following node types were not found') expect(call).toContain('NotKSampler') expect(call).toContain('NotVAEDecode') - expect(call).toContain('workflow/testerror') + expect(call).toContain('workflow>testerror') }) test('maintains widget inputs on conversion back to nodes', async () => { const { ez, graph, app } = await start()