@@ -803,3 +803,222 @@ test.describe('Viewport settings', () => {
803803 )
804804 } )
805805} )
806+
807+ test . describe ( 'Canvas Navigation' , ( ) => {
808+ test . describe ( 'Legacy Mode' , ( ) => {
809+ test . beforeEach ( async ( { comfyPage } ) => {
810+ await comfyPage . setSetting ( 'Comfy.Canvas.NavigationMode' , 'legacy' )
811+ } )
812+
813+ test ( 'Left-click drag in empty area should pan canvas' , async ( {
814+ comfyPage
815+ } ) => {
816+ await comfyPage . dragAndDrop ( { x : 50 , y : 50 } , { x : 150 , y : 150 } )
817+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
818+ 'legacy-left-drag-pan.png'
819+ )
820+ } )
821+
822+ test ( 'Middle-click drag should pan canvas' , async ( { comfyPage } ) => {
823+ await comfyPage . page . mouse . move ( 50 , 50 )
824+ await comfyPage . page . mouse . down ( { button : 'middle' } )
825+ await comfyPage . page . mouse . move ( 150 , 150 )
826+ await comfyPage . page . mouse . up ( { button : 'middle' } )
827+ await comfyPage . nextFrame ( )
828+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
829+ 'legacy-middle-drag-pan.png'
830+ )
831+ } )
832+
833+ test ( 'Mouse wheel should zoom in/out' , async ( { comfyPage } ) => {
834+ await comfyPage . page . mouse . move ( 400 , 300 )
835+ await comfyPage . page . mouse . wheel ( 0 , - 120 )
836+ await comfyPage . nextFrame ( )
837+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
838+ 'legacy-wheel-zoom-in.png'
839+ )
840+
841+ await comfyPage . page . mouse . wheel ( 0 , 240 )
842+ await comfyPage . nextFrame ( )
843+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
844+ 'legacy-wheel-zoom-out.png'
845+ )
846+ } )
847+
848+ test ( 'Left-click on node should not pan canvas' , async ( { comfyPage } ) => {
849+ await comfyPage . clickTextEncodeNode1 ( )
850+ const selectedCount = await comfyPage . getSelectedGraphNodesCount ( )
851+ expect ( selectedCount ) . toBe ( 1 )
852+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
853+ 'legacy-click-node-select.png'
854+ )
855+ } )
856+ } )
857+
858+ test . describe ( 'Standard Mode' , ( ) => {
859+ test . beforeEach ( async ( { comfyPage } ) => {
860+ await comfyPage . setSetting ( 'Comfy.Canvas.NavigationMode' , 'standard' )
861+ } )
862+
863+ test ( 'Left-click drag in empty area should select nodes' , async ( {
864+ comfyPage
865+ } ) => {
866+ const clipNodes = await comfyPage . getNodeRefsByType ( 'CLIPTextEncode' )
867+ const clipNode1Pos = await clipNodes [ 0 ] . getPosition ( )
868+ const clipNode2Pos = await clipNodes [ 1 ] . getPosition ( )
869+ const offset = 64
870+
871+ await comfyPage . dragAndDrop (
872+ {
873+ x : Math . min ( clipNode1Pos . x , clipNode2Pos . x ) - offset ,
874+ y : Math . min ( clipNode1Pos . y , clipNode2Pos . y ) - offset
875+ } ,
876+ {
877+ x : Math . max ( clipNode1Pos . x , clipNode2Pos . x ) + offset ,
878+ y : Math . max ( clipNode1Pos . y , clipNode2Pos . y ) + offset
879+ }
880+ )
881+
882+ const selectedCount = await comfyPage . getSelectedGraphNodesCount ( )
883+ expect ( selectedCount ) . toBe ( clipNodes . length )
884+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
885+ 'standard-left-drag-select.png'
886+ )
887+ } )
888+
889+ test ( 'Middle-click drag should pan canvas' , async ( { comfyPage } ) => {
890+ await comfyPage . page . mouse . move ( 50 , 50 )
891+ await comfyPage . page . mouse . down ( { button : 'middle' } )
892+ await comfyPage . page . mouse . move ( 150 , 150 )
893+ await comfyPage . page . mouse . up ( { button : 'middle' } )
894+ await comfyPage . nextFrame ( )
895+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
896+ 'standard-middle-drag-pan.png'
897+ )
898+ } )
899+
900+ test ( 'Ctrl + mouse wheel should zoom in/out' , async ( { comfyPage } ) => {
901+ await comfyPage . page . mouse . move ( 400 , 300 )
902+ await comfyPage . page . keyboard . down ( 'Control' )
903+ await comfyPage . page . mouse . wheel ( 0 , - 120 )
904+ await comfyPage . page . keyboard . up ( 'Control' )
905+ await comfyPage . nextFrame ( )
906+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
907+ 'standard-ctrl-wheel-zoom-in.png'
908+ )
909+
910+ await comfyPage . page . keyboard . down ( 'Control' )
911+ await comfyPage . page . mouse . wheel ( 0 , 240 )
912+ await comfyPage . page . keyboard . up ( 'Control' )
913+ await comfyPage . nextFrame ( )
914+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
915+ 'standard-ctrl-wheel-zoom-out.png'
916+ )
917+ } )
918+
919+ test ( 'Left-click on node should select node (not start selection box)' , async ( {
920+ comfyPage
921+ } ) => {
922+ await comfyPage . clickTextEncodeNode1 ( )
923+ const selectedCount = await comfyPage . getSelectedGraphNodesCount ( )
924+ expect ( selectedCount ) . toBe ( 1 )
925+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
926+ 'standard-click-node-select.png'
927+ )
928+ } )
929+
930+ test ( 'Space + left-click drag should pan canvas' , async ( { comfyPage } ) => {
931+ // Click canvas to focus it
932+ await comfyPage . page . click ( 'canvas' )
933+ await comfyPage . nextFrame ( )
934+
935+ await comfyPage . page . keyboard . down ( 'Space' )
936+ await comfyPage . dragAndDrop ( { x : 50 , y : 50 } , { x : 150 , y : 150 } )
937+ await comfyPage . page . keyboard . up ( 'Space' )
938+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
939+ 'standard-space-drag-pan.png'
940+ )
941+ } )
942+
943+ test ( 'Space key overrides default left-click behavior' , async ( {
944+ comfyPage
945+ } ) => {
946+ const clipNodes = await comfyPage . getNodeRefsByType ( 'CLIPTextEncode' )
947+ const clipNode1Pos = await clipNodes [ 0 ] . getPosition ( )
948+ const offset = 64
949+
950+ await comfyPage . dragAndDrop (
951+ {
952+ x : clipNode1Pos . x - offset ,
953+ y : clipNode1Pos . y - offset
954+ } ,
955+ {
956+ x : clipNode1Pos . x + offset ,
957+ y : clipNode1Pos . y + offset
958+ }
959+ )
960+
961+ const selectedCountAfterDrag =
962+ await comfyPage . getSelectedGraphNodesCount ( )
963+ expect ( selectedCountAfterDrag ) . toBeGreaterThan ( 0 )
964+
965+ await comfyPage . clickEmptySpace ( )
966+ const selectedCountAfterClear =
967+ await comfyPage . getSelectedGraphNodesCount ( )
968+ expect ( selectedCountAfterClear ) . toBe ( 0 )
969+
970+ await comfyPage . page . keyboard . down ( 'Space' )
971+ await comfyPage . dragAndDrop (
972+ {
973+ x : clipNode1Pos . x - offset ,
974+ y : clipNode1Pos . y - offset
975+ } ,
976+ {
977+ x : clipNode1Pos . x + offset ,
978+ y : clipNode1Pos . y + offset
979+ }
980+ )
981+ await comfyPage . page . keyboard . up ( 'Space' )
982+
983+ const selectedCountAfterSpaceDrag =
984+ await comfyPage . getSelectedGraphNodesCount ( )
985+ expect ( selectedCountAfterSpaceDrag ) . toBe ( 0 )
986+ } )
987+ } )
988+
989+ test . describe ( 'Edge Cases' , ( ) => {
990+ test ( 'Multiple modifier keys work correctly in legacy mode' , async ( {
991+ comfyPage
992+ } ) => {
993+ await comfyPage . setSetting ( 'Comfy.Canvas.NavigationMode' , 'legacy' )
994+
995+ await comfyPage . page . keyboard . down ( 'Alt' )
996+ await comfyPage . page . keyboard . down ( 'Shift' )
997+ await comfyPage . dragAndDrop ( { x : 50 , y : 50 } , { x : 150 , y : 150 } )
998+ await comfyPage . page . keyboard . up ( 'Shift' )
999+ await comfyPage . page . keyboard . up ( 'Alt' )
1000+
1001+ await expect ( comfyPage . canvas ) . toHaveScreenshot (
1002+ 'legacy-alt-shift-drag.png'
1003+ )
1004+ } )
1005+
1006+ test ( 'Cursor changes appropriately in different modes' , async ( {
1007+ comfyPage
1008+ } ) => {
1009+ const getCursorStyle = async ( ) => {
1010+ return await comfyPage . page . evaluate ( ( ) => {
1011+ return (
1012+ document . getElementById ( 'graph-canvas' ) ! . style . cursor || 'default'
1013+ )
1014+ } )
1015+ }
1016+
1017+ await comfyPage . setSetting ( 'Comfy.Canvas.NavigationMode' , 'legacy' )
1018+ await comfyPage . page . mouse . move ( 50 , 50 )
1019+ await comfyPage . page . mouse . down ( )
1020+ expect ( await getCursorStyle ( ) ) . toBe ( 'grabbing' )
1021+ await comfyPage . page . mouse . up ( )
1022+ } )
1023+ } )
1024+ } )
0 commit comments