@@ -289,4 +289,172 @@ public async Task BreakpointPausesExecutionAndShowsStatusMessage()
289289 // The status message should eventually disappear when program ends
290290 // (or show debugging status without breakpoint)
291291 }
292+
293+ [ Fact ( Timeout = 180_000 ) ]
294+ public async Task DynamicBreakpoint_CanBeAddedDuringDebugSession ( )
295+ {
296+ // This test validates the complete workflow of adding a breakpoint
297+ // DURING an active debug session (not before building)
298+
299+ // Arrange - Create project with two WriteLine nodes
300+ await HomePage . CreateNewProject ( ) ;
301+ await HomePage . OpenProjectExplorerProjectTab ( ) ;
302+ await HomePage . HasClass ( "Program" ) ;
303+ await HomePage . ClickClass ( "Program" ) ;
304+ await HomePage . OpenMethod ( "Main" ) ;
305+
306+ await Task . Delay ( 500 ) ;
307+
308+ // Move Return node to make space for our nodes
309+ await HomePage . DragNodeTo ( "Return" , 1800 , 200 ) ;
310+ await Task . Delay ( 200 ) ;
311+
312+ // Add first WriteLine node
313+ await HomePage . ClickAddNodeButton ( ) ;
314+ await HomePage . SearchNodeInPopup ( "WriteLine" ) ;
315+ await HomePage . SelectNodeFromPopup ( "WriteLine" ) ;
316+ await Task . Delay ( 500 ) ;
317+
318+ // Move WriteLine1 and set its text
319+ await HomePage . DragNodeTo ( "WriteLine" , 600 , 200 ) ;
320+ await Task . Delay ( 200 ) ;
321+ await HomePage . SetNodeInputValue ( "WriteLine" , "Text" , "\" First WriteLine\" " ) ;
322+ await Task . Delay ( 200 ) ;
323+
324+ // Add second WriteLine node
325+ await HomePage . ClickAddNodeButton ( ) ;
326+ await HomePage . SearchNodeInPopup ( "WriteLine" ) ;
327+ await HomePage . SelectNodeFromPopup ( "WriteLine" ) ;
328+ await Task . Delay ( 500 ) ;
329+
330+ // There are now 2 WriteLines - need to identify them by position or other means
331+ // Move the second one to a different location
332+ var writeLineNodes = HomePage . GetGraphNodes ( "WriteLine" ) ;
333+ var writeLine2 = await writeLineNodes . Nth ( 1 ) . ElementHandleAsync ( ) ;
334+ if ( writeLine2 != null )
335+ {
336+ var box = await writeLine2 . BoundingBoxAsync ( ) ;
337+ if ( box != null )
338+ {
339+ // Drag second WriteLine to position
340+ await Page . Mouse . MoveAsync ( box . X + box . Width / 2 , box . Y + box . Height / 2 ) ;
341+ await Page . Mouse . DownAsync ( ) ;
342+ await Task . Delay ( 50 ) ;
343+ await Page . Mouse . MoveAsync ( 1000 , 200 , new ( ) { Steps = 20 } ) ;
344+ await Task . Delay ( 50 ) ;
345+ await Page . Mouse . UpAsync ( ) ;
346+ await Task . Delay ( 500 ) ;
347+ }
348+ }
349+
350+ // Add Sleep node to give us time to add late breakpoint
351+ await HomePage . ClickAddNodeButton ( ) ;
352+ await HomePage . SearchNodeInPopup ( "Sleep" ) ;
353+ await HomePage . SelectNodeFromPopup ( "Sleep" ) ;
354+ await Task . Delay ( 500 ) ;
355+
356+ // Move Sleep node
357+ await HomePage . DragNodeTo ( "Sleep" , 1400 , 200 ) ;
358+ await Task . Delay ( 200 ) ;
359+ await HomePage . SetNodeInputValue ( "Sleep" , "TimeMilliseconds" , "3000" ) ; // 3 seconds
360+ await Task . Delay ( 200 ) ;
361+
362+ // Connect nodes: Entry -> WriteLine1 -> WriteLine2 -> Sleep -> Return
363+ await HomePage . ConnectPorts ( "Entry" , "Exec" , "WriteLine" , "Exec" ) ;
364+ await Task . Delay ( 300 ) ;
365+
366+ // For second WriteLine, we need to find it by position
367+ // Connect first WriteLine output to second WriteLine input
368+ var writeLine1Port = HomePage . GetGraphPort ( "WriteLine" , "Exec" , isInput : false ) ;
369+ var writeLine2Node = await writeLineNodes . Nth ( 1 ) . ElementHandleAsync ( ) ;
370+ if ( writeLine2Node != null )
371+ {
372+ // Click on WriteLine1 output port
373+ var portBox = await writeLine1Port . BoundingBoxAsync ( ) ;
374+ if ( portBox != null )
375+ {
376+ await Page . Mouse . ClickAsync ( portBox . X + portBox . Width / 2 , portBox . Y + portBox . Height / 2 ) ;
377+ await Task . Delay ( 200 ) ;
378+
379+ // Click on WriteLine2 input port
380+ var targetBox = await writeLine2Node . BoundingBoxAsync ( ) ;
381+ if ( targetBox != null )
382+ {
383+ await Page . Mouse . ClickAsync ( targetBox . X + 20 , targetBox . Y + 30 ) ; // Approximate input port position
384+ await Task . Delay ( 500 ) ;
385+ }
386+ }
387+ }
388+
389+ // Continue connecting: last node outputs to Sleep and Return
390+ await HomePage . ConnectPorts ( "Sleep" , "Exec" , "Return" , "Exec" ) ;
391+ await Task . Delay ( 300 ) ;
392+
393+ // Add initial breakpoint to FIRST WriteLine only
394+ var firstWriteLine = await writeLineNodes . First . ElementHandleAsync ( ) ;
395+ if ( firstWriteLine != null )
396+ {
397+ var box = await firstWriteLine . BoundingBoxAsync ( ) ;
398+ if ( box != null )
399+ {
400+ await Page . Mouse . ClickAsync ( box . X + box . Width / 2 , box . Y + 20 ) ; // Click title
401+ await Task . Delay ( 200 ) ;
402+ await Page . Keyboard . PressAsync ( "F9" ) ;
403+ await Task . Delay ( 500 ) ;
404+ }
405+ }
406+
407+ // Take screenshot showing initial setup
408+ await HomePage . TakeScreenshot ( "/tmp/dynamic-bp-initial-setup.png" ) ;
409+
410+ // Build the project
411+ var buildButton = Page . Locator ( "[data-test-id='build-project']" ) ;
412+ await buildButton . ClickAsync ( ) ;
413+ await Task . Delay ( 3000 ) ; // Wait for build
414+
415+ // Run with debug
416+ await HomePage . RunWithDebug ( ) ;
417+ await Task . Delay ( 2000 ) ; // Wait for first breakpoint to hit
418+
419+ // Take screenshot at first breakpoint
420+ await HomePage . TakeScreenshot ( "/tmp/dynamic-bp-first-hit.png" ) ;
421+
422+ // Click Continue to resume
423+ await HomePage . ClickContinueButton ( ) ;
424+ await Task . Delay ( 1000 ) ;
425+
426+ // NOW add breakpoint to SECOND WriteLine dynamically (while debugging!)
427+ var secondWriteLine = await writeLineNodes . Nth ( 1 ) . ElementHandleAsync ( ) ;
428+ if ( secondWriteLine != null )
429+ {
430+ var box = await secondWriteLine . BoundingBoxAsync ( ) ;
431+ if ( box != null )
432+ {
433+ await Page . Mouse . ClickAsync ( box . X + box . Width / 2 , box . Y + 20 ) ; // Click title
434+ await Task . Delay ( 200 ) ;
435+ await Page . Keyboard . PressAsync ( "F9" ) ; // Add breakpoint DURING debugging!
436+ await Task . Delay ( 500 ) ;
437+ }
438+ }
439+
440+ // Take screenshot showing dynamic breakpoint added
441+ await HomePage . TakeScreenshot ( "/tmp/dynamic-bp-added.png" ) ;
442+
443+ // Wait for second (dynamic) breakpoint to hit
444+ await Task . Delay ( 2000 ) ;
445+
446+ // Take screenshot at second breakpoint
447+ await HomePage . TakeScreenshot ( "/tmp/dynamic-bp-second-hit.png" ) ;
448+
449+ // Verify pause message appears (indicates second breakpoint was hit)
450+ var breakpointStatusExists = await Page . Locator ( "[data-test-id='breakpoint-status-text']" ) . CountAsync ( ) > 0 ;
451+ Assert . True ( breakpointStatusExists , "Should be paused at the dynamically-added breakpoint" ) ;
452+
453+ // Continue to finish execution
454+ await HomePage . ClickContinueButton ( ) ;
455+ await Task . Delay ( 1000 ) ;
456+
457+ // SUCCESS! Both initial and dynamic breakpoints worked
458+ Console . WriteLine ( "✓ Dynamic breakpoint test passed - breakpoint added during debug session was hit!" ) ;
459+ }
292460}
0 commit comments