mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-20 12:29:39 +00:00
## Summary Backfills missing e2e test coverage identified in the [FixIt Burndown](https://www.notion.so/comfy-org/FixIt-Burndown-32e6d73d365080609a81cdc9bc884460) audit. Adds 39 new behavioral tests across 5 spec files with zero test-code overlap. ## Changes - **What**: New e2e specs for Image Crop (6 tests) and Curve Widget (6 tests). Deepened coverage for Minimap (+6), Mask Editor (+10), Painter (+11). - **New fixtures**: `curve_widget.json`, updated `image_crop_widget.json` ## Test Inventory | Spec | New tests | Coverage area | |---|---|---| | `imageCrop.spec.ts` | 6 | Empty state, bounding box inputs, ratio selector/presets, lock toggle, programmatic value update | | `curveWidget.spec.ts` | 6 | SVG render, click-to-add point, drag-to-reshape, Ctrl+click remove, interpolation mode switch, min-2 guard | | `minimap.spec.ts` | +6 | Click-to-pan, drag-to-pan, zoom viewport shrink, node count changes, workflow reload, pan state reflection | | `maskEditor.spec.ts` | +10 | Brush drawing, undo/redo, clear, cancel, invert, Ctrl+Z, tool panel/switching, brush settings, save with mock, eraser | | `painter.spec.ts` | +11 | Clear, eraser, control visibility toggle, brush size slider, stroke width comparison, canvas dimensions, background color, multi-stroke accumulate, color picker, opacity, partial erase | ## Review Focus - Mask editor tests use `.maskEditor_toolPanelContainer` class selectors — may need test-id hardening later - Painter slider interaction tests could be flaky if slider layout changes - All canvas pixel-count assertions use `expect.poll()` with timeouts for reliability ## Test plan - [ ] CI passes all new/modified specs - [ ] No duplicate coverage with existing tests (verified via grep before writing) - [ ] No `waitForTimeout` usage (confirmed) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11183-test-backfill-e2e-coverage-gaps-for-toolkit-widgets-minimap-mask-editor-painter-3416d73d3650819ca33edd1f27b9651a) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
123 lines
3.6 KiB
TypeScript
123 lines
3.6 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
|
|
|
|
test.describe('Image Crop', () => {
|
|
test.beforeEach(async ({ comfyPage }) => {
|
|
await comfyPage.settings.setSetting('Comfy.VueNodes.Enabled', true)
|
|
await comfyPage.workflow.loadWorkflow('widgets/image_crop_widget')
|
|
await comfyPage.vueNodes.waitForNodes()
|
|
})
|
|
|
|
test(
|
|
'Shows empty state when no input image is connected',
|
|
{ tag: '@smoke' },
|
|
async ({ comfyPage }) => {
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
await expect(node).toBeVisible()
|
|
|
|
await expect(node.getByText('No input image connected')).toBeVisible()
|
|
await expect(node.locator('img[alt="Crop preview"]')).toHaveCount(0)
|
|
}
|
|
)
|
|
|
|
test(
|
|
'Renders bounding box coordinate inputs',
|
|
{ tag: '@smoke' },
|
|
async ({ comfyPage }) => {
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
await expect(node).toBeVisible()
|
|
|
|
await expect(node.getByText('X')).toBeVisible()
|
|
await expect(node.getByText('Y')).toBeVisible()
|
|
await expect(node.getByText('Width')).toBeVisible()
|
|
await expect(node.getByText('Height')).toBeVisible()
|
|
}
|
|
)
|
|
|
|
test(
|
|
'Renders ratio selector and lock button',
|
|
{ tag: '@ui' },
|
|
async ({ comfyPage }) => {
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
await expect(node).toBeVisible()
|
|
|
|
await expect(node.getByText('Ratio')).toBeVisible()
|
|
await expect(node.getByRole('button', { name: /lock/i })).toBeVisible()
|
|
}
|
|
)
|
|
|
|
test(
|
|
'Lock button toggles aspect ratio lock',
|
|
{ tag: '@ui' },
|
|
async ({ comfyPage }) => {
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
|
|
const lockButton = node.getByRole('button', {
|
|
name: 'Lock aspect ratio'
|
|
})
|
|
await expect(lockButton).toBeVisible()
|
|
|
|
await lockButton.click()
|
|
await expect(
|
|
node.getByRole('button', { name: 'Unlock aspect ratio' })
|
|
).toBeVisible()
|
|
|
|
await node.getByRole('button', { name: 'Unlock aspect ratio' }).click()
|
|
await expect(
|
|
node.getByRole('button', { name: 'Lock aspect ratio' })
|
|
).toBeVisible()
|
|
}
|
|
)
|
|
|
|
test(
|
|
'Ratio selector offers expected presets',
|
|
{ tag: '@ui' },
|
|
async ({ comfyPage }) => {
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
|
|
const trigger = node.getByRole('combobox')
|
|
await trigger.click()
|
|
|
|
const expectedRatios = ['1:1', '3:4', '4:3', '16:9', '9:16', 'Custom']
|
|
for (const label of expectedRatios) {
|
|
await expect(
|
|
comfyPage.page.getByRole('option', { name: label, exact: true })
|
|
).toBeVisible()
|
|
}
|
|
}
|
|
)
|
|
|
|
test(
|
|
'Programmatically setting widget value updates bounding box inputs',
|
|
{ tag: '@ui' },
|
|
async ({ comfyPage }) => {
|
|
const newBounds = { x: 50, y: 100, width: 200, height: 300 }
|
|
|
|
await comfyPage.page.evaluate(
|
|
({ bounds }) => {
|
|
const node = window.app!.graph.getNodeById(1)
|
|
const widget = node?.widgets?.find((w) => w.type === 'imagecrop')
|
|
if (widget) {
|
|
widget.value = bounds
|
|
widget.callback?.(bounds)
|
|
}
|
|
},
|
|
{ bounds: newBounds }
|
|
)
|
|
await comfyPage.nextFrame()
|
|
|
|
const node = comfyPage.vueNodes.getNodeLocator('1')
|
|
const inputs = node.locator('input[inputmode="decimal"]')
|
|
|
|
await expect.poll(() => inputs.nth(0).inputValue()).toBe('50')
|
|
|
|
await expect.poll(() => inputs.nth(1).inputValue()).toBe('100')
|
|
|
|
await expect.poll(() => inputs.nth(2).inputValue()).toBe('200')
|
|
|
|
await expect.poll(() => inputs.nth(3).inputValue()).toBe('300')
|
|
}
|
|
)
|
|
})
|