mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 16:30:57 +00:00
*PR Created by the Glary-Bot Agent* --- ## Summary Fixes the "choose video to upload" button becoming unresponsive after running a workflow with a subgraph a few times. **Root cause**: The detached input element in `useNodeFileInput` never resets its `value`. The browser's `onchange` only fires when the value *changes* — re-selecting the same file silently drops the event. A page refresh recreates the input with an empty value, which is why refreshing fixes it. ## Changes - `useNodeFileInput.ts`: Reset `fileInput.value` before invoking callbacks so value is cleared even if a callback throws - `useNodeDragAndDrop.ts`: Add `onRemoved` cleanup for installed handlers (only clears own handlers; preserves replacements from extensions) - `useNodePaste.ts`: Add `onRemoved` cleanup for installed `pasteFiles` handler (same reference-safe pattern) - 3 new colocated test files with 26 test cases covering all branches ## Codebase Audit Audited all 11 file upload implementations across the codebase. Found 5 using the ghost/virtual input pattern — 3 with the same missing value-reset bug: - `useNodeFileInput.ts` — fixed in this PR - `scripts/utils.ts` (`uploadFile()`) — one-shot pattern, lower risk - `extensions/core/load3d.ts` — partial reset only The 4 Vue component implementations already reset correctly. ## Future Work VueUse `useFileDialog` composable handles same-file reselection via `reset: true` and provides automatic lifecycle cleanup. A follow-up PR could migrate the ghost input patterns for a centralized solution. ## Test Plan - 26 unit tests across 3 new test files (all pass) - 9 existing useNodeImageUpload tests still pass - Pre-commit hooks pass (oxfmt, oxlint, eslint, typecheck) - Oracle code review addressed ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11417-fix-reset-file-input-value-after-selection-to-allow-same-file-reupload-3476d73d3650814d95efdab602a3852d) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: GitHub Action <action@github.com>
55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage'
|
|
|
|
test.describe('File input same-file reselection', () => {
|
|
test('should allow uploading the same file twice via LoadImage node', async ({
|
|
comfyPage
|
|
}) => {
|
|
await comfyPage.workflow.loadWorkflow('nodes/load_image_with_ksampler')
|
|
|
|
const loadImageNodes =
|
|
await comfyPage.nodeOps.getNodeRefsByType('LoadImage')
|
|
const loadImageNode = loadImageNodes[0]
|
|
const uploadWidget = await loadImageNode.getWidget(1)
|
|
const fileWidget = await loadImageNode.getWidget(0)
|
|
|
|
// First upload
|
|
const firstUpload = comfyPage.page.waitForResponse(
|
|
(resp) => resp.url().includes('/upload/') && resp.status() === 200,
|
|
{ timeout: 10_000 }
|
|
)
|
|
const firstChooser = comfyPage.page.waitForEvent('filechooser')
|
|
await uploadWidget.click()
|
|
await (
|
|
await firstChooser
|
|
).setFiles(comfyPage.assetPath('test_upload_image.png'))
|
|
await firstUpload
|
|
|
|
await expect
|
|
.poll(() => fileWidget.getValue(), {
|
|
message: 'First upload should set widget value'
|
|
})
|
|
.toContain('test_upload_image')
|
|
|
|
// Second upload of the SAME file — before the fix, the hidden input
|
|
// retained the previous value and onchange did not fire.
|
|
const secondUpload = comfyPage.page.waitForResponse(
|
|
(resp) => resp.url().includes('/upload/') && resp.status() === 200,
|
|
{ timeout: 10_000 }
|
|
)
|
|
const secondChooser = comfyPage.page.waitForEvent('filechooser')
|
|
await uploadWidget.click()
|
|
await (
|
|
await secondChooser
|
|
).setFiles(comfyPage.assetPath('test_upload_image.png'))
|
|
await secondUpload
|
|
|
|
await expect
|
|
.poll(() => fileWidget.getValue(), {
|
|
message: 'Second upload of the same file should still set widget value'
|
|
})
|
|
.toContain('test_upload_image')
|
|
})
|
|
})
|