mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
Merge branch 'main' into bl/assets-sidebar-test-foundation
This commit is contained in:
1
.github/workflows/ci-tests-unit.yaml
vendored
1
.github/workflows/ci-tests-unit.yaml
vendored
@@ -31,4 +31,5 @@ jobs:
|
||||
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3
|
||||
with:
|
||||
files: coverage/lcov.info
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: false
|
||||
|
||||
2
.github/workflows/release-version-bump.yaml
vendored
2
.github/workflows/release-version-bump.yaml
vendored
@@ -144,6 +144,8 @@ jobs:
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
|
||||
@@ -20,6 +20,10 @@ export class ContextMenu {
|
||||
await this.page.getByRole('menuitem', { name }).click()
|
||||
}
|
||||
|
||||
async clickMenuItemExact(name: string): Promise<void> {
|
||||
await this.page.getByRole('menuitem', { name, exact: true }).click()
|
||||
}
|
||||
|
||||
async clickLitegraphMenuItem(name: string): Promise<void> {
|
||||
await this.page.locator(`.litemenu-entry:has-text("${name}")`).click()
|
||||
}
|
||||
@@ -48,6 +52,18 @@ export class ContextMenu {
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a Vue node by clicking its header, then right-click to open
|
||||
* the context menu. Vue nodes require a selection click before the
|
||||
* right-click so the correct per-node menu items appear.
|
||||
*/
|
||||
async openForVueNode(header: Locator): Promise<this> {
|
||||
await header.click()
|
||||
await header.click({ button: 'right' })
|
||||
await this.primeVueMenu.waitFor({ state: 'visible' })
|
||||
return this
|
||||
}
|
||||
|
||||
async waitForHidden(): Promise<void> {
|
||||
const waitIfExists = async (locator: Locator, menuName: string) => {
|
||||
const count = await locator.count()
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
comfyExpect as expect,
|
||||
comfyPageFixture as test
|
||||
} from '../../fixtures/ComfyPage'
|
||||
import type { ComfyPage } from '../../fixtures/ComfyPage'
|
||||
|
||||
async function openVueNodeContextMenu(comfyPage: ComfyPage, nodeTitle: string) {
|
||||
const fixture = await comfyPage.vueNodes.getFixtureByTitle(nodeTitle)
|
||||
await comfyPage.contextMenu.openForVueNode(fixture.header)
|
||||
}
|
||||
|
||||
test.describe(
|
||||
'Subgraph Duplicate Independent Values',
|
||||
{ tag: ['@slow', '@subgraph'] },
|
||||
() => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.settings.setSetting('Comfy.VueNodes.Enabled', true)
|
||||
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Top')
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
})
|
||||
|
||||
test('Duplicated subgraphs maintain independent widget values', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const clipNodeTitle = 'CLIP Text Encode (Prompt)'
|
||||
|
||||
// Convert first CLIP Text Encode node to subgraph
|
||||
await openVueNodeContextMenu(comfyPage, clipNodeTitle)
|
||||
await comfyPage.contextMenu.clickMenuItemExact('Convert to Subgraph')
|
||||
await comfyPage.nextFrame()
|
||||
const subgraphNode = comfyPage.vueNodes.getNodeByTitle('New Subgraph')
|
||||
await expect(subgraphNode).toBeVisible()
|
||||
|
||||
// Duplicate the subgraph
|
||||
await openVueNodeContextMenu(comfyPage, 'New Subgraph')
|
||||
await comfyPage.contextMenu.clickMenuItemExact('Duplicate')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// Capture both subgraph node IDs
|
||||
const subgraphNodes = comfyPage.vueNodes.getNodeByTitle('New Subgraph')
|
||||
await expect(subgraphNodes).toHaveCount(2)
|
||||
const nodeIds = await subgraphNodes.evaluateAll((nodes) =>
|
||||
nodes
|
||||
.map((n) => n.getAttribute('data-node-id'))
|
||||
.filter((id): id is string => id !== null)
|
||||
)
|
||||
const [nodeId1, nodeId2] = nodeIds
|
||||
|
||||
// Enter first subgraph, set text widget value
|
||||
await comfyPage.vueNodes.enterSubgraph(nodeId1)
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
const textarea1 = comfyPage.vueNodes
|
||||
.getNodeByTitle(clipNodeTitle)
|
||||
.first()
|
||||
.getByRole('textbox', { name: 'text' })
|
||||
await textarea1.fill('subgraph1_value')
|
||||
await expect(textarea1).toHaveValue('subgraph1_value')
|
||||
await comfyPage.subgraph.exitViaBreadcrumb()
|
||||
|
||||
// Enter second subgraph, set text widget value
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
await comfyPage.vueNodes.enterSubgraph(nodeId2)
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
const textarea2 = comfyPage.vueNodes
|
||||
.getNodeByTitle(clipNodeTitle)
|
||||
.first()
|
||||
.getByRole('textbox', { name: 'text' })
|
||||
await textarea2.fill('subgraph2_value')
|
||||
await expect(textarea2).toHaveValue('subgraph2_value')
|
||||
await comfyPage.subgraph.exitViaBreadcrumb()
|
||||
|
||||
// Re-enter first subgraph, assert value preserved
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
await comfyPage.vueNodes.enterSubgraph(nodeId1)
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
const textarea1Again = comfyPage.vueNodes
|
||||
.getNodeByTitle(clipNodeTitle)
|
||||
.first()
|
||||
.getByRole('textbox', { name: 'text' })
|
||||
await expect(textarea1Again).toHaveValue('subgraph1_value')
|
||||
await comfyPage.subgraph.exitViaBreadcrumb()
|
||||
|
||||
// Re-enter second subgraph, assert value preserved
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
await comfyPage.vueNodes.enterSubgraph(nodeId2)
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
const textarea2Again = comfyPage.vueNodes
|
||||
.getNodeByTitle(clipNodeTitle)
|
||||
.first()
|
||||
.getByRole('textbox', { name: 'text' })
|
||||
await expect(textarea2Again).toHaveValue('subgraph2_value')
|
||||
})
|
||||
}
|
||||
)
|
||||
@@ -10,17 +10,14 @@ import { TestIds } from '../../../../fixtures/selectors'
|
||||
const BYPASS_CLASS = /before:bg-bypass\/60/
|
||||
|
||||
async function clickExactMenuItem(comfyPage: ComfyPage, name: string) {
|
||||
await comfyPage.page.getByRole('menuitem', { name, exact: true }).click()
|
||||
await comfyPage.contextMenu.clickMenuItemExact(name)
|
||||
await comfyPage.nextFrame()
|
||||
}
|
||||
|
||||
async function openContextMenu(comfyPage: ComfyPage, nodeTitle: string) {
|
||||
const fixture = await comfyPage.vueNodes.getFixtureByTitle(nodeTitle)
|
||||
await fixture.header.click()
|
||||
await fixture.header.click({ button: 'right' })
|
||||
const menu = comfyPage.contextMenu.primeVueMenu
|
||||
await menu.waitFor({ state: 'visible' })
|
||||
return menu
|
||||
await comfyPage.contextMenu.openForVueNode(fixture.header)
|
||||
return comfyPage.contextMenu.primeVueMenu
|
||||
}
|
||||
|
||||
async function openMultiNodeContextMenu(
|
||||
|
||||
6
codecov.yml
Normal file
6
codecov.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
comment:
|
||||
layout: 'header, diff, flags, files'
|
||||
behavior: default
|
||||
require_changes: false
|
||||
require_base: false
|
||||
require_head: true
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@comfyorg/comfyui-frontend",
|
||||
"version": "1.43.14",
|
||||
"version": "1.43.15",
|
||||
"private": true,
|
||||
"description": "Official front-end implementation of ComfyUI",
|
||||
"homepage": "https://comfy.org",
|
||||
|
||||
Reference in New Issue
Block a user