@@ -24,6 +24,10 @@ export default class CodeGraph extends BasePage {
2424 return ( selector : string ) => this . container . locator ( selector ) ;
2525 }
2626
27+ private get activeGraphGetterName ( ) : "graphDesktop" | "graphMobile" {
28+ return this . isMobile ? "graphMobile" : "graphDesktop" ;
29+ }
30+
2731 /* NavBar Locators*/
2832 private get falkorDBLogo ( ) : Locator {
2933 return this . scopedLocator ( "//*[img[@alt='FalkorDB']]" )
@@ -417,19 +421,31 @@ export default class CodeGraph extends BasePage {
417421
418422 /* CodeGraph functionality */
419423 async selectGraph ( graph : string | number ) : Promise < void > {
424+ const previousGraphSnapshot = await this . getActiveGraphSnapshot ( ) ;
420425 await interactWhenVisible ( this . comboBoxbtn , ( el ) => el . click ( ) , 'ComboBox button' ) ;
421426 if ( typeof graph === 'number' ) {
422427 await interactWhenVisible ( this . selectGraphInComboBoxById ( graph . toString ( ) ) , ( el ) => el . click ( ) , `Graph option ${ graph } ` ) ;
423428 } else {
424429 await interactWhenVisible ( this . selectGraphInComboBoxByName ( graph ) , ( el ) => el . click ( ) , `Graph option ${ graph } ` ) ;
425430 }
426- const graphGetter = this . isMobile ? "graphMobile" : "graphDesktop" ;
427- await this . page . waitForFunction ( ( getterName ) => {
431+ await this . page . waitForFunction ( ( { getterName, previousGraphId, previousNodeIds } ) => {
428432 const getter = ( window as any ) [ getterName ] ;
429433 const graphData = typeof getter === "function" ? getter ( ) : null ;
430434 const nodes = graphData ?. elements ?. nodes || graphData ?. nodes ;
431- return Array . isArray ( nodes ) && nodes . length > 0 ;
432- } , graphGetter , { timeout : 10000 } ) ;
435+ if ( ! Array . isArray ( nodes ) || nodes . length === 0 ) return false ;
436+
437+ const currentGraphId = ( window as any ) . graph ?. Id != null ? String ( ( window as any ) . graph . Id ) : null ;
438+ if ( currentGraphId !== previousGraphId ) return true ;
439+
440+ const currentNodeIds = nodes . map ( ( node : { id : string | number } ) => String ( node . id ) ) . sort ( ) ;
441+ if ( currentNodeIds . length !== previousNodeIds . length ) return true ;
442+
443+ return currentNodeIds . some ( ( id : string , index : number ) => id !== previousNodeIds [ index ] ) ;
444+ } , {
445+ getterName : this . activeGraphGetterName ,
446+ previousGraphId : previousGraphSnapshot . graphId ,
447+ previousNodeIds : previousGraphSnapshot . nodeIds ,
448+ } , { timeout : 10000 } ) ;
433449 await this . waitForCanvasViewportToSettle ( ) ;
434450 }
435451
@@ -507,19 +523,26 @@ export default class CodeGraph extends BasePage {
507523 await this . waitForCanvasAnimationToEnd ( ) ;
508524 const boundingBox = await this . canvasElement . boundingBox ( ) ;
509525 if ( ! boundingBox ) throw new Error ( "Canvas bounding box not found" ) ;
510- const targetX = Math . min ( Math . max ( x , boundingBox . x + 1 ) , boundingBox . x + boundingBox . width - 1 ) ;
511- const targetY = Math . min ( Math . max ( y , boundingBox . y + 1 ) , boundingBox . y + boundingBox . height - 1 ) ;
526+ const maxX = boundingBox . x + boundingBox . width ;
527+ const maxY = boundingBox . y + boundingBox . height ;
528+ if ( x < boundingBox . x || x > maxX || y < boundingBox . y || y > maxY ) {
529+ throw new Error (
530+ `Node click coordinates (${ x } , ${ y } ) are outside canvas bounds ` +
531+ `[${ boundingBox . x } , ${ maxX } ] x [${ boundingBox . y } , ${ maxY } ]`
532+ ) ;
533+ }
534+
512535 for ( let attempt = 1 ; attempt <= 3 ; attempt ++ ) {
513- await this . page . mouse . move ( targetX , targetY ) ;
536+ await this . page . mouse . move ( x , y ) ;
514537 await this . page . waitForTimeout ( 500 ) ;
515- await this . page . mouse . click ( targetX , targetY , { button : 'right' } ) ;
516- if ( await this . elementMenu . isVisible ( ) ) {
538+ await this . page . mouse . click ( x , y , { button : 'right' } ) ;
539+ if ( await waitForElementToBeVisible ( this . elementMenuButton ( "View Node" ) , 100 , 5 ) ) {
517540 return ;
518541 }
519542 await this . page . waitForTimeout ( 1000 ) ;
520543 }
521544
522- throw new Error ( `Failed to click, elementMenu not visible after multiple attempts.` ) ;
545+ throw new Error ( `Failed to open node context menu at ( ${ x } , ${ y } ); "View Node" did not appear after multiple attempts.` ) ;
523546 }
524547
525548
@@ -624,18 +647,18 @@ export default class CodeGraph extends BasePage {
624647
625648 private async waitForGraphData ( ) : Promise < any > {
626649 await this . waitForCanvasAnimationToEnd ( ) ;
627- // Wait for the graph data to be available
628- await this . page . waitForFunction ( ( ) => {
629- const data = ( window as any ) . graphDesktop ?.( ) ;
630- return data && ( ( Array . isArray ( data . nodes ) && data . nodes . length > 0 ) ||
631- ( data . elements && Array . isArray ( data . elements . nodes ) && data . elements . nodes . length > 0 ) ) ;
632- } , { timeout : 5000 } ) ;
633-
634- // Safety guard: wait for engine to fully stop and data to settle
650+ await this . page . waitForFunction ( ( getterName ) => {
651+ const getter = ( window as any ) [ getterName ] ;
652+ const data = typeof getter === "function" ? getter ( ) : null ;
653+ const nodes = data ?. elements ?. nodes || data ?. nodes ;
654+ return Array . isArray ( nodes ) && nodes . length > 0 ;
655+ } , this . activeGraphGetterName , { timeout : 5000 } ) ;
635656 await this . page . waitForTimeout ( 3000 ) ;
636657 await this . waitForCanvasAnimationToEnd ( ) ;
637658
638- return await this . page . evaluate ( ( ) => ( window as any ) . graphDesktop ( ) ) ;
659+ const graphData = await this . getActiveGraphData ( ) ;
660+ if ( ! graphData ) throw new Error ( `Graph data not available from ${ this . activeGraphGetterName } ` ) ;
661+ return graphData ;
639662 }
640663
641664 async getGraphNodes ( ) : Promise < any [ ] > {
@@ -814,4 +837,24 @@ export default class CodeGraph extends BasePage {
814837
815838 throw new Error ( "Canvas viewport did not settle after graph selection" ) ;
816839 }
840+
841+ private async getActiveGraphData ( ) : Promise < any | null > {
842+ return await this . page . evaluate ( ( getterName ) => {
843+ const getter = ( window as any ) [ getterName ] ;
844+ return typeof getter === "function" ? getter ( ) : null ;
845+ } , this . activeGraphGetterName ) ;
846+ }
847+
848+ private async getActiveGraphSnapshot ( ) : Promise < { graphId : string | null ; nodeIds : string [ ] } > {
849+ return await this . page . evaluate ( ( getterName ) => {
850+ const getter = ( window as any ) [ getterName ] ;
851+ const graphData = typeof getter === "function" ? getter ( ) : null ;
852+ const nodes = graphData ?. elements ?. nodes || graphData ?. nodes || [ ] ;
853+
854+ return {
855+ graphId : ( window as any ) . graph ?. Id != null ? String ( ( window as any ) . graph . Id ) : null ,
856+ nodeIds : Array . isArray ( nodes ) ? nodes . map ( ( node : { id : string | number } ) => String ( node . id ) ) . sort ( ) : [ ] ,
857+ } ;
858+ } , this . activeGraphGetterName ) ;
859+ }
817860}
0 commit comments