6.7 KiB
Connection 1:1 Constraint Test Plan
Issue Description
Two purple arrows (or multiple arrows) coming from the same connection point on an idea card. Each handle should support exactly ONE connection (1:1 constraint).
Implementation Details
Core Logic
The validateAndRemoveConflicts function enforces the 1:1 constraint:
- For any new connection, it checks all existing edges
- Removes edges that conflict with the source handle OR target handle
- Returns filtered edges, count of removed edges, and conflict descriptions
Key Functions Modified
- onConnect - Creates new connections with conflict resolution
- onReconnect - Remaps existing connections with conflict resolution
- validateAndRemoveConflicts - Core validation logic (new)
Test Cases
Test Case 1: Basic Connection Creation
Steps:
- Go to Feature Idea Cloud
- Click the 🔍 Debug button to open the debug panel
- Drag from Idea A's right handle to Idea B's left handle
- Verify in debug panel that:
- Idea A's right handle shows ✓ (occupied)
- Idea B's left handle shows ✓ (occupied)
- Total edges increased by 1
Expected Result: Connection created successfully, both handles marked as occupied
Test Case 2: Prevent Multiple Connections from Same Source Handle
Steps:
- Create connection: Idea A[right] → Idea B[left]
- Verify connection exists in debug panel
- Try to create: Idea A[right] → Idea C[left]
- Check debug panel and toast notification
Expected Result:
- Toast shows "Connection remapped! (1 old connection removed)"
- Idea A's right handle now connects to Idea C only
- Old connection to Idea B is removed
- Debug panel shows only 1 connection from Idea A's right handle
Test Case 3: Prevent Multiple Connections to Same Target Handle
Steps:
- Create connection: Idea A[right] → Idea B[left]
- Try to create: Idea C[right] → Idea B[left]
- Check debug panel
Expected Result:
- Toast shows "Connection remapped! (1 old connection removed)"
- Idea B's left handle now connects from Idea C only
- Old connection from Idea A is removed
- Debug panel shows only 1 connection to Idea B's left handle
Test Case 4: Reconnection (Remapping) from Source
Steps:
- Create connection: Idea A[right] → Idea B[left]
- Drag the source end (at Idea A) to Idea A's bottom handle
- Check debug panel
Expected Result:
- Connection now goes from Idea A[bottom] → Idea B[left]
- Idea A's right handle is now free (○)
- Idea A's bottom handle is now occupied (✓)
- Toast shows "Connection remapped!"
Test Case 5: Reconnection (Remapping) to Different Target
Steps:
- Create connection: Idea A[right] → Idea B[left]
- Drag the target end (at Idea B) to Idea C's left handle
- Check debug panel
Expected Result:
- Connection now goes from Idea A[right] → Idea C[left]
- Idea B's left handle is now free (○)
- Idea C's left handle is now occupied (✓)
Test Case 6: Reconnection with Conflict Resolution
Steps:
- Create connection 1: Idea A[right] → Idea B[left]
- Create connection 2: Idea C[right] → Idea D[left]
- Drag connection 2's target from Idea D to Idea B's left handle
- Check debug panel
Expected Result:
- Connection 1 is removed (conflict on Idea B's left handle)
- Connection 2 now goes: Idea C[right] → Idea B[left]
- Toast shows "Connection remapped! (1 conflicting connection removed)"
- Idea B's left handle shows only 1 connection total
Test Case 7: Database Persistence
Steps:
- Create several connections with various conflict resolutions
- Note the final state in the debug panel
- Refresh the page (F5)
- Open debug panel again
Expected Result:
- All connections persist exactly as they were
- No duplicate connections on any handle
- Debug panel shows same state as before refresh
Test Case 8: Console Logging Verification
Steps:
- Open browser DevTools console
- Create a new connection
- Look for log entries starting with
[Connection]
Expected Result:
[Connection] New connection attempt: { source: "idea-X[right]", target: "idea-Y[left]" }
[Connection Validator] Conflicts detected and resolved: [...] // (if conflicts exist)
[Connection] New edge created: edge-123456789
[Connection] Total edges after addition: N
[Connection] Edges by handle: [...]
Test Case 9: Multiple Handles Per Node
Steps:
- Create 4 different connections from a single idea using all 4 handles:
- Idea A[left] ← Idea B[right]
- Idea A[right] → Idea C[left]
- Idea A[top] ← Idea D[bottom]
- Idea A[bottom] → Idea E[top]
- Check debug panel for Idea A
Expected Result:
- All 4 handles show ✓ (occupied)
- Total connections for Idea A: 4
- Each handle has exactly 1 connection
- No conflicts exist
Test Case 10: Edge Case - Same Source and Target
Steps:
- Create connection: Idea A[right] → Idea B[left]
- Create connection: Idea C[right] → Idea D[left]
- Remap connection 2 to: Idea A[right] → Idea B[left]
Expected Result:
- Connection 1 is removed (conflicts on BOTH source AND target)
- Connection 2 takes over both handles
- Toast shows "Connection remapped! (1 conflicting connection removed)"
- Only 1 arrow exists between Idea A and Idea B
Visual Indicators in Debug Panel
The debug panel shows a grid for each idea card with 4 handle positions:
← ✓or← ○(left handle - incoming)→ ✓or→ ○(right handle - outgoing)↑ ✓or↑ ○(top handle - incoming)↓ ✓or↓ ○(bottom handle - outgoing)
Green background = Handle is occupied (✓) Gray background = Handle is free (○)
Success Criteria
✅ All test cases pass ✅ No multiple arrows from/to same connection point ✅ Automatic conflict resolution works correctly ✅ Changes persist to database ✅ Console logs provide clear debugging information ✅ Toast notifications inform user of remapping ✅ Debug panel accurately reflects connection state
How to Run Tests
- Navigate to Feature Idea Cloud page in the app
- Click the 🔍 debug icon in the top-right panel
- Follow each test case step-by-step
- Verify expected results using:
- Visual inspection of arrows on canvas
- Debug panel handle occupancy display
- Toast notifications
- Browser console logs
- Test persistence by refreshing the page
Notes for Developer
- The debug panel is ONLY for testing and can be removed once all tests pass
- All console.log statements with
[Connection]and[Reconnection]prefixes are for debugging - The validateAndRemoveConflicts function is the core of the 1:1 constraint
- Each handle ID is either 'left', 'right', 'top', 'bottom', or 'default'
- The logic treats missing sourceHandle/targetHandle as 'default'