Add more UI tests (#53)
* Add disconnect node test * Add connect node test * Add widght value adjust test * Add zoom test * Test panning of canvas * Move fixture * Add add node test * Add group test * Property panel * Add collapse test * Bypass node * Add widget convertion test * Update test expectations [skip ci] * Add group node test * Update test expectations [skip ci] --------- Co-authored-by: github-actions <github-actions@github.com>
@@ -1,4 +1,5 @@
|
||||
import type { Page, Locator } from '@playwright/test';
|
||||
import { test as base } from '@playwright/test';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
@@ -85,4 +86,109 @@ export class ComfyPage {
|
||||
);
|
||||
await this.nextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
async disconnectEdge() {
|
||||
// CLIP input anchor
|
||||
await this.page.mouse.move(427, 198);
|
||||
await this.page.mouse.down();
|
||||
await this.page.mouse.move(427, 98);
|
||||
await this.page.mouse.up();
|
||||
// Move out the way to avoid highlight of menu item.
|
||||
await this.page.mouse.move(10, 10);
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async connectEdge() {
|
||||
// CLIP output anchor on Load Checkpoint Node.
|
||||
await this.page.mouse.move(332, 509);
|
||||
await this.page.mouse.down();
|
||||
// CLIP input anchor on CLIP Text Encode Node.
|
||||
await this.page.mouse.move(427, 198);
|
||||
await this.page.mouse.up();
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async adjustWidgetValue() {
|
||||
// Adjust Empty Latent Image's width input.
|
||||
const page = this.page;
|
||||
await page.locator('#graph-canvas').click({
|
||||
position: {
|
||||
x: 724,
|
||||
y: 645
|
||||
}
|
||||
});
|
||||
await page.locator('input[type="text"]').click();
|
||||
await page.locator('input[type="text"]').fill('128');
|
||||
await page.locator('input[type="text"]').press('Enter');
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async zoom(deltaY: number) {
|
||||
await this.page.mouse.move(10, 10);
|
||||
await this.page.mouse.wheel(0, deltaY);
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async pan(offset: Position) {
|
||||
await this.page.mouse.move(10, 10);
|
||||
await this.page.mouse.down();
|
||||
await this.page.mouse.move(offset.x, offset.y);
|
||||
await this.page.mouse.up();
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async rightClickCanvas() {
|
||||
await this.page.mouse.click(10, 10, { button: 'right' });
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async rightClickEmptyLatentNode() {
|
||||
await this.canvas.click({
|
||||
position: {
|
||||
x: 724,
|
||||
y: 645
|
||||
},
|
||||
button: 'right'
|
||||
});
|
||||
this.page.mouse.move(10, 10);
|
||||
await this.nextFrame();
|
||||
}
|
||||
|
||||
async select2Nodes() {
|
||||
// Select 2 CLIP nodes.
|
||||
await this.page.keyboard.down('Control');
|
||||
await this.clickTextEncodeNode1();
|
||||
await this.clickTextEncodeNode2();
|
||||
await this.page.keyboard.up('Control');
|
||||
await this.nextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({
|
||||
comfyPage: async ({ page }, use) => {
|
||||
const comfyPage = new ComfyPage(page);
|
||||
await comfyPage.goto();
|
||||
// Unify font for consistent screenshots.
|
||||
await page.addStyleTag({
|
||||
url: "https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
});
|
||||
await page.addStyleTag({
|
||||
url: "https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
});
|
||||
await page.addStyleTag({
|
||||
content: `
|
||||
* {
|
||||
font-family: 'Roboto Mono', 'Noto Color Emoji';
|
||||
}`
|
||||
});
|
||||
|
||||
await page.waitForFunction(() => document.fonts.ready);
|
||||
await page.waitForFunction(() => window['app'] != undefined);
|
||||
await page.evaluate(() => { window['app']['canvas'].show_info = false; });
|
||||
await comfyPage.nextFrame();
|
||||
// Reset view to force re-rendering of canvas. So that info fields like fps
|
||||
// become hidden.
|
||||
await comfyPage.resetView();
|
||||
await use(comfyPage);
|
||||
},
|
||||
});
|
||||
@@ -1,34 +1,5 @@
|
||||
import { test as base, expect } from '@playwright/test';
|
||||
import { ComfyPage } from './ComfyPage';
|
||||
|
||||
const test = base.extend<{ comfyPage: ComfyPage }>({
|
||||
comfyPage: async ({ page }, use) => {
|
||||
const comfyPage = new ComfyPage(page);
|
||||
await comfyPage.goto();
|
||||
// Unify font for consistent screenshots.
|
||||
await page.addStyleTag({
|
||||
url: "https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
});
|
||||
await page.addStyleTag({
|
||||
url: "https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
});
|
||||
await page.addStyleTag({
|
||||
content: `
|
||||
* {
|
||||
font-family: 'Roboto Mono', 'Noto Color Emoji';
|
||||
}`
|
||||
});
|
||||
|
||||
await page.waitForFunction(() => document.fonts.ready);
|
||||
await page.waitForFunction(() => window['app'] != undefined);
|
||||
await page.evaluate(() => { window['app']['canvas'].show_info = false; });
|
||||
await comfyPage.nextFrame();
|
||||
// Reset view to force re-rendering of canvas. So that info fields like fps
|
||||
// become hidden.
|
||||
await comfyPage.resetView();
|
||||
await use(comfyPage);
|
||||
},
|
||||
});
|
||||
import { expect } from '@playwright/test';
|
||||
import { comfyPageFixture as test } from './ComfyPage';
|
||||
|
||||
test.describe('Node Interaction', () => {
|
||||
test('Can enter prompt', async ({ comfyPage }) => {
|
||||
@@ -41,7 +12,7 @@ test.describe('Node Interaction', () => {
|
||||
});
|
||||
|
||||
test('Can highlight selected', async ({ comfyPage }) => {
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('deselected-node.png');
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('default.png');
|
||||
await comfyPage.clickTextEncodeNode1();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('selected-node1.png');
|
||||
await comfyPage.clickTextEncodeNode2();
|
||||
@@ -53,4 +24,31 @@ test.describe('Node Interaction', () => {
|
||||
await comfyPage.dragNode2();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('dragged-node1.png');
|
||||
});
|
||||
|
||||
test('Can disconnect/connect edge', async ({ comfyPage }) => {
|
||||
await comfyPage.disconnectEdge();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('disconnected-edge-with-menu.png');
|
||||
await comfyPage.connectEdge();
|
||||
// Litegraph renders edge with a slight offset.
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('default.png', { maxDiffPixels: 50 });
|
||||
});
|
||||
|
||||
test('Can adjust widget value', async ({ comfyPage }) => {
|
||||
await comfyPage.adjustWidgetValue();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('adjusted-widget-value.png');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Canvas Interaction', () => {
|
||||
test('Can zoom in/out', async ({ comfyPage }) => {
|
||||
await comfyPage.zoom(-100);
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-in.png');
|
||||
await comfyPage.zoom(200);
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('zoomed-out.png');
|
||||
});
|
||||
|
||||
test('Can pan', async ({ comfyPage }) => {
|
||||
await comfyPage.pan({ x: 200, y: 200 });
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('panned.png');
|
||||
});
|
||||
});
|
||||
|
||||
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 88 KiB |
74
browser_tests/rightClickMenu.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { comfyPageFixture as test } from './ComfyPage';
|
||||
|
||||
test.describe('Canvas Right Click Menu', () => {
|
||||
test('Can add node', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickCanvas();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png');
|
||||
await comfyPage.page.getByText('Add Node').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('add-node-menu.png');
|
||||
await comfyPage.page.getByText('loaders').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('add-node-menu-loaders.png');
|
||||
await comfyPage.page.getByText('Load VAE').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('add-node-node-added.png');
|
||||
});
|
||||
|
||||
test('Can add group', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickCanvas();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-menu.png');
|
||||
await comfyPage.page.getByText('Add Group', { exact: true }).click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('add-group-group-added.png');
|
||||
});
|
||||
|
||||
test('Can convert to group node', async ({ comfyPage }) => {
|
||||
await comfyPage.select2Nodes();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('selected-2-nodes.png');
|
||||
comfyPage.page.on('dialog', async dialog => {
|
||||
await dialog.accept("GroupNode2CLIP");
|
||||
});
|
||||
await comfyPage.rightClickCanvas();
|
||||
await comfyPage.page.getByText('Convert to Group Node').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node-group-node.png');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Node Right Click Menu', () => {
|
||||
test('Can open properties panel', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickEmptyLatentNode();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png');
|
||||
await comfyPage.page.getByText('Properties Panel').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node-properties-panel.png');
|
||||
});
|
||||
|
||||
test('Can collapse', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickEmptyLatentNode();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png');
|
||||
await comfyPage.page.getByText('Collapse').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node-collapsed.png');
|
||||
});
|
||||
|
||||
test('Can bypass', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickEmptyLatentNode();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png');
|
||||
await comfyPage.page.getByText('Bypass').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node-bypassed.png');
|
||||
});
|
||||
|
||||
test('Can convert widget to input', async ({ comfyPage }) => {
|
||||
await comfyPage.rightClickEmptyLatentNode();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node.png');
|
||||
await comfyPage.page.getByText('Convert Widget to Input').click();
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.page.getByText('Convert width to input').click();
|
||||
await comfyPage.nextFrame();
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('right-click-node-widget-converted.png');
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 91 KiB |