@@ -324,14 +324,15 @@ describe('ComponentsPacksWebviewMain', () => {
324324 jest . restoreAllMocks ( ) ;
325325 } ) ;
326326
327- it ( 'calls debounce_load with project id and reload=true when a valid project exists ' , async ( ) => {
327+ it ( 'calls debounce_load with project id and reload=false when selected project is unchanged ' , async ( ) => {
328328 const debounceSpy = jest . spyOn ( componentsPacksWebviewMain as any , 'debounce_load' ) . mockResolvedValue ( undefined ) ;
329329 jest . spyOn ( componentsPacksWebviewMain as any , 'getValidProjectId' ) . mockReturnValue ( 'projValid' ) ;
330+ jest . spyOn ( componentsPacksWebviewMain as any , 'projectFromPath' ) . mockReturnValue ( 'sameProject' ) ;
330331
331332 await ( componentsPacksWebviewMain as any ) . handleMessage ( { type : 'REQUEST_INITIAL_DATA' } ) ;
332333
333334 expect ( debounceSpy ) . toHaveBeenCalledTimes ( 1 ) ;
334- expect ( debounceSpy ) . toHaveBeenCalledWith ( 'projValid' , true ) ;
335+ expect ( debounceSpy ) . toHaveBeenCalledWith ( 'projValid' , false ) ;
335336 } ) ;
336337
337338 it ( 'does not call debounce_load when no valid project id exists' , async ( ) => {
@@ -572,7 +573,7 @@ describe('ComponentsPacksWebviewMain', () => {
572573 'Connecting to rpc daemon' ,
573574 'Loading Packs...' ,
574575 'Loading Solution...' ,
575- 'Fetching Packs Info ...'
576+ 'Retrieving assigned items ...'
576577 ] )
577578 ) ;
578579 expect ( stateMessages . indexOf ( 'Connecting to rpc daemon' ) ) . toBeLessThan ( stateMessages . indexOf ( 'Loading Packs...' ) ) ;
@@ -598,6 +599,7 @@ describe('ComponentsPacksWebviewMain', () => {
598599 it ( 'skips heavy reload steps when reload=false' , async ( ) => {
599600 const svc = setupCsolutionServiceMocks ( ) ;
600601
602+ ( componentsPacksWebviewMain as any ) . usedItems = usedItemsReturn ;
601603 await ( componentsPacksWebviewMain as any ) . loadSolution ( 'solPath' , 'activeTs' , 'activeCtx' , false ) ;
602604
603605 // Heavy operations not called
@@ -613,8 +615,8 @@ describe('ComponentsPacksWebviewMain', () => {
613615 const compTreeMsg = webviewManager . sendMessage . mock . calls . map ( c => c [ 0 ] ) . find ( m => m . type === 'SOLUTION_LOADED' ) ;
614616 expect ( compTreeMsg ?. componentTree ) . toBe ( componentTreeReturn ) ;
615617
616- // usedItems is set
617- expect ( ( componentsPacksWebviewMain as any ) . usedItems ) . toBeDefined ( ) ;
618+ // usedItems is not refreshed in reload=false path
619+ expect ( ( componentsPacksWebviewMain as any ) . usedItems ) . toBe ( usedItemsReturn ) ;
618620 } ) ;
619621
620622 it ( 'handles errors and sends error messages' , async ( ) => {
@@ -892,17 +894,68 @@ describe('ComponentsPacksWebviewMain', () => {
892894 expect ( spy ) . toHaveBeenCalledWith ( { newState : { solutionPath : 'sol' } , previousState : { solutionPath : '' } } ) ;
893895 } ) ;
894896
895- it ( 'resets cached state when panel disposes' , ( ) => {
897+ it ( 'resets cached state when panel disposes without unsaved changes' , async ( ) => {
898+ jest . spyOn ( componentsPacksWebviewMain as any , 'isDirty' ) . mockResolvedValue ( false ) ;
899+ const warningSpy = jest . spyOn ( vscode . window , 'showWarningMessage' ) ;
896900 ( componentsPacksWebviewMain as any ) . currentProject = { solutionPath : 'sol' , project : { projectId : 'proj' , projectName : 'proj' } } ;
897901 ( componentsPacksWebviewMain as any ) . componentTree = { success : true , classes : [ { } ] } ;
898902 ( componentsPacksWebviewMain as any ) . validations = { success : true , result : 'OK' , validation : [ { id : 'val' } ] } ;
899903
900904 webviewManager . didDisposeEmitter . fire ( ) ;
905+ await waitTimeout ( ) ;
901906
907+ expect ( warningSpy ) . not . toHaveBeenCalled ( ) ;
902908 expect ( ( componentsPacksWebviewMain as any ) . currentProject ) . toBeUndefined ( ) ;
903909 expect ( ( componentsPacksWebviewMain as any ) . componentTree ) . toEqual ( { success : false , classes : [ ] } ) ;
904910 expect ( ( componentsPacksWebviewMain as any ) . validations ) . toEqual ( { success : false , result : 'UNDEFINED' , validation : [ ] } ) ;
905911 } ) ;
912+
913+ it ( 'saves and then disposes when user picks Save on unsaved changes' , async ( ) => {
914+ jest . spyOn ( componentsPacksWebviewMain as any , 'isDirty' ) . mockResolvedValue ( true ) ;
915+ const applySpy = jest . spyOn ( componentsPacksWebviewMain as any , 'handleApplyComponentSet' ) . mockResolvedValue ( undefined ) ;
916+ jest . spyOn ( vscode . window , 'showWarningMessage' ) . mockResolvedValue ( { title : 'Save' } as any ) ;
917+
918+ ( componentsPacksWebviewMain as any ) . currentProject = { solutionPath : 'sol' , project : { projectId : 'proj' , projectName : 'proj' } } ;
919+
920+ webviewManager . didDisposeEmitter . fire ( ) ;
921+ await waitTimeout ( ) ;
922+
923+ expect ( applySpy ) . toHaveBeenCalledTimes ( 1 ) ;
924+ expect ( ( componentsPacksWebviewMain as any ) . currentProject ) . toBeUndefined ( ) ;
925+ } ) ;
926+
927+ it ( 'disposes without saving when user picks Don\'t Save on unsaved changes' , async ( ) => {
928+ jest . spyOn ( componentsPacksWebviewMain as any , 'isDirty' ) . mockResolvedValue ( true ) ;
929+ const applySpy = jest . spyOn ( componentsPacksWebviewMain as any , 'handleApplyComponentSet' ) . mockResolvedValue ( undefined ) ;
930+ jest . spyOn ( vscode . window , 'showWarningMessage' ) . mockResolvedValue ( { title : "Don't Save" } as any ) ;
931+
932+ ( componentsPacksWebviewMain as any ) . currentProject = { solutionPath : 'sol' , project : { projectId : 'proj' , projectName : 'proj' } } ;
933+
934+ webviewManager . didDisposeEmitter . fire ( ) ;
935+ await waitTimeout ( ) ;
936+
937+ expect ( applySpy ) . not . toHaveBeenCalled ( ) ;
938+ expect ( ( componentsPacksWebviewMain as any ) . currentProject ) . toBeUndefined ( ) ;
939+ } ) ;
940+
941+ it ( 'reopens panel and keeps state when user picks Cancel on unsaved changes' , async ( ) => {
942+ jest . spyOn ( componentsPacksWebviewMain as any , 'isDirty' ) . mockResolvedValue ( true ) ;
943+ const applySpy = jest . spyOn ( componentsPacksWebviewMain as any , 'handleApplyComponentSet' ) . mockResolvedValue ( undefined ) ;
944+ const reopenSpy = jest . spyOn ( ( componentsPacksWebviewMain as any ) . webviewManager , 'createOrShowPanel' ) ;
945+ jest . spyOn ( vscode . window , 'showWarningMessage' ) . mockResolvedValue ( { title : 'Cancel' } as any ) ;
946+
947+ ( componentsPacksWebviewMain as any ) . currentProject = { solutionPath : 'sol' , project : { projectId : 'proj' , projectName : 'proj' } } ;
948+
949+ webviewManager . didDisposeEmitter . fire ( ) ;
950+ await waitTimeout ( ) ;
951+
952+ expect ( applySpy ) . not . toHaveBeenCalled ( ) ;
953+ expect ( reopenSpy ) . toHaveBeenCalledTimes ( 1 ) ;
954+ expect ( ( componentsPacksWebviewMain as any ) . currentProject ) . toEqual ( {
955+ solutionPath : 'sol' ,
956+ project : { projectId : 'proj' , projectName : 'proj' }
957+ } ) ;
958+ } ) ;
906959 } ) ;
907960
908961 describe ( 'openWebview context selection' , ( ) => {
0 commit comments