mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 14:30:41 +00:00
refactor: improve type safety patterns from @ts-expect-error cleanup
Amp-Thread-ID: https://ampcode.com/threads/T-019bb3bd-f607-735a-b1a8-fce5fe4f0125 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -9,33 +9,25 @@ test.beforeEach(async ({ comfyPage }) => {
|
||||
test.describe('Keybindings', () => {
|
||||
test('Should execute command', async ({ comfyPage }) => {
|
||||
await comfyPage.registerCommand('TestCommand', () => {
|
||||
;(window as unknown as Record<string, unknown>)['foo'] = true
|
||||
window.foo = true
|
||||
})
|
||||
|
||||
await comfyPage.executeCommand('TestCommand')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['foo']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.foo)).toBe(true)
|
||||
})
|
||||
|
||||
test('Should execute async command', async ({ comfyPage }) => {
|
||||
await comfyPage.registerCommand('TestCommand', async () => {
|
||||
await new Promise<void>((resolve) =>
|
||||
setTimeout(() => {
|
||||
;(window as unknown as Record<string, unknown>)['foo'] = true
|
||||
window.foo = true
|
||||
resolve()
|
||||
}, 5)
|
||||
)
|
||||
})
|
||||
|
||||
await comfyPage.executeCommand('TestCommand')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['foo']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.foo)).toBe(true)
|
||||
})
|
||||
|
||||
test('Should handle command errors', async ({ comfyPage }) => {
|
||||
|
||||
@@ -19,7 +19,7 @@ test.describe('Topbar commands', () => {
|
||||
id: 'foo',
|
||||
label: 'foo-command',
|
||||
function: () => {
|
||||
;(window as unknown as Record<string, unknown>)['foo'] = true
|
||||
window.foo = true
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -33,11 +33,7 @@ test.describe('Topbar commands', () => {
|
||||
})
|
||||
|
||||
await comfyPage.menu.topbar.triggerTopbarCommand(['ext', 'foo-command'])
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['foo']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.foo)).toBe(true)
|
||||
})
|
||||
|
||||
test('Should not allow register command defined in other extension', async ({
|
||||
@@ -72,8 +68,7 @@ test.describe('Topbar commands', () => {
|
||||
{
|
||||
id: 'TestCommand',
|
||||
function: () => {
|
||||
;(window as unknown as Record<string, unknown>)['TestCommand'] =
|
||||
true
|
||||
window.TestCommand = true
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -87,11 +82,7 @@ test.describe('Topbar commands', () => {
|
||||
})
|
||||
|
||||
await comfyPage.page.keyboard.press('k')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['TestCommand']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.TestCommand)).toBe(true)
|
||||
})
|
||||
|
||||
test.describe('Settings', () => {
|
||||
@@ -108,19 +99,14 @@ test.describe('Topbar commands', () => {
|
||||
type: 'text',
|
||||
defaultValue: 'Hello, world!',
|
||||
onChange: () => {
|
||||
const win = window as unknown as Record<string, unknown>
|
||||
win['changeCount'] = ((win['changeCount'] as number) ?? 0) + 1
|
||||
window.changeCount = (window.changeCount ?? 0) + 1
|
||||
}
|
||||
} as unknown as SettingParams
|
||||
]
|
||||
})
|
||||
})
|
||||
// onChange is called when the setting is first added
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['changeCount']
|
||||
)
|
||||
).toBe(1)
|
||||
expect(await comfyPage.page.evaluate(() => window.changeCount)).toBe(1)
|
||||
expect(await comfyPage.getSetting('TestSetting' as string)).toBe(
|
||||
'Hello, world!'
|
||||
)
|
||||
@@ -129,11 +115,7 @@ test.describe('Topbar commands', () => {
|
||||
expect(await comfyPage.getSetting('TestSetting' as string)).toBe(
|
||||
'Hello, universe!'
|
||||
)
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['changeCount']
|
||||
)
|
||||
).toBe(2)
|
||||
expect(await comfyPage.page.evaluate(() => window.changeCount)).toBe(2)
|
||||
})
|
||||
|
||||
test('Should allow setting boolean settings', async ({ comfyPage }) => {
|
||||
@@ -149,8 +131,7 @@ test.describe('Topbar commands', () => {
|
||||
type: 'boolean',
|
||||
defaultValue: false,
|
||||
onChange: () => {
|
||||
const win = window as unknown as Record<string, unknown>
|
||||
win['changeCount'] = ((win['changeCount'] as number) ?? 0) + 1
|
||||
window.changeCount = (window.changeCount ?? 0) + 1
|
||||
}
|
||||
} as unknown as SettingParams
|
||||
]
|
||||
@@ -160,11 +141,7 @@ test.describe('Topbar commands', () => {
|
||||
expect(await comfyPage.getSetting('Comfy.TestSetting' as string)).toBe(
|
||||
false
|
||||
)
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['changeCount']
|
||||
)
|
||||
).toBe(1)
|
||||
expect(await comfyPage.page.evaluate(() => window.changeCount)).toBe(1)
|
||||
|
||||
await comfyPage.settingDialog.open()
|
||||
await comfyPage.settingDialog.toggleBooleanSetting(
|
||||
@@ -173,11 +150,7 @@ test.describe('Topbar commands', () => {
|
||||
expect(await comfyPage.getSetting('Comfy.TestSetting' as string)).toBe(
|
||||
true
|
||||
)
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['changeCount']
|
||||
)
|
||||
).toBe(2)
|
||||
expect(await comfyPage.page.evaluate(() => window.changeCount)).toBe(2)
|
||||
})
|
||||
|
||||
test.describe('Passing through attrs to setting components', () => {
|
||||
@@ -303,16 +276,14 @@ test.describe('Topbar commands', () => {
|
||||
message: 'Test Prompt Message'
|
||||
})
|
||||
.then((value: string | null) => {
|
||||
;(window as unknown as Record<string, unknown>)['value'] = value
|
||||
window.value = value
|
||||
})
|
||||
})
|
||||
|
||||
await comfyPage.fillPromptDialog('Hello, world!')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['value']
|
||||
)
|
||||
).toBe('Hello, world!')
|
||||
expect(await comfyPage.page.evaluate(() => window.value)).toBe(
|
||||
'Hello, world!'
|
||||
)
|
||||
})
|
||||
|
||||
test('Should allow showing a confirmation dialog', async ({
|
||||
@@ -327,39 +298,31 @@ test.describe('Topbar commands', () => {
|
||||
message: 'Test Confirm Message'
|
||||
})
|
||||
.then((value: boolean | null) => {
|
||||
;(window as unknown as Record<string, unknown>)['value'] = value
|
||||
window.value = value
|
||||
})
|
||||
})
|
||||
|
||||
await comfyPage.confirmDialog.click('confirm')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['value']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.value)).toBe(true)
|
||||
})
|
||||
|
||||
test('Should allow dismissing a dialog', async ({ comfyPage }) => {
|
||||
await comfyPage.page.evaluate(() => {
|
||||
const app = window['app']
|
||||
if (!app) throw new Error('App not initialized')
|
||||
;(window as unknown as Record<string, unknown>)['value'] = 'foo'
|
||||
window.value = 'foo'
|
||||
void app.extensionManager.dialog
|
||||
.confirm({
|
||||
title: 'Test Confirm',
|
||||
message: 'Test Confirm Message'
|
||||
})
|
||||
.then((value: boolean | null) => {
|
||||
;(window as unknown as Record<string, unknown>)['value'] = value
|
||||
window.value = value
|
||||
})
|
||||
})
|
||||
|
||||
await comfyPage.confirmDialog.click('reject')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['value']
|
||||
)
|
||||
).toBeNull()
|
||||
expect(await comfyPage.page.evaluate(() => window.value)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -383,9 +346,7 @@ test.describe('Topbar commands', () => {
|
||||
label: 'Test Command',
|
||||
icon: 'pi pi-star',
|
||||
function: () => {
|
||||
;(window as unknown as Record<string, unknown>)[
|
||||
'selectionCommandExecuted'
|
||||
] = true
|
||||
window.selectionCommandExecuted = true
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -403,12 +364,7 @@ test.describe('Topbar commands', () => {
|
||||
|
||||
// Verify the command was executed
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() =>
|
||||
(window as unknown as Record<string, unknown>)[
|
||||
'selectionCommandExecuted'
|
||||
]
|
||||
)
|
||||
await comfyPage.page.evaluate(() => window.selectionCommandExecuted)
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -11,25 +11,23 @@ test.describe('Keybindings', () => {
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.registerKeybinding({ key: 'k' }, () => {
|
||||
;(window as unknown as Record<string, unknown>)['TestCommand'] = true
|
||||
window.TestCommand = true
|
||||
})
|
||||
|
||||
const textBox = comfyPage.widgetTextBox
|
||||
await textBox.click()
|
||||
await textBox.fill('k')
|
||||
await expect(textBox).toHaveValue('k')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['TestCommand']
|
||||
)
|
||||
).toBe(undefined)
|
||||
expect(await comfyPage.page.evaluate(() => window.TestCommand)).toBe(
|
||||
undefined
|
||||
)
|
||||
})
|
||||
|
||||
test('Should not trigger modifier keybinding when typing in input fields', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.registerKeybinding({ key: 'k', ctrl: true }, () => {
|
||||
;(window as unknown as Record<string, unknown>)['TestCommand'] = true
|
||||
window.TestCommand = true
|
||||
})
|
||||
|
||||
const textBox = comfyPage.widgetTextBox
|
||||
@@ -37,28 +35,22 @@ test.describe('Keybindings', () => {
|
||||
await textBox.fill('q')
|
||||
await textBox.press('Control+k')
|
||||
await expect(textBox).toHaveValue('q')
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['TestCommand']
|
||||
)
|
||||
).toBe(true)
|
||||
expect(await comfyPage.page.evaluate(() => window.TestCommand)).toBe(true)
|
||||
})
|
||||
|
||||
test('Should not trigger keybinding reserved by text input when typing in input fields', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
await comfyPage.registerKeybinding({ key: 'Ctrl+v' }, () => {
|
||||
;(window as unknown as Record<string, unknown>)['TestCommand'] = true
|
||||
window.TestCommand = true
|
||||
})
|
||||
|
||||
const textBox = comfyPage.widgetTextBox
|
||||
await textBox.click()
|
||||
await textBox.press('Control+v')
|
||||
await expect(textBox).toBeFocused()
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['TestCommand']
|
||||
)
|
||||
).toBe(undefined)
|
||||
expect(await comfyPage.page.evaluate(() => window.TestCommand)).toBe(
|
||||
undefined
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,14 +26,30 @@ test.describe('Subgraph Slot Rename Dialog', () => {
|
||||
|
||||
// Get initial slot label
|
||||
const initialInputLabel = await comfyPage.page.evaluate(() => {
|
||||
const assertSubgraph = (
|
||||
graph: unknown
|
||||
): asserts graph is {
|
||||
inputs: { label?: string; name?: string }[]
|
||||
outputs: unknown[]
|
||||
} => {
|
||||
if (
|
||||
graph === null ||
|
||||
typeof graph !== 'object' ||
|
||||
!('inputs' in graph) ||
|
||||
!('outputs' in graph) ||
|
||||
!Array.isArray((graph as { inputs: unknown }).inputs) ||
|
||||
!Array.isArray((graph as { outputs: unknown }).outputs)
|
||||
) {
|
||||
throw new Error('Not in subgraph')
|
||||
}
|
||||
}
|
||||
const app = window['app']
|
||||
if (!app) throw new Error('App not available')
|
||||
const canvas = app.canvas
|
||||
if (!canvas) throw new Error('Canvas not available')
|
||||
const graph = canvas.graph
|
||||
if (!graph || !('inputs' in graph)) throw new Error('Not in subgraph')
|
||||
const inputs = graph.inputs as { label?: string; name?: string }[]
|
||||
return inputs?.[0]?.label || inputs?.[0]?.name || null
|
||||
assertSubgraph(graph)
|
||||
return graph.inputs[0]?.label || graph.inputs[0]?.name || null
|
||||
})
|
||||
|
||||
// First rename
|
||||
@@ -60,18 +76,30 @@ test.describe('Subgraph Slot Rename Dialog', () => {
|
||||
|
||||
// Verify the rename worked
|
||||
const afterFirstRename = await comfyPage.page.evaluate(() => {
|
||||
const assertSubgraph = (
|
||||
graph: unknown
|
||||
): asserts graph is {
|
||||
inputs: { label?: string; name?: string; displayName?: string }[]
|
||||
outputs: unknown[]
|
||||
} => {
|
||||
if (
|
||||
graph === null ||
|
||||
typeof graph !== 'object' ||
|
||||
!('inputs' in graph) ||
|
||||
!('outputs' in graph) ||
|
||||
!Array.isArray((graph as { inputs: unknown }).inputs) ||
|
||||
!Array.isArray((graph as { outputs: unknown }).outputs)
|
||||
) {
|
||||
throw new Error('Not in subgraph')
|
||||
}
|
||||
}
|
||||
const app = window['app']
|
||||
if (!app) throw new Error('App not available')
|
||||
const canvas = app.canvas
|
||||
if (!canvas) throw new Error('Canvas not available')
|
||||
const graph = canvas.graph
|
||||
if (!graph || !('inputs' in graph)) throw new Error('Not in subgraph')
|
||||
const inputs = graph.inputs as {
|
||||
label?: string
|
||||
name?: string
|
||||
displayName?: string
|
||||
}[]
|
||||
const slot = inputs?.[0]
|
||||
assertSubgraph(graph)
|
||||
const slot = graph.inputs[0]
|
||||
return {
|
||||
label: slot?.label || null,
|
||||
name: slot?.name || null,
|
||||
@@ -112,14 +140,30 @@ test.describe('Subgraph Slot Rename Dialog', () => {
|
||||
|
||||
// Verify the second rename worked
|
||||
const afterSecondRename = await comfyPage.page.evaluate(() => {
|
||||
const assertSubgraph = (
|
||||
graph: unknown
|
||||
): asserts graph is {
|
||||
inputs: { label?: string }[]
|
||||
outputs: unknown[]
|
||||
} => {
|
||||
if (
|
||||
graph === null ||
|
||||
typeof graph !== 'object' ||
|
||||
!('inputs' in graph) ||
|
||||
!('outputs' in graph) ||
|
||||
!Array.isArray((graph as { inputs: unknown }).inputs) ||
|
||||
!Array.isArray((graph as { outputs: unknown }).outputs)
|
||||
) {
|
||||
throw new Error('Not in subgraph')
|
||||
}
|
||||
}
|
||||
const app = window['app']
|
||||
if (!app) throw new Error('App not available')
|
||||
const canvas = app.canvas
|
||||
if (!canvas) throw new Error('Canvas not available')
|
||||
const graph = canvas.graph
|
||||
if (!graph || !('inputs' in graph)) throw new Error('Not in subgraph')
|
||||
const inputs = graph.inputs as { label?: string }[]
|
||||
return inputs?.[0]?.label || null
|
||||
assertSubgraph(graph)
|
||||
return graph.inputs[0]?.label || null
|
||||
})
|
||||
expect(afterSecondRename).toBe(SECOND_RENAMED_NAME)
|
||||
})
|
||||
@@ -134,14 +178,30 @@ test.describe('Subgraph Slot Rename Dialog', () => {
|
||||
|
||||
// Get initial output slot label
|
||||
const initialOutputLabel = await comfyPage.page.evaluate(() => {
|
||||
const assertSubgraph = (
|
||||
graph: unknown
|
||||
): asserts graph is {
|
||||
inputs: unknown[]
|
||||
outputs: { label?: string; name?: string }[]
|
||||
} => {
|
||||
if (
|
||||
graph === null ||
|
||||
typeof graph !== 'object' ||
|
||||
!('inputs' in graph) ||
|
||||
!('outputs' in graph) ||
|
||||
!Array.isArray((graph as { inputs: unknown }).inputs) ||
|
||||
!Array.isArray((graph as { outputs: unknown }).outputs)
|
||||
) {
|
||||
throw new Error('Not in subgraph')
|
||||
}
|
||||
}
|
||||
const app = window['app']
|
||||
if (!app) throw new Error('App not available')
|
||||
const canvas = app.canvas
|
||||
if (!canvas) throw new Error('Canvas not available')
|
||||
const graph = canvas.graph
|
||||
if (!graph || !('outputs' in graph)) throw new Error('Not in subgraph')
|
||||
const outputs = graph.outputs as { label?: string; name?: string }[]
|
||||
return outputs?.[0]?.label || outputs?.[0]?.name || null
|
||||
assertSubgraph(graph)
|
||||
return graph.outputs[0]?.label || graph.outputs[0]?.name || null
|
||||
})
|
||||
|
||||
// First rename
|
||||
|
||||
@@ -112,16 +112,14 @@ test.describe('Slider widget', () => {
|
||||
if (!app?.graph?.nodes?.[0]?.widgets?.[0]) return
|
||||
const widget = app.graph.nodes[0].widgets[0]
|
||||
widget.callback = (value: number) => {
|
||||
;(window as unknown as Record<string, unknown>)['widgetValue'] = value
|
||||
window.widgetValue = value
|
||||
}
|
||||
})
|
||||
await widget.dragHorizontal(50)
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('slider_widget_dragged.png')
|
||||
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['widgetValue']
|
||||
)
|
||||
await comfyPage.page.evaluate(() => window.widgetValue)
|
||||
).toBeDefined()
|
||||
})
|
||||
})
|
||||
@@ -137,16 +135,14 @@ test.describe('Number widget', () => {
|
||||
if (!app?.graph?.nodes?.[0]?.widgets?.[0]) return
|
||||
const widget = app.graph.nodes[0].widgets[0]
|
||||
widget.callback = (value: number) => {
|
||||
;(window as unknown as Record<string, unknown>)['widgetValue'] = value
|
||||
window.widgetValue = value
|
||||
}
|
||||
})
|
||||
await widget.dragHorizontal(50)
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('seed_widget_dragged.png')
|
||||
|
||||
expect(
|
||||
await comfyPage.page.evaluate(
|
||||
() => (window as unknown as Record<string, unknown>)['widgetValue']
|
||||
)
|
||||
await comfyPage.page.evaluate(() => window.widgetValue)
|
||||
).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user