Skip to content

Commit

Permalink
chore: memory leak fixes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mathuo committed Dec 21, 2024
1 parent c216d70 commit f749372
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 105 deletions.
212 changes: 108 additions & 104 deletions packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { DockviewApi } from '../../api/component.api';
import { DockviewDndOverlayEvent } from '../../dockview/options';
import { SizeEvent } from '../../api/gridviewPanelApi';
import { setupMockWindow } from '../__mocks__/mockWindow';
import { exhaustMicrotaskQueue } from '../__test_utils__/utils';

class PanelContentPartTest implements IContentRenderer {
element: HTMLElement = document.createElement('div');
Expand Down Expand Up @@ -141,109 +140,114 @@ describe('dockviewComponent', () => {
expect(dockview.element.className).toBe('test-b test-c');
});

// describe('memory leakage', () => {
// beforeEach(() => {
// window.open = () => fromPartial<Window>({
// addEventListener: jest.fn(),
// close: jest.fn(),
// });
// });

// test('event leakage', () => {
// Emitter.setLeakageMonitorEnabled(true);

// dockview = new DockviewComponent({
// parentElement: container,
// components: {
// default: PanelContentPartTest,
// },
// });

// dockview.layout(500, 1000);

// const panel1 = dockview.addPanel({
// id: 'panel1',
// component: 'default',
// });

// const panel2 = dockview.addPanel({
// id: 'panel2',
// component: 'default',
// });

// dockview.removePanel(panel2);

// const panel3 = dockview.addPanel({
// id: 'panel3',
// component: 'default',
// position: {
// direction: 'right',
// referencePanel: 'panel1',
// },
// });

// const panel4 = dockview.addPanel({
// id: 'panel4',
// component: 'default',
// position: {
// direction: 'above',
// },
// });

// dockview.moveGroupOrPanel(
// panel4.group,
// panel3.group.id,
// panel3.id,
// 'center'
// );

// dockview.addPanel({
// id: 'panel5',
// component: 'default',
// floating: true,
// });

// const panel6 = dockview.addPanel({
// id: 'panel6',
// component: 'default',
// position: {
// referencePanel: 'panel5',
// direction: 'within',
// },
// });

// dockview.addFloatingGroup(panel4.api.group);

// dockview.addPopoutGroup(panel6);

// dockview.moveGroupOrPanel(
// panel1.group,
// panel6.group.id,
// panel6.id,
// 'center'
// );

// dockview.moveGroupOrPanel(
// panel4.group,
// panel6.group.id,
// panel6.id,
// 'center'
// );

// dockview.dispose();

// if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
// for (const entry of Array.from(
// Emitter.MEMORY_LEAK_WATCHER.events
// )) {
// console.log('disposal', entry[1]);
// }
// throw new Error('not all listeners disposed');
// }

// Emitter.setLeakageMonitorEnabled(false);
// });
// });
describe('memory leakage', () => {
beforeEach(() => {
window.open = () => setupMockWindow();
});

test('event leakage', async () => {
Emitter.setLeakageMonitorEnabled(true);

dockview = new DockviewComponent(container, {
createComponent(options) {
switch (options.name) {
case 'default':
return new PanelContentPartTest(
options.id,
options.name
);
default:
throw new Error(`unsupported`);
}
},
className: 'test-a test-b',
});

dockview.layout(500, 1000);

const panel1 = dockview.addPanel({
id: 'panel1',
component: 'default',
});

const panel2 = dockview.addPanel({
id: 'panel2',
component: 'default',
});

dockview.removePanel(panel2);

const panel3 = dockview.addPanel({
id: 'panel3',
component: 'default',
position: {
direction: 'right',
referencePanel: 'panel1',
},
});

const panel4 = dockview.addPanel({
id: 'panel4',
component: 'default',
position: {
direction: 'above',
},
});

panel4.api.group.api.moveTo({
group: panel3.api.group,
position: 'center',
});

dockview.addPanel({
id: 'panel5',
component: 'default',
floating: true,
});

const panel6 = dockview.addPanel({
id: 'panel6',
component: 'default',
position: {
referencePanel: 'panel5',
direction: 'within',
},
});

dockview.addFloatingGroup(panel4.api.group);

await dockview.addPopoutGroup(panel2);

panel1.api.group.api.moveTo({
group: panel6.api.group,
position: 'center',
});

panel4.api.group.api.moveTo({
group: panel6.api.group,
position: 'center',
});

dockview.dispose();

if (Emitter.MEMORY_LEAK_WATCHER.size > 0) {
console.warn(
`${Emitter.MEMORY_LEAK_WATCHER.size} undisposed resources`
);

for (const entry of Array.from(
Emitter.MEMORY_LEAK_WATCHER.events
)) {
console.log('disposal', entry[1]);
}
throw new Error(
`${Emitter.MEMORY_LEAK_WATCHER.size} undisposed resources`
);
}

Emitter.setLeakageMonitorEnabled(false);
});
});

test('duplicate panel', () => {
dockview.layout(500, 1000);
Expand Down
6 changes: 6 additions & 0 deletions packages/dockview-core/src/dockview/dockviewComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ export class DockviewComponent
this._onDidRemoveGroup,
this._onDidActiveGroupChange,
this._onUnhandledDragOverEvent,
this._onDidMaximizedGroupChange,
this.onDidViewVisibilityChangeMicroTaskQueue(() => {
this.updateWatermark();
}),
Expand Down Expand Up @@ -576,6 +577,11 @@ export class DockviewComponent
this.updateWatermark();
}

override dispose(): void {
this.clear(); // explicitly clear the layout before cleaning up
super.dispose();
}

override setVisible(panel: DockviewGroupPanel, visible: boolean): void {
switch (panel.api.location.type) {
case 'grid':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,9 @@ export class DockviewGroupPanelModel
this._onDidAddPanel,
this._onDidRemovePanel,
this._onDidActivePanelChange,
this._onUnhandledDragOverEvent
this._onUnhandledDragOverEvent,
this._onDidPanelTitleChange,
this._onDidPanelParametersChange
);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/dockview-core/src/gridview/baseComponentGridview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ export abstract class BaseGrid<T extends IGridPanelView>
)(() => {
this._bufferOnDidLayoutChange.fire();
}),
this._onDidMaximizedChange,
this._onDidViewVisibilityChangeMicroTaskQueue,
this._bufferOnDidLayoutChange
);
}
Expand Down

0 comments on commit f749372

Please sign in to comment.