1- import type { Page , Locator } from ' @playwright/test' ;
2- import { test as base } from ' @playwright/test' ;
1+ import type { Page , Locator } from " @playwright/test" ;
2+ import { test as base } from " @playwright/test" ;
33import dotenv from "dotenv" ;
44dotenv . config ( ) ;
55
@@ -8,6 +8,27 @@ interface Position {
88 y : number ;
99}
1010
11+ class ComfyNodeSearchBox {
12+ public readonly input : Locator ;
13+ public readonly dropdown : Locator ;
14+
15+ constructor ( public readonly page : Page ) {
16+ this . input = page . locator (
17+ '.comfy-vue-node-search-container input[type="text"]'
18+ ) ;
19+ this . dropdown = page . locator (
20+ ".comfy-vue-node-search-container .p-autocomplete-list"
21+ ) ;
22+ }
23+
24+ async fillAndSelectFirstNode ( nodeName : string ) {
25+ await this . input . waitFor ( { state : "visible" } ) ;
26+ await this . input . fill ( nodeName ) ;
27+ await this . dropdown . waitFor ( { state : "visible" } ) ;
28+ await this . dropdown . locator ( "li" ) . nth ( 0 ) . click ( ) ;
29+ }
30+ }
31+
1132export class ComfyPage {
1233 public readonly url : string ;
1334 // All canvas position operations are based on default view of canvas.
@@ -17,13 +38,15 @@ export class ComfyPage {
1738 // Buttons
1839 public readonly resetViewButton : Locator ;
1940
20- constructor (
21- public readonly page : Page ,
22- ) {
23- this . url = process . env . PLAYWRIGHT_TEST_URL || 'http://localhost:8188' ;
24- this . canvas = page . locator ( '#graph-canvas' ) ;
25- this . widgetTextBox = page . getByPlaceholder ( 'text' ) . nth ( 1 ) ;
26- this . resetViewButton = page . getByRole ( 'button' , { name : 'Reset View' } ) ;
41+ // Search box
42+ public readonly searchBox : ComfyNodeSearchBox ;
43+
44+ constructor ( public readonly page : Page ) {
45+ this . url = process . env . PLAYWRIGHT_TEST_URL || "http://localhost:8188" ;
46+ this . canvas = page . locator ( "#graph-canvas" ) ;
47+ this . widgetTextBox = page . getByPlaceholder ( "text" ) . nth ( 1 ) ;
48+ this . resetViewButton = page . getByRole ( "button" , { name : "Reset View" } ) ;
49+ this . searchBox = new ComfyNodeSearchBox ( page ) ;
2750 }
2851
2952 async goto ( ) {
@@ -47,8 +70,8 @@ export class ComfyPage {
4770 await this . canvas . click ( {
4871 position : {
4972 x : 618 ,
50- y : 191
51- }
73+ y : 191 ,
74+ } ,
5275 } ) ;
5376 await this . nextFrame ( ) ;
5477 }
@@ -57,8 +80,8 @@ export class ComfyPage {
5780 await this . canvas . click ( {
5881 position : {
5982 x : 622 ,
60- y : 400
61- }
83+ y : 400 ,
84+ } ,
6285 } ) ;
6386 await this . nextFrame ( ) ;
6487 }
@@ -67,8 +90,8 @@ export class ComfyPage {
6790 await this . canvas . click ( {
6891 position : {
6992 x : 35 ,
70- y : 31
71- }
93+ y : 31 ,
94+ } ,
7295 } ) ;
7396 await this . nextFrame ( ) ;
7497 }
@@ -82,10 +105,7 @@ export class ComfyPage {
82105 }
83106
84107 async dragNode2 ( ) {
85- await this . dragAndDrop (
86- { x : 622 , y : 400 } ,
87- { x : 622 , y : 300 } ,
88- ) ;
108+ await this . dragAndDrop ( { x : 622 , y : 400 } , { x : 622 , y : 300 } ) ;
89109 await this . nextFrame ( ) ;
90110 }
91111
@@ -113,15 +133,15 @@ export class ComfyPage {
113133 async adjustWidgetValue ( ) {
114134 // Adjust Empty Latent Image's width input.
115135 const page = this . page ;
116- await page . locator ( ' #graph-canvas' ) . click ( {
136+ await page . locator ( " #graph-canvas" ) . click ( {
117137 position : {
118138 x : 724 ,
119- y : 645
120- }
139+ y : 645 ,
140+ } ,
121141 } ) ;
122142 await page . locator ( 'input[type="text"]' ) . click ( ) ;
123- await page . locator ( 'input[type="text"]' ) . fill ( ' 128' ) ;
124- await page . locator ( 'input[type="text"]' ) . press ( ' Enter' ) ;
143+ await page . locator ( 'input[type="text"]' ) . fill ( " 128" ) ;
144+ await page . locator ( 'input[type="text"]' ) . press ( " Enter" ) ;
125145 await this . nextFrame ( ) ;
126146 }
127147
@@ -140,7 +160,7 @@ export class ComfyPage {
140160 }
141161
142162 async rightClickCanvas ( ) {
143- await this . page . mouse . click ( 10 , 10 , { button : ' right' } ) ;
163+ await this . page . mouse . click ( 10 , 10 , { button : " right" } ) ;
144164 await this . nextFrame ( ) ;
145165 }
146166
@@ -153,7 +173,7 @@ export class ComfyPage {
153173 await this . canvas . click ( {
154174 position : {
155175 x : 724 ,
156- y : 625
176+ y : 625 ,
157177 } ,
158178 } ) ;
159179 this . page . mouse . move ( 10 , 10 ) ;
@@ -164,34 +184,34 @@ export class ComfyPage {
164184 await this . canvas . click ( {
165185 position : {
166186 x : 724 ,
167- y : 645
187+ y : 645 ,
168188 } ,
169- button : ' right'
189+ button : " right" ,
170190 } ) ;
171191 this . page . mouse . move ( 10 , 10 ) ;
172192 await this . nextFrame ( ) ;
173193 }
174194
175195 async select2Nodes ( ) {
176196 // Select 2 CLIP nodes.
177- await this . page . keyboard . down ( ' Control' ) ;
197+ await this . page . keyboard . down ( " Control" ) ;
178198 await this . clickTextEncodeNode1 ( ) ;
179199 await this . clickTextEncodeNode2 ( ) ;
180- await this . page . keyboard . up ( ' Control' ) ;
200+ await this . page . keyboard . up ( " Control" ) ;
181201 await this . nextFrame ( ) ;
182202 }
183203
184204 async ctrlC ( ) {
185- await this . page . keyboard . down ( ' Control' ) ;
186- await this . page . keyboard . press ( ' KeyC' ) ;
187- await this . page . keyboard . up ( ' Control' ) ;
205+ await this . page . keyboard . down ( " Control" ) ;
206+ await this . page . keyboard . press ( " KeyC" ) ;
207+ await this . page . keyboard . up ( " Control" ) ;
188208 await this . nextFrame ( ) ;
189209 }
190210
191211 async ctrlV ( ) {
192- await this . page . keyboard . down ( ' Control' ) ;
193- await this . page . keyboard . press ( ' KeyV' ) ;
194- await this . page . keyboard . up ( ' Control' ) ;
212+ await this . page . keyboard . down ( " Control" ) ;
213+ await this . page . keyboard . press ( " KeyV" ) ;
214+ await this . page . keyboard . up ( " Control" ) ;
195215 await this . nextFrame ( ) ;
196216 }
197217}
@@ -202,25 +222,27 @@ export const comfyPageFixture = base.extend<{ comfyPage: ComfyPage }>({
202222 await comfyPage . goto ( ) ;
203223 // Unify font for consistent screenshots.
204224 await page . addStyleTag ( {
205- 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"
225+ 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" ,
206226 } ) ;
207227 await page . addStyleTag ( {
208- 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"
228+ 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" ,
209229 } ) ;
210230 await page . addStyleTag ( {
211231 content : `
212232 * {
213233 font-family: 'Roboto Mono', 'Noto Color Emoji';
214- }`
234+ }` ,
215235 } ) ;
216236
217237 await page . waitForFunction ( ( ) => document . fonts . ready ) ;
218- await page . waitForFunction ( ( ) => window [ 'app' ] != undefined ) ;
219- await page . evaluate ( ( ) => { window [ 'app' ] [ 'canvas' ] . show_info = false ; } ) ;
238+ await page . waitForFunction ( ( ) => window [ "app" ] != undefined ) ;
239+ await page . evaluate ( ( ) => {
240+ window [ "app" ] [ "canvas" ] . show_info = false ;
241+ } ) ;
220242 await comfyPage . nextFrame ( ) ;
221243 // Reset view to force re-rendering of canvas. So that info fields like fps
222244 // become hidden.
223245 await comfyPage . resetView ( ) ;
224246 await use ( comfyPage ) ;
225247 } ,
226- } ) ;
248+ } ) ;
0 commit comments