Skip to content

Commit 5c66c2c

Browse files
committed
Enhance dispose logic in ComponentsPacksWebviewMain to handle unsaved changes; implement save, discard, and cancel options for user prompts.
1 parent 5809937 commit 5c66c2c

1 file changed

Lines changed: 59 additions & 6 deletions

File tree

src/views/manage-components-packs/components-packs-webview-main.test.ts

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)