@@ -687,4 +687,99 @@ test.describe('Vue Node Link Interaction', () => {
687
687
if ( shiftHeld ) await comfyPage . page . keyboard . up ( 'Shift' ) . catch ( ( ) => { } )
688
688
}
689
689
} )
690
+
691
+ test ( 'should snap to node center while dragging and link on drop' , async ( {
692
+ comfyPage,
693
+ comfyMouse
694
+ } ) => {
695
+ const clipNode = ( await comfyPage . getNodeRefsByType ( 'CLIPTextEncode' ) ) [ 0 ]
696
+ const samplerNode = ( await comfyPage . getNodeRefsByType ( 'KSampler' ) ) [ 0 ]
697
+ expect ( clipNode && samplerNode ) . toBeTruthy ( )
698
+
699
+ // Start drag from CLIP output[0]
700
+ const clipOutputCenter = await getSlotCenter (
701
+ comfyPage . page ,
702
+ clipNode . id ,
703
+ 0 ,
704
+ false
705
+ )
706
+
707
+ // Drag to the visual center of the KSampler Vue node (not a slot)
708
+ const samplerVue = comfyPage . vueNodes . getNodeLocator ( String ( samplerNode . id ) )
709
+ await expect ( samplerVue ) . toBeVisible ( )
710
+ const samplerCenter = await getCenter ( samplerVue )
711
+
712
+ await comfyMouse . move ( clipOutputCenter )
713
+ await comfyMouse . drag ( samplerCenter )
714
+
715
+ // During drag, the preview should snap/highlight a compatible input on KSampler
716
+ await expect ( comfyPage . canvas ) . toHaveScreenshot ( 'vue-node-snap-to-node.png' )
717
+
718
+ // Drop to create the link
719
+ await comfyMouse . drop ( )
720
+ await comfyPage . nextFrame ( )
721
+
722
+ // Validate a link was created to one of KSampler's compatible inputs (1 or 2)
723
+ const linkOnInput1 = await getInputLinkDetails (
724
+ comfyPage . page ,
725
+ samplerNode . id ,
726
+ 1
727
+ )
728
+ const linkOnInput2 = await getInputLinkDetails (
729
+ comfyPage . page ,
730
+ samplerNode . id ,
731
+ 2
732
+ )
733
+
734
+ const linked = linkOnInput1 ?? linkOnInput2
735
+ expect ( linked ) . not . toBeNull ( )
736
+ expect ( linked ?. originId ) . toBe ( clipNode . id )
737
+ expect ( linked ?. targetId ) . toBe ( samplerNode . id )
738
+ } )
739
+
740
+ test ( 'should snap to a specific compatible slot when targeting it' , async ( {
741
+ comfyPage,
742
+ comfyMouse
743
+ } ) => {
744
+ const clipNode = ( await comfyPage . getNodeRefsByType ( 'CLIPTextEncode' ) ) [ 0 ]
745
+ const samplerNode = ( await comfyPage . getNodeRefsByType ( 'KSampler' ) ) [ 0 ]
746
+ expect ( clipNode && samplerNode ) . toBeTruthy ( )
747
+
748
+ // Drag from CLIP output[0] to KSampler input[2] (third slot) which is the
749
+ // second compatible input for CLIP
750
+ const clipOutputCenter = await getSlotCenter (
751
+ comfyPage . page ,
752
+ clipNode . id ,
753
+ 0 ,
754
+ false
755
+ )
756
+ const samplerInput3Center = await getSlotCenter (
757
+ comfyPage . page ,
758
+ samplerNode . id ,
759
+ 2 ,
760
+ true
761
+ )
762
+
763
+ await comfyMouse . move ( clipOutputCenter )
764
+ await comfyMouse . drag ( samplerInput3Center )
765
+
766
+ // Expect the preview to show snapping to the targeted slot
767
+ await expect ( comfyPage . canvas ) . toHaveScreenshot ( 'vue-node-snap-to-slot.png' )
768
+
769
+ // Finish the connection
770
+ await comfyMouse . drop ( )
771
+ await comfyPage . nextFrame ( )
772
+
773
+ const linkDetails = await getInputLinkDetails (
774
+ comfyPage . page ,
775
+ samplerNode . id ,
776
+ 2
777
+ )
778
+ expect ( linkDetails ) . not . toBeNull ( )
779
+ expect ( linkDetails ) . toMatchObject ( {
780
+ originId : clipNode . id ,
781
+ targetId : samplerNode . id ,
782
+ targetSlot : 2
783
+ } )
784
+ } )
690
785
} )
0 commit comments