mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
## Summary Alright, alright, alright. These e2e tests have been runnin' around like they're late for somethin', settin' tight little timeouts like the world's gonna end in 250 milliseconds. Man, you gotta *breathe*. Let the framework do its thing. Go slow to go fast, that's what I always say. ## Changes - **What**: Removed ~120 redundant timeout overrides from auto-retrying Playwright assertions (`toBeVisible`, `toBeHidden`, `toHaveCount`, `toBeEnabled`, `toHaveAttribute`, `toContainText`, `expect.poll`) where 5000ms is already the default. Also removed sub-5s timeouts (1s, 2s, 3s) that were just *begging* for flaky failures — like wearin' a belt and suspenders and also holdin' your pants up with both hands. Raised the absurdly short timeouts in `customMatchers.ts` (250ms `toPass` → 5000ms, 256ms poll → default). Kept `timeout: 5000` on `.toPass()` calls (defaults to 0), `.waitFor()`, `waitForRequest`, `waitForFunction`, intentionally-short timeouts inside retry loops, and conditional `.isVisible()/.catch()` checks — those fellas actually need the help. ## Review Focus Every remaining timeout in the diff is there for a *reason*. The ones on `.toPass()` stay because that API defaults to zero — it won't retry at all without one. The ones on `.waitFor()` and `waitForRequest` stay because those are locator actions, not auto-retrying assertions. The intentionally-short ones inside `toPass` retry loops (`interaction.spec.ts`) and the negative assertions (`actionbar.spec.ts` confirming no response arrives) — those are *supposed* to be tight. The short timeouts on regular assertions were actively *encouragin'* flaky failures. That's like settin' your alarm for 4 AM and then gettin' mad you're tired. Just... don't do that, man. Let things take the time they need. 38 files, net -115 lines. Less code, more chill. That's livin'. --------- Co-authored-by: Amp <amp@ampcode.com>
197 lines
6.7 KiB
TypeScript
197 lines
6.7 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
|
|
import { DefaultGraphPositions } from '@e2e/fixtures/constants/defaultGraphPositions'
|
|
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
await comfyPage.settings.setSetting('Comfy.UseNewMenu', 'Disabled')
|
|
})
|
|
|
|
test.describe('Copy Paste', { tag: ['@screenshot', '@workflow'] }, () => {
|
|
test('Can copy and paste node', async ({ comfyPage }) => {
|
|
await comfyPage.canvas.click({
|
|
position: DefaultGraphPositions.emptyLatentWidgetClick
|
|
})
|
|
await comfyPage.page.mouse.move(10, 10)
|
|
await comfyPage.nextFrame()
|
|
await comfyPage.clipboard.copy()
|
|
await comfyPage.clipboard.paste()
|
|
await expect(comfyPage.canvas).toHaveScreenshot('copied-node.png')
|
|
})
|
|
|
|
test('Can copy and paste node with link', async ({ comfyPage }) => {
|
|
await comfyPage.canvas.click({
|
|
position: DefaultGraphPositions.textEncodeNode1
|
|
})
|
|
await comfyPage.nextFrame()
|
|
await comfyPage.page.mouse.move(10, 10)
|
|
await comfyPage.clipboard.copy()
|
|
await comfyPage.page.keyboard.press('Control+Shift+V')
|
|
await expect(comfyPage.canvas).toHaveScreenshot('copied-node-with-link.png')
|
|
})
|
|
|
|
test('Can copy and paste text', async ({ comfyPage }) => {
|
|
const textBox = comfyPage.widgetTextBox
|
|
await textBox.click()
|
|
const originalString = await textBox.inputValue()
|
|
await textBox.selectText()
|
|
await comfyPage.clipboard.copy(null)
|
|
await comfyPage.clipboard.paste(null)
|
|
await comfyPage.clipboard.paste(null)
|
|
await expect
|
|
.poll(() => textBox.inputValue())
|
|
.toBe(originalString + originalString)
|
|
})
|
|
|
|
test('Can copy and paste widget value', async ({ comfyPage }) => {
|
|
// Copy width value (512) from empty latent node to KSampler's seed.
|
|
// KSampler's seed
|
|
await comfyPage.canvas.click({
|
|
position: {
|
|
x: 1005,
|
|
y: 281
|
|
}
|
|
})
|
|
await comfyPage.clipboard.copy(null)
|
|
// Empty latent node's width
|
|
await comfyPage.canvas.click({
|
|
position: {
|
|
x: 718,
|
|
y: 643
|
|
}
|
|
})
|
|
await comfyPage.clipboard.paste(null)
|
|
await comfyPage.page.keyboard.press('Enter')
|
|
await expect(comfyPage.canvas).toHaveScreenshot('copied-widget-value.png')
|
|
})
|
|
|
|
/**
|
|
* https://github.com/Comfy-Org/ComfyUI_frontend/issues/98
|
|
*/
|
|
test('Paste in text area with node previously copied', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.canvas.click({
|
|
position: DefaultGraphPositions.emptyLatentWidgetClick
|
|
})
|
|
await comfyPage.page.mouse.move(10, 10)
|
|
await comfyPage.nextFrame()
|
|
await comfyPage.clipboard.copy(null)
|
|
const textBox = comfyPage.widgetTextBox
|
|
await textBox.click()
|
|
await textBox.inputValue()
|
|
await textBox.selectText()
|
|
await comfyPage.clipboard.copy(null)
|
|
await comfyPage.clipboard.paste(null)
|
|
await comfyPage.clipboard.paste(null)
|
|
await expect(comfyPage.canvas).toHaveScreenshot(
|
|
'paste-in-text-area-with-node-previously-copied.png'
|
|
)
|
|
})
|
|
|
|
test('Copy text area does not copy node', async ({ comfyPage }) => {
|
|
const textBox = comfyPage.widgetTextBox
|
|
await textBox.click()
|
|
await textBox.inputValue()
|
|
await textBox.selectText()
|
|
await comfyPage.clipboard.copy(null)
|
|
// Unfocus textbox.
|
|
await comfyPage.page.mouse.click(10, 10)
|
|
await comfyPage.clipboard.paste(null)
|
|
await expect(comfyPage.canvas).toHaveScreenshot('no-node-copied.png')
|
|
})
|
|
|
|
test('Copy node by dragging + alt', async ({ comfyPage }) => {
|
|
// TextEncodeNode1
|
|
await comfyPage.page.mouse.move(618, 191)
|
|
await comfyPage.page.keyboard.down('Alt')
|
|
await comfyPage.page.mouse.down()
|
|
await comfyPage.page.mouse.move(100, 100)
|
|
await comfyPage.page.mouse.up()
|
|
await comfyPage.page.keyboard.up('Alt')
|
|
await expect(comfyPage.canvas).toHaveScreenshot('drag-copy-copied-node.png')
|
|
})
|
|
|
|
test('Can undo paste multiple nodes as single action', async ({
|
|
comfyPage
|
|
}) => {
|
|
await expect
|
|
.poll(() => comfyPage.nodeOps.getGraphNodesCount())
|
|
.toBeGreaterThan(1)
|
|
const initialCount = await comfyPage.nodeOps.getGraphNodesCount()
|
|
await comfyPage.canvas.click()
|
|
await comfyPage.keyboard.selectAll()
|
|
await comfyPage.page.mouse.move(10, 10)
|
|
await comfyPage.clipboard.copy()
|
|
await comfyPage.clipboard.paste()
|
|
|
|
await expect
|
|
.poll(() => comfyPage.nodeOps.getGraphNodesCount())
|
|
.toBe(initialCount * 2)
|
|
|
|
await comfyPage.keyboard.undo()
|
|
await expect
|
|
.poll(() => comfyPage.nodeOps.getGraphNodesCount())
|
|
.toBe(initialCount)
|
|
})
|
|
|
|
test(
|
|
'Copy paste node, image paste onto LoadImage, image paste on empty canvas',
|
|
{ tag: ['@node'] },
|
|
async ({ comfyPage }) => {
|
|
await comfyPage.workflow.loadWorkflow('nodes/load_image_with_ksampler')
|
|
await expect.poll(() => comfyPage.nodeOps.getGraphNodesCount()).toBe(2)
|
|
|
|
// Step 1: Copy a KSampler node with Ctrl+C and paste with Ctrl+V
|
|
const ksamplerNodes =
|
|
await comfyPage.nodeOps.getNodeRefsByType('KSampler')
|
|
await ksamplerNodes[0].copy()
|
|
await comfyPage.canvas.click({ position: { x: 50, y: 500 } })
|
|
await comfyPage.nextFrame()
|
|
await comfyPage.clipboard.paste()
|
|
await expect.poll(() => comfyPage.nodeOps.getGraphNodesCount()).toBe(3)
|
|
|
|
// Step 2: Paste image onto selected LoadImage node
|
|
const loadImageNodes =
|
|
await comfyPage.nodeOps.getNodeRefsByType('LoadImage')
|
|
await loadImageNodes[0].click('title')
|
|
await comfyPage.nextFrame()
|
|
|
|
const uploadPromise = comfyPage.page.waitForResponse(
|
|
(resp) => resp.url().includes('/upload/') && resp.status() === 200,
|
|
{ timeout: 10_000 }
|
|
)
|
|
await comfyPage.clipboard.pasteFile(
|
|
comfyPage.assetPath('image32x32.webp')
|
|
)
|
|
await uploadPromise
|
|
|
|
await expect
|
|
.poll(async () => {
|
|
const fileWidget = await loadImageNodes[0].getWidget(0)
|
|
return fileWidget.getValue()
|
|
})
|
|
.toContain('image32x32')
|
|
await expect.poll(() => comfyPage.nodeOps.getGraphNodesCount()).toBe(3)
|
|
|
|
// Step 3: Click empty canvas area, paste image → creates new LoadImage
|
|
await comfyPage.canvas.click({ position: { x: 50, y: 500 } })
|
|
await comfyPage.nextFrame()
|
|
|
|
const uploadPromise2 = comfyPage.page.waitForResponse(
|
|
(resp) => resp.url().includes('/upload/') && resp.status() === 200,
|
|
{ timeout: 10_000 }
|
|
)
|
|
await comfyPage.clipboard.pasteFile(
|
|
comfyPage.assetPath('image32x32.webp')
|
|
)
|
|
await uploadPromise2
|
|
|
|
await expect.poll(() => comfyPage.nodeOps.getGraphNodesCount()).toBe(4)
|
|
const allLoadImageNodes =
|
|
await comfyPage.nodeOps.getNodeRefsByType('LoadImage')
|
|
expect(allLoadImageNodes).toHaveLength(2)
|
|
}
|
|
)
|
|
})
|