@@ -26,6 +26,22 @@ vi.mock('@/stores/settingStore', () => ({
2626 } )
2727} ) )
2828
29+ vi . mock ( '@/scripts/api' , ( ) => ( {
30+ api : {
31+ addEventListener : vi . fn ( ) ,
32+ removeEventListener : vi . fn ( )
33+ }
34+ } ) )
35+
36+ vi . mock ( '@/composables/functional/useChainCallback' , ( ) => ( {
37+ useChainCallback : vi . fn ( ( original , ...callbacks ) => {
38+ return function ( this : any , ...args : any [ ] ) {
39+ original ?. apply ( this , args )
40+ callbacks . forEach ( ( cb : any ) => cb . apply ( this , args ) )
41+ }
42+ } )
43+ } ) )
44+
2945const FIRST_BACKOFF = 1000 // backoff is 1s on first retry
3046const DEFAULT_VALUE = 'Loading...'
3147
@@ -40,7 +56,9 @@ function createMockConfig(overrides = {}): RemoteWidgetConfig {
4056const createMockOptions = ( inputOverrides = { } ) => ( {
4157 remoteConfig : createMockConfig ( inputOverrides ) ,
4258 defaultValue : DEFAULT_VALUE ,
43- node : { } as any ,
59+ node : {
60+ addWidget : vi . fn ( )
61+ } as any ,
4462 widget : { } as any
4563} )
4664
@@ -499,4 +517,168 @@ describe('useRemoteWidget', () => {
499517 expect ( data2 ) . toEqual ( DEFAULT_VALUE )
500518 } )
501519 } )
520+
521+ describe ( 'auto-refresh on task completion' , ( ) => {
522+ it ( 'should add auto-refresh toggle widget' , ( ) => {
523+ const mockNode = {
524+ addWidget : vi . fn ( ) ,
525+ widgets : [ ]
526+ }
527+ const mockWidget = {
528+ refresh : vi . fn ( )
529+ }
530+
531+ useRemoteWidget ( {
532+ remoteConfig : createMockConfig ( ) ,
533+ defaultValue : DEFAULT_VALUE ,
534+ node : mockNode as any ,
535+ widget : mockWidget as any
536+ } )
537+
538+ // Should add auto-refresh toggle widget
539+ expect ( mockNode . addWidget ) . toHaveBeenCalledWith (
540+ 'toggle' ,
541+ 'Auto-refresh after generation' ,
542+ false ,
543+ expect . any ( Function ) ,
544+ {
545+ serialize : false
546+ }
547+ )
548+ } )
549+
550+ it ( 'should register event listener when enabled' , async ( ) => {
551+ const { api } = await import ( '@/scripts/api' )
552+
553+ const mockNode = {
554+ addWidget : vi . fn ( ) ,
555+ widgets : [ ]
556+ }
557+ const mockWidget = {
558+ refresh : vi . fn ( )
559+ }
560+
561+ useRemoteWidget ( {
562+ remoteConfig : createMockConfig ( ) ,
563+ defaultValue : DEFAULT_VALUE ,
564+ node : mockNode as any ,
565+ widget : mockWidget as any
566+ } )
567+
568+ // Event listener should be registered immediately
569+ expect ( api . addEventListener ) . toHaveBeenCalledWith (
570+ 'execution_success' ,
571+ expect . any ( Function )
572+ )
573+ } )
574+
575+ it ( 'should refresh widget when workflow completes successfully' , async ( ) => {
576+ const { api } = await import ( '@/scripts/api' )
577+ let executionSuccessHandler : ( ( ) => void ) | undefined
578+
579+ // Capture the event handler
580+ vi . mocked ( api . addEventListener ) . mockImplementation ( ( event , handler ) => {
581+ if ( event === 'execution_success' ) {
582+ executionSuccessHandler = handler as ( ) => void
583+ }
584+ } )
585+
586+ const mockNode = {
587+ addWidget : vi . fn ( ) ,
588+ widgets : [ ]
589+ }
590+ const mockWidget = { } as any
591+
592+ useRemoteWidget ( {
593+ remoteConfig : createMockConfig ( ) ,
594+ defaultValue : DEFAULT_VALUE ,
595+ node : mockNode as any ,
596+ widget : mockWidget
597+ } )
598+
599+ // Spy on the refresh function that was added by useRemoteWidget
600+ const refreshSpy = vi . spyOn ( mockWidget , 'refresh' )
601+
602+ // Get the toggle callback and enable auto-refresh
603+ const toggleCallback = mockNode . addWidget . mock . calls . find (
604+ ( call ) => call [ 0 ] === 'toggle'
605+ ) ?. [ 3 ]
606+ toggleCallback ?.( true )
607+
608+ // Simulate workflow completion
609+ executionSuccessHandler ?.( )
610+
611+ expect ( refreshSpy ) . toHaveBeenCalled ( )
612+ } )
613+
614+ it ( 'should not refresh when toggle is disabled' , async ( ) => {
615+ const { api } = await import ( '@/scripts/api' )
616+ let executionSuccessHandler : ( ( ) => void ) | undefined
617+
618+ // Capture the event handler
619+ vi . mocked ( api . addEventListener ) . mockImplementation ( ( event , handler ) => {
620+ if ( event === 'execution_success' ) {
621+ executionSuccessHandler = handler as ( ) => void
622+ }
623+ } )
624+
625+ const mockNode = {
626+ addWidget : vi . fn ( ) ,
627+ widgets : [ ]
628+ }
629+ const mockWidget = { } as any
630+
631+ useRemoteWidget ( {
632+ remoteConfig : createMockConfig ( ) ,
633+ defaultValue : DEFAULT_VALUE ,
634+ node : mockNode as any ,
635+ widget : mockWidget
636+ } )
637+
638+ // Spy on the refresh function that was added by useRemoteWidget
639+ const refreshSpy = vi . spyOn ( mockWidget , 'refresh' )
640+
641+ // Toggle is disabled by default
642+ // Simulate workflow completion
643+ executionSuccessHandler ?.( )
644+
645+ expect ( refreshSpy ) . not . toHaveBeenCalled ( )
646+ } )
647+
648+ it ( 'should cleanup event listener on node removal' , async ( ) => {
649+ const { api } = await import ( '@/scripts/api' )
650+ let executionSuccessHandler : ( ( ) => void ) | undefined
651+
652+ // Capture the event handler
653+ vi . mocked ( api . addEventListener ) . mockImplementation ( ( event , handler ) => {
654+ if ( event === 'execution_success' ) {
655+ executionSuccessHandler = handler as ( ) => void
656+ }
657+ } )
658+
659+ const mockNode = {
660+ addWidget : vi . fn ( ) ,
661+ widgets : [ ] ,
662+ onRemoved : undefined as any
663+ }
664+ const mockWidget = {
665+ refresh : vi . fn ( )
666+ }
667+
668+ useRemoteWidget ( {
669+ remoteConfig : createMockConfig ( ) ,
670+ defaultValue : DEFAULT_VALUE ,
671+ node : mockNode as any ,
672+ widget : mockWidget as any
673+ } )
674+
675+ // Simulate node removal
676+ mockNode . onRemoved ?.( )
677+
678+ expect ( api . removeEventListener ) . toHaveBeenCalledWith (
679+ 'execution_success' ,
680+ executionSuccessHandler
681+ )
682+ } )
683+ } )
502684} )
0 commit comments