@@ -148,12 +148,27 @@ describe('IderComponent', () => {
148148 it ( 'should create' , ( ) => {
149149 expect ( component ) . toBeTruthy ( )
150150 fixture . detectChanges ( )
151- expect ( tokenSpy ) . toHaveBeenCalled ( )
152- expect ( getPowerStateCachedSpy ) . toHaveBeenCalled ( )
151+ expect ( tokenSpy ) . not . toHaveBeenCalled ( )
152+ expect ( getPowerStateCachedSpy ) . not . toHaveBeenCalled ( )
153153 expect ( getAMTFeaturesCachedSpy ) . toHaveBeenCalled ( )
154154 expect ( getPowerStateSpy ) . not . toHaveBeenCalled ( )
155155 expect ( getAMTFeaturesSpy ) . not . toHaveBeenCalled ( )
156- expect ( getRedirectionStatusSpy ) . toHaveBeenCalled ( )
156+ expect ( getRedirectionStatusSpy ) . not . toHaveBeenCalled ( )
157+ } )
158+
159+ it ( 'prompts to enable IDER on tab load when IDER is disabled' , ( ) => {
160+ getAMTFeaturesCachedSpy . and . returnValue (
161+ of ( {
162+ ...amtFeaturesResponse ,
163+ IDER : false ,
164+ redirection : true
165+ } )
166+ )
167+
168+ fixture . detectChanges ( )
169+
170+ expect ( dialogSpy . open ) . toHaveBeenCalled ( )
171+ expect ( setAmtFeaturesSpy ) . toHaveBeenCalled ( )
157172 } )
158173
159174 it ( 'should set isDisconnecting to true on NavigationStart event' , ( ) => {
@@ -223,9 +238,25 @@ describe('IderComponent', () => {
223238 } )
224239 } )
225240
241+ it ( 'postUserConsentDecision short-circuits when file selection was canceled' , ( done ) => {
242+ tokenSpy . calls . reset ( )
243+ ; ( component as any ) . diskSelectionCanceled = true
244+ component . isLoading . set ( true )
245+ component . loadingStatus . set ( 'ider.status.connectingIder.value' )
246+
247+ component . postUserConsentDecision ( true ) . subscribe ( ( result ) => {
248+ expect ( result ) . toBeNull ( )
249+ expect ( component . isLoading ( ) ) . toBeFalse ( )
250+ expect ( component . loadingStatus ( ) ) . toBe ( '' )
251+ expect ( tokenSpy ) . not . toHaveBeenCalled ( )
252+ expect ( ( component as any ) . diskSelectionCanceled ) . toBeFalse ( )
253+ done ( )
254+ } )
255+ } )
256+
226257 it ( 'init runs consent handlers and refreshes token after consent success' , ( ) => {
227258 tokenSpy . calls . reset ( )
228- fixture . detectChanges ( )
259+ component . connect ( )
229260 expect ( component . loadingStatus ( ) ) . toBe ( 'ider.status.connectingIder.value' )
230261 expect ( userConsentService . handleUserConsentDecision ) . toHaveBeenCalledWith (
231262 true ,
@@ -236,6 +267,21 @@ describe('IderComponent', () => {
236267 expect ( tokenSpy . calls . count ( ) ) . toBe ( 1 )
237268 } )
238269
270+ it ( 'init stops before consent handlers when enabling IDER is declined' , ( ) => {
271+ tokenSpy . calls . reset ( )
272+ userConsentService . handleUserConsentDecision . calls . reset ( )
273+ userConsentService . handleUserConsentResponse . calls . reset ( )
274+ spyOn ( component , 'handleAMTFeaturesResponse' ) . and . returnValue ( of ( false ) )
275+
276+ component . connect ( )
277+
278+ expect ( userConsentService . handleUserConsentDecision ) . not . toHaveBeenCalled ( )
279+ expect ( userConsentService . handleUserConsentResponse ) . not . toHaveBeenCalled ( )
280+ expect ( component . isLoading ( ) ) . toBeFalse ( )
281+ expect ( component . loadingStatus ( ) ) . toBe ( '' )
282+ expect ( tokenSpy . calls . count ( ) ) . toBe ( 1 )
283+ } )
284+
239285 it ( 'postUserConsentDecision does not issue a duplicate AMT features fetch' , ( done ) => {
240286 getAMTFeaturesSpy . calls . reset ( )
241287 getAMTFeaturesCachedSpy . calls . reset ( )
@@ -477,13 +523,109 @@ describe('IderComponent', () => {
477523 expect ( component . diskImage ) . toBeNull ( )
478524 } )
479525
526+ it ( 'onAttachDiskImage starts connection and opens file picker' , ( ) => {
527+ const connectSpy = spyOn ( component , 'connect' )
528+ const mockFileInput = jasmine . createSpyObj ( 'HTMLInputElement' , [ 'click' ] ) as HTMLInputElement
529+ mockFileInput . value = 'existing.iso'
530+
531+ component . onAttachDiskImage ( mockFileInput )
532+
533+ expect ( mockFileInput . value ) . toBe ( '' )
534+ expect ( connectSpy ) . toHaveBeenCalled ( )
535+ expect ( mockFileInput . click ) . toHaveBeenCalled ( )
536+ } )
537+
538+ it ( 'onFileSelected does not start connection when a file is selected during active attach flow' , ( ) => {
539+ const connectSpy = spyOn ( component , 'connect' )
540+ const mockFile = new File ( [ '' ] , 'test-file.iso' , { type : 'application/octet-stream' } )
541+ const mockEvt = { target : { files : [ mockFile ] } } as unknown as Event
542+ component . isLoading . set ( true )
543+
544+ component . onFileSelected ( mockEvt )
545+
546+ expect ( connectSpy ) . not . toHaveBeenCalled ( )
547+ } )
548+
549+ it ( 'onFileSelected does not start connection when file selection is canceled' , ( ) => {
550+ const connectSpy = spyOn ( component , 'connect' )
551+ component . isLoading . set ( true )
552+ component . loadingStatus . set ( 'ider.status.connectingIder.value' )
553+ const mockEvt = { target : { files : [ ] } } as unknown as Event
554+
555+ component . onFileSelected ( mockEvt )
556+
557+ expect ( component . diskImage ) . toBeNull ( )
558+ expect ( component . deviceIDERConnection ( ) ) . toBeFalse ( )
559+ expect ( component . isLoading ( ) ) . toBeFalse ( )
560+ expect ( component . loadingStatus ( ) ) . toBe ( '' )
561+ expect ( connectSpy ) . not . toHaveBeenCalled ( )
562+ } )
563+
564+ it ( 'onAttachDiskImage ignores clicks while loading' , ( ) => {
565+ const connectSpy = spyOn ( component , 'connect' )
566+ const mockFileInput = jasmine . createSpyObj ( 'HTMLInputElement' , [ 'click' ] ) as HTMLInputElement
567+ component . isLoading . set ( true )
568+
569+ component . onAttachDiskImage ( mockFileInput )
570+
571+ expect ( connectSpy ) . not . toHaveBeenCalled ( )
572+ expect ( mockFileInput . click ) . not . toHaveBeenCalled ( )
573+ } )
574+
575+ it ( 'onAttachDiskImage warns and does not reconnect when IDER is already active' , ( ) => {
576+ const connectSpy = spyOn ( component , 'connect' )
577+ const mockFileInput = jasmine . createSpyObj ( 'HTMLInputElement' , [ 'click' ] ) as HTMLInputElement
578+ component . isIDERActive . set ( true )
579+
580+ component . onAttachDiskImage ( mockFileInput )
581+
582+ expect ( displayWarningSpy ) . toHaveBeenCalledWith ( 'ider.alreadyActiveWarning.value' )
583+ expect ( connectSpy ) . not . toHaveBeenCalled ( )
584+ expect ( mockFileInput . click ) . not . toHaveBeenCalled ( )
585+ } )
586+
587+ it ( 'onAttachDiskImage clears loading when picker closes without selecting a file' , ( ) => {
588+ const connectSpy = spyOn ( component , 'connect' )
589+ const mockFileInput = jasmine . createSpyObj ( 'HTMLInputElement' , [ 'click' ] ) as HTMLInputElement
590+
591+ component . onAttachDiskImage ( mockFileInput )
592+ component . isLoading . set ( true )
593+ component . loadingStatus . set ( 'ider.status.connectingIder.value' )
594+
595+ window . dispatchEvent ( new Event ( 'focus' ) )
596+
597+ expect ( connectSpy ) . toHaveBeenCalled ( )
598+ expect ( component . diskImage ) . toBeNull ( )
599+ expect ( component . isLoading ( ) ) . toBeFalse ( )
600+ expect ( component . loadingStatus ( ) ) . toBe ( '' )
601+ } )
602+
603+ it ( 'disables the Attach button when IDER is already active' , ( ) => {
604+ component . isIDERActive . set ( true )
605+ fixture . detectChanges ( )
606+
607+ const attachButton = fixture . nativeElement . querySelector ( 'button[color="primary"]' ) as HTMLButtonElement
608+
609+ expect ( attachButton . disabled ) . toBeTrue ( )
610+ } )
611+
480612 // onCancelIDER()
481613 it ( 'should set deviceIDERConnection to false on cancel IDER' , ( ) => {
482614 const deviceIDERConnectionSpy = spyOn ( component . deviceIDERConnection , 'set' )
483615 component . onCancelIDER ( )
484616 expect ( deviceIDERConnectionSpy ) . toHaveBeenCalledWith ( false )
485617 } )
486618
619+ it ( 'should clear loading state on cancel IDER' , ( ) => {
620+ component . isLoading . set ( true )
621+ component . loadingStatus . set ( 'ider.status.connectingIder.value' )
622+
623+ component . onCancelIDER ( )
624+
625+ expect ( component . isLoading ( ) ) . toBeFalse ( )
626+ expect ( component . loadingStatus ( ) ) . toBe ( '' )
627+ } )
628+
487629 it ( 'should clear file input value on cancel IDER' , ( ) => {
488630 const mockFileInput = document . createElement ( 'input' )
489631 mockFileInput . id = 'file'
0 commit comments