mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-21 15:24:09 +00:00
Add nodeTemplate tests
Test failure confirmed when links are not connected
This commit is contained in:
10
browser_tests/assets/node_template_templates.json
Normal file
10
browser_tests/assets/node_template_templates.json
Normal file
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"name": "Three Nodes Template",
|
||||
"data": "{\"nodes\":[{\"id\":7,\"type\":\"CLIPTextEncode\",\"pos\":[413,389],\"size\":[425.27801513671875,180.6060791015625],\"flags\":{},\"order\":3,\"mode\":0,\"inputs\":[{\"name\":\"clip\",\"type\":\"CLIP\",\"link\":null}],\"outputs\":[{\"name\":\"CONDITIONING\",\"type\":\"CONDITIONING\",\"links\":[],\"slot_index\":0}],\"properties\":{\"Node name for S&R\":\"CLIPTextEncode\"},\"widgets_values\":[\"text, watermark\"]},{\"id\":6,\"type\":\"CLIPTextEncode\",\"pos\":[415,186],\"size\":[422.84503173828125,164.31304931640625],\"flags\":{},\"order\":2,\"mode\":0,\"inputs\":[{\"name\":\"clip\",\"type\":\"CLIP\",\"link\":null}],\"outputs\":[{\"name\":\"CONDITIONING\",\"type\":\"CONDITIONING\",\"links\":[],\"slot_index\":0}],\"properties\":{\"Node name for S&R\":\"CLIPTextEncode\"},\"widgets_values\":[\"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,\"]},{\"id\":4,\"type\":\"CheckpointLoaderSimple\",\"pos\":[26,474],\"size\":[315,98],\"flags\":{},\"order\":1,\"mode\":0,\"inputs\":[],\"outputs\":[{\"name\":\"MODEL\",\"type\":\"MODEL\",\"links\":[],\"slot_index\":0},{\"name\":\"CLIP\",\"type\":\"CLIP\",\"links\":[],\"slot_index\":1},{\"name\":\"VAE\",\"type\":\"VAE\",\"links\":[],\"slot_index\":2}],\"properties\":{\"Node name for S&R\":\"CheckpointLoaderSimple\"},\"widgets_values\":[\"v1-5-pruned-emaonly.ckpt\"]}],\"groups\":[],\"reroutes\":[],\"links\":[{\"id\":5,\"origin_id\":4,\"origin_slot\":1,\"target_id\":7,\"target_slot\":0,\"type\":\"CLIP\"},{\"id\":3,\"origin_id\":4,\"origin_slot\":1,\"target_id\":6,\"target_slot\":0,\"type\":\"CLIP\"}]}"
|
||||
},
|
||||
{
|
||||
"name": "Completely empty template",
|
||||
"data": "{\"nodes\":[],\"groups\":[],\"reroutes\":[],\"links\":[]}"
|
||||
}
|
||||
]
|
||||
6
browser_tests/assets/vintage_clipboard_template.json
Normal file
6
browser_tests/assets/vintage_clipboard_template.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name": "vintageClipboard Template",
|
||||
"data": "{\"nodes\":[{\"id\":-1,\"type\":\"CheckpointLoaderSimple\",\"pos\":[26,474],\"size\":[315,98],\"flags\":{},\"order\":1,\"mode\":0,\"inputs\":[],\"outputs\":[{\"name\":\"MODEL\",\"type\":\"MODEL\",\"links\":[],\"slot_index\":0},{\"name\":\"CLIP\",\"type\":\"CLIP\",\"links\":[],\"slot_index\":1},{\"name\":\"VAE\",\"type\":\"VAE\",\"links\":[],\"slot_index\":2}],\"properties\":{\"Node name for S&R\":\"CheckpointLoaderSimple\"},\"widgets_values\":[\"v1-5-pruned-emaonly.ckpt\"]},{\"id\":-1,\"type\":\"CLIPTextEncode\",\"pos\":[415,186],\"size\":[422.84503173828125,164.31304931640625],\"flags\":{},\"order\":2,\"mode\":0,\"inputs\":[{\"name\":\"clip\",\"type\":\"CLIP\",\"link\":null}],\"outputs\":[{\"name\":\"CONDITIONING\",\"type\":\"CONDITIONING\",\"links\":[],\"slot_index\":0}],\"properties\":{\"Node name for S&R\":\"CLIPTextEncode\"},\"widgets_values\":[\"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,\"]},{\"id\":-1,\"type\":\"CLIPTextEncode\",\"pos\":[413,389],\"size\":[425.27801513671875,180.6060791015625],\"flags\":{},\"order\":3,\"mode\":0,\"inputs\":[{\"name\":\"clip\",\"type\":\"CLIP\",\"link\":null}],\"outputs\":[{\"name\":\"CONDITIONING\",\"type\":\"CONDITIONING\",\"links\":[],\"slot_index\":0}],\"properties\":{\"Node name for S&R\":\"CLIPTextEncode\"},\"widgets_values\":[\"text, watermark\"]}],\"links\":[[0,1,1,0,4],[0,1,2,0,4]]}"
|
||||
}
|
||||
]
|
||||
@@ -77,6 +77,7 @@ export class ComfyPage {
|
||||
// All canvas position operations are based on default view of canvas.
|
||||
public readonly canvas: Locator
|
||||
public readonly widgetTextBox: Locator
|
||||
public readonly contextMenu: Locator
|
||||
|
||||
// Buttons
|
||||
public readonly resetViewButton: Locator
|
||||
@@ -107,6 +108,7 @@ export class ComfyPage {
|
||||
this.url = process.env.PLAYWRIGHT_TEST_URL || 'http://localhost:8188'
|
||||
this.canvas = page.locator('#graph-canvas')
|
||||
this.widgetTextBox = page.getByPlaceholder('text').nth(1)
|
||||
this.contextMenu = page.locator('.litegraph.litecontextmenu')
|
||||
this.resetViewButton = page.getByRole('button', { name: 'Reset View' })
|
||||
this.queueButton = page.getByRole('button', { name: 'Queue Prompt' })
|
||||
this.workflowUploadInput = page.locator('#comfy-file-input')
|
||||
@@ -148,6 +150,12 @@ export class ComfyPage {
|
||||
})
|
||||
}
|
||||
|
||||
async getGraphSelectedItemsCount(): Promise<number | undefined> {
|
||||
return await this.page.evaluate(() => {
|
||||
return window['app']?.canvas?.selectedItems?.size
|
||||
})
|
||||
}
|
||||
|
||||
async setupWorkflowsDirectory(structure: FolderStructure) {
|
||||
const resp = await this.request.post(
|
||||
`${this.url}/api/devtools/setup_folder_structure`,
|
||||
@@ -191,6 +199,39 @@ export class ComfyPage {
|
||||
return await resp.json()
|
||||
}
|
||||
|
||||
async clearNodeTemplates() {
|
||||
const resp = await this.request.delete(
|
||||
`${this.url}/api/userdata/comfy.templates.json`,
|
||||
{
|
||||
headers: { 'Comfy-User': this.id }
|
||||
}
|
||||
)
|
||||
|
||||
const status = resp.status()
|
||||
if (status !== 204 && status !== 404)
|
||||
throw new Error(`Failed to delete node templates: ${await resp.text()}`)
|
||||
}
|
||||
|
||||
async setNodeTemplates(fileName: string) {
|
||||
const path = this.assetPath(fileName)
|
||||
const data = fs.readFileSync(path, 'utf-8')
|
||||
|
||||
const resp = await this.request.post(
|
||||
`${this.url}/api/userdata/comfy.templates.json`,
|
||||
{
|
||||
headers: {
|
||||
'Comfy-User': this.id,
|
||||
overwrite: 'true',
|
||||
full_info: 'true'
|
||||
},
|
||||
data
|
||||
}
|
||||
)
|
||||
|
||||
if (resp.status() !== 200)
|
||||
throw new Error(`Failed to upload node templates: ${await resp.text()}`)
|
||||
}
|
||||
|
||||
async setupSettings(settings: Record<string, any>) {
|
||||
const resp = await this.request.post(
|
||||
`${this.url}/api/devtools/set_settings`,
|
||||
@@ -399,11 +440,17 @@ export class ComfyPage {
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
async dragAndDrop(source: Position, target: Position) {
|
||||
async dragAndDrop(
|
||||
source: Position,
|
||||
target: Position,
|
||||
modifierKey?: 'ControlOrMeta' | 'Control' | 'Alt' | 'Shift'
|
||||
) {
|
||||
if (modifierKey) await this.page.keyboard.down(modifierKey)
|
||||
await this.page.mouse.move(source.x, source.y)
|
||||
await this.page.mouse.down()
|
||||
await this.page.mouse.move(target.x, target.y)
|
||||
await this.page.mouse.up()
|
||||
if (modifierKey) await this.page.keyboard.up(modifierKey)
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
@@ -551,8 +598,11 @@ export class ComfyPage {
|
||||
}
|
||||
|
||||
async rightClickCanvas() {
|
||||
await this.page.mouse.click(10, 10, { button: 'right' })
|
||||
await this.nextFrame()
|
||||
await this.canvas.click({
|
||||
position: { x: 10, y: 10 },
|
||||
button: 'right'
|
||||
})
|
||||
await expect(this.contextMenu).toBeVisible()
|
||||
}
|
||||
|
||||
async doubleClickCanvas() {
|
||||
@@ -583,6 +633,10 @@ export class ComfyPage {
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
async clickContextMenuItem(name: string): Promise<void> {
|
||||
await this.page.getByRole('menuitem', { name }).click()
|
||||
}
|
||||
|
||||
async select2Nodes() {
|
||||
// Select 2 CLIP nodes.
|
||||
await this.page.keyboard.down('Control')
|
||||
|
||||
70
browser_tests/nodeTemplate.spec.ts
Normal file
70
browser_tests/nodeTemplate.spec.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
comfyPageFixture as test,
|
||||
comfyExpect as expect
|
||||
} from './fixtures/ComfyPage'
|
||||
|
||||
// Old `nodeTemplate.ts` system
|
||||
test.describe('Node Template', () => {
|
||||
test.afterEach(async ({ comfyPage }) => {
|
||||
await comfyPage.clearNodeTemplates()
|
||||
})
|
||||
|
||||
test('Can create and use node template', async ({ comfyPage }) => {
|
||||
const templateName = 'Can create node template template'
|
||||
|
||||
await comfyPage.clearNodeTemplates()
|
||||
await comfyPage.reload()
|
||||
|
||||
// TODO: Flaky test. Right click requires delay after reload, but other interactions do not.
|
||||
await comfyPage.page.waitForTimeout(500)
|
||||
|
||||
// Enter filename when prompt dialog shown
|
||||
comfyPage.page.on('dialog', (dialog) => dialog.accept(templateName))
|
||||
|
||||
// Ctrl + drag over 3 nodes
|
||||
await comfyPage.dragAndDrop(
|
||||
{ x: 175, y: 252 },
|
||||
{ x: 483, y: 564 },
|
||||
'ControlOrMeta'
|
||||
)
|
||||
expect(await comfyPage.getGraphSelectedItemsCount()).toEqual(3)
|
||||
|
||||
await comfyPage.rightClickCanvas()
|
||||
await comfyPage.clickContextMenuItem('Save Selected as Template')
|
||||
await comfyPage.nextFrame()
|
||||
|
||||
await comfyPage.rightClickCanvas()
|
||||
await comfyPage.clickContextMenuItem('Node Templates >')
|
||||
await comfyPage.clickContextMenuItem(templateName)
|
||||
|
||||
await expect(comfyPage.canvas).toHaveScreenshot()
|
||||
})
|
||||
|
||||
test('Can load old format template', async ({ comfyPage }) => {
|
||||
await comfyPage.setNodeTemplates('vintage_clipboard_template.json')
|
||||
await comfyPage.reload()
|
||||
|
||||
// TODO: Flaky test. Right click requires delay after reload, but other interactions do not.
|
||||
await comfyPage.page.waitForTimeout(500)
|
||||
|
||||
await comfyPage.rightClickCanvas()
|
||||
await comfyPage.clickContextMenuItem('Node Templates >')
|
||||
await comfyPage.clickContextMenuItem('vintageClipboard Template')
|
||||
|
||||
await expect(comfyPage.canvas).toHaveScreenshot()
|
||||
})
|
||||
|
||||
test('Can load new format template', async ({ comfyPage }) => {
|
||||
await comfyPage.setNodeTemplates('node_template_templates.json')
|
||||
await comfyPage.reload()
|
||||
|
||||
// TODO: Flaky test. Right click requires delay after reload, but other interactions do not.
|
||||
await comfyPage.page.waitForTimeout(500)
|
||||
|
||||
await comfyPage.rightClickCanvas()
|
||||
await comfyPage.clickContextMenuItem('Node Templates >')
|
||||
await comfyPage.clickContextMenuItem('Three Nodes Template')
|
||||
|
||||
await expect(comfyPage.canvas).toHaveScreenshot()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user