Fix uploaded image not forcing re-render (#3115)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Christian Byrne
2025-03-17 17:13:05 -07:00
committed by GitHub
parent da415e9d80
commit 26a7ebdd77
6 changed files with 105 additions and 10 deletions

View File

@@ -459,7 +459,14 @@ export class ComfyPage {
await this.nextFrame()
}
async dragAndDropFile(fileName: string) {
async dragAndDropFile(
fileName: string,
options: {
dropPosition?: Position
} = {}
) {
const { dropPosition = { x: 100, y: 100 } } = options
const filePath = this.assetPath(fileName)
// Read the file content
@@ -477,32 +484,56 @@ export class ComfyPage {
const fileType = getFileType(fileName)
await this.page.evaluate(
async ({ buffer, fileName, fileType }) => {
async ({ buffer, fileName, fileType, dropPosition }) => {
const file = new File([new Uint8Array(buffer)], fileName, {
type: fileType
})
const dataTransfer = new DataTransfer()
dataTransfer.items.add(file)
const dropEvent = new DragEvent('drop', {
const targetElement = document.elementFromPoint(
dropPosition.x,
dropPosition.y
)
if (!targetElement) {
console.error('No element found at drop position:', dropPosition)
return { success: false, error: 'No element at position' }
}
const eventOptions = {
bubbles: true,
cancelable: true,
dataTransfer
})
dataTransfer,
clientX: dropPosition.x,
clientY: dropPosition.y
}
const dragOverEvent = new DragEvent('dragover', eventOptions)
const dropEvent = new DragEvent('drop', eventOptions)
Object.defineProperty(dropEvent, 'preventDefault', {
value: () => {},
writable: false
})
Object.defineProperty(dropEvent, 'stopPropagation', {
value: () => {},
writable: false
})
document.dispatchEvent(dropEvent)
targetElement.dispatchEvent(dragOverEvent)
targetElement.dispatchEvent(dropEvent)
return {
success: true,
targetInfo: {
tagName: targetElement.tagName,
id: targetElement.id,
classList: Array.from(targetElement.classList)
}
}
},
{ buffer: [...new Uint8Array(buffer)], fileName, fileType }
{ buffer: [...new Uint8Array(buffer)], fileName, fileType, dropPosition }
)
await this.nextFrame()

View File

@@ -115,8 +115,20 @@ export class NodeWidgetReference {
}
)
}
}
async getValue() {
return await this.node.comfyPage.page.evaluate(
([id, index]) => {
const node = window['app'].graph.getNodeById(id)
if (!node) throw new Error(`Node ${id} not found.`)
const widget = node.widgets[index]
if (!widget) throw new Error(`Widget ${index} not found.`)
return widget.value
},
[this.node.id, this.index] as const
)
}
}
export class NodeReference {
constructor(
readonly id: NodeId,

View File

@@ -128,11 +128,62 @@ test.describe('Dynamic widget manipulation', () => {
})
})
test.describe('Load image widget', () => {
test.describe('Image widget', () => {
test('Can load image', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('widgets/load_image_widget')
await expect(comfyPage.canvas).toHaveScreenshot('load_image_widget.png')
})
test('Can drag and drop image', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('widgets/load_image_widget')
// Get position of the load image node
const nodes = await comfyPage.getNodeRefsByType('LoadImage')
const loadImageNode = nodes[0]
const { x, y } = await loadImageNode.getPosition()
// Drag and drop image file onto the load image node
await comfyPage.dragAndDropFile('image32x32.webp', {
dropPosition: { x, y }
})
// Expect the image preview to change automatically
await expect(comfyPage.canvas).toHaveScreenshot(
'image_preview_drag_and_dropped.png'
)
// Expect the filename combo value to be updated
const fileComboWidget = await loadImageNode.getWidget(0)
const filename = await fileComboWidget.getValue()
expect(filename).toBe('image32x32.webp')
})
test('Can change image by changing the filename combo value', async ({
comfyPage
}) => {
await comfyPage.loadWorkflow('widgets/load_image_widget')
const nodes = await comfyPage.getNodeRefsByType('LoadImage')
const loadImageNode = nodes[0]
// Click the combo widget used to select the image filename
const fileComboWidget = await loadImageNode.getWidget(0)
await fileComboWidget.click()
// Select a new image filename value from the combo context menu
const comboEntry = comfyPage.page.getByRole('menuitem', {
name: 'image32x32.webp'
})
await comboEntry.click({ noWaitAfter: true })
// Expect the image preview to change automatically
await expect(comfyPage.canvas).toHaveScreenshot(
'image_preview_changed_by_combo_value.png'
)
// Expect the filename combo value to be updated
const filename = await fileComboWidget.getValue()
expect(filename).toBe('image32x32.webp')
})
})
test.describe('Load audio widget', () => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -93,6 +93,7 @@ export const useImageUploadWidget = () => {
// Add our own callback to the combo widget to render an image when it changes
fileComboWidget.callback = function () {
nodeOutputStore.setNodeOutputs(node, fileComboWidget.value)
node.graph?.setDirtyCanvas(true)
}
// On load if we have a value then render the image