mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
test: add e2e tests for slot context menu in Vue nodes mode
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import { expect } from '@playwright/test'
|
||||
|
||||
import { comfyPageFixture as test } from '../../../../fixtures/ComfyPage'
|
||||
|
||||
test.describe('Vue Nodes - Slot Context Menu', () => {
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.settings.setSetting('Comfy.VueNodes.Enabled', true)
|
||||
await comfyPage.settings.setSetting('Comfy.Graph.CanvasMenu', false)
|
||||
await comfyPage.setup()
|
||||
await comfyPage.vueNodes.waitForNodes()
|
||||
})
|
||||
|
||||
test('Right-clicking an input slot dot shows the slot context menu', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// KSampler has input slots with connections — find any input slot
|
||||
const ksamplerNode = comfyPage.vueNodes.getNodeByTitle('KSampler')
|
||||
const inputSlot = ksamplerNode.locator('.lg-slot--input').first()
|
||||
await expect(inputSlot).toBeVisible()
|
||||
|
||||
// Click on the left edge where the SlotConnectionDot is
|
||||
await inputSlot.click({ button: 'right', position: { x: 6, y: 12 } })
|
||||
|
||||
// The custom slot context menu should appear (role="menu" is on the
|
||||
// teleported menu, not on the PrimeVue node context menu)
|
||||
const slotMenu = comfyPage.page.locator(
|
||||
'div[role="menu"]:not(.p-contextmenu)'
|
||||
)
|
||||
await expect(slotMenu).toBeVisible()
|
||||
|
||||
// Should show "Rename" since standard slots are not nameLocked
|
||||
await expect(
|
||||
slotMenu.getByRole('menuitem', { name: 'Rename' })
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test('Right-clicking the node body shows the node context menu, not the slot menu', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const ksamplerNode = comfyPage.vueNodes.getNodeByTitle('KSampler')
|
||||
const nodeBody = ksamplerNode.locator('[data-testid^="node-body-"]')
|
||||
await expect(nodeBody).toBeVisible()
|
||||
|
||||
await nodeBody.click({ button: 'right' })
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
// The PrimeVue node context menu should appear
|
||||
const nodeMenu = comfyPage.page.locator('.p-contextmenu')
|
||||
await expect(nodeMenu).toBeVisible()
|
||||
|
||||
// Slot-specific items should NOT be present
|
||||
await expect(
|
||||
comfyPage.page.getByRole('menuitem', { name: 'Disconnect Links' })
|
||||
).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('Right-clicking an output slot dot shows the slot context menu', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const checkpointNode =
|
||||
comfyPage.vueNodes.getNodeByTitle('Load Checkpoint')
|
||||
const outputSlot = checkpointNode.locator('.lg-slot--output').first()
|
||||
await expect(outputSlot).toBeVisible()
|
||||
|
||||
// Click on the right edge where the output SlotConnectionDot is
|
||||
const box = await outputSlot.boundingBox()
|
||||
await outputSlot.click({
|
||||
button: 'right',
|
||||
position: { x: (box?.width ?? 24) - 6, y: 12 }
|
||||
})
|
||||
|
||||
const slotMenu = comfyPage.page.locator(
|
||||
'div[role="menu"]:not(.p-contextmenu)'
|
||||
)
|
||||
await expect(slotMenu).toBeVisible()
|
||||
|
||||
await expect(
|
||||
slotMenu.getByRole('menuitem', { name: 'Rename' })
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test('Slot context menu closes when clicking outside', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const ksamplerNode = comfyPage.vueNodes.getNodeByTitle('KSampler')
|
||||
const inputSlot = ksamplerNode.locator('.lg-slot--input').first()
|
||||
await expect(inputSlot).toBeVisible()
|
||||
|
||||
await inputSlot.click({ button: 'right', position: { x: 6, y: 12 } })
|
||||
|
||||
const slotMenu = comfyPage.page.locator(
|
||||
'div[role="menu"]:not(.p-contextmenu)'
|
||||
)
|
||||
await expect(slotMenu).toBeVisible()
|
||||
|
||||
// Press Escape to close the menu
|
||||
await comfyPage.page.keyboard.press('Escape')
|
||||
|
||||
await expect(slotMenu).not.toBeVisible()
|
||||
})
|
||||
|
||||
test('Slot context menu Disconnect Links removes connections', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
// Use page.evaluate to find a KSampler input with an active link
|
||||
const slotIndex = await comfyPage.page.evaluate(() => {
|
||||
const graph = window.app!.graph!
|
||||
const nodes = graph.findNodesByType('KSampler', [])
|
||||
const ksamplerNode = nodes.find((n) =>
|
||||
n.inputs?.some((i) => i.link != null)
|
||||
)
|
||||
if (!ksamplerNode) return -1
|
||||
return ksamplerNode.inputs!.findIndex((i) => i.link != null)
|
||||
})
|
||||
expect(slotIndex).toBeGreaterThanOrEqual(0)
|
||||
|
||||
// Find the corresponding Vue input slot
|
||||
const ksamplerNode = comfyPage.vueNodes.getNodeByTitle('KSampler')
|
||||
const inputSlot = ksamplerNode.locator('.lg-slot--input').nth(slotIndex)
|
||||
await expect(inputSlot).toBeVisible()
|
||||
|
||||
await inputSlot.click({ button: 'right', position: { x: 6, y: 12 } })
|
||||
|
||||
const slotMenu = comfyPage.page.locator(
|
||||
'div[role="menu"]:not(.p-contextmenu)'
|
||||
)
|
||||
await expect(slotMenu).toBeVisible()
|
||||
|
||||
await expect(
|
||||
slotMenu.getByRole('menuitem', { name: 'Disconnect Links' })
|
||||
).toBeVisible()
|
||||
|
||||
await slotMenu
|
||||
.getByRole('menuitem', { name: 'Disconnect Links' })
|
||||
.click()
|
||||
|
||||
// Menu should close
|
||||
await expect(slotMenu).not.toBeVisible()
|
||||
|
||||
// Verify the link was removed in the graph
|
||||
const linkRemoved = await comfyPage.page.evaluate(
|
||||
(idx) => {
|
||||
const graph = window.app!.graph!
|
||||
const node = graph.findNodesByType('KSampler', [])[0]
|
||||
return node?.inputs?.[idx]?.link == null
|
||||
},
|
||||
slotIndex
|
||||
)
|
||||
expect(linkRemoved).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user