test: add tests

This commit is contained in:
mathuo 2024-01-03 19:38:18 +00:00
parent 43548618ba
commit 10256672b4
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
4 changed files with 175 additions and 7 deletions

View File

@ -1,5 +1,14 @@
import * as React from 'react';
/**
* useful utility type to erase readonly signatures for testing purposes
*
* @see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#readonly-mapped-type-modifiers-and-readonly-arrays
*/
export type Writable<T> = T extends object
? { -readonly [K in keyof T]: Writable<T[K]> }
: T;
export function setMockRefElement(node: Partial<HTMLElement>): void {
const mockRef = {
get current() {
@ -25,3 +34,13 @@ export function createOffsetDragOverEvent(params: {
Object.defineProperty(event, 'clientY', { get: () => params.clientY });
return event;
}
/**
* `jest.runAllTicks` doesn't seem to exhaust all events in the micro-task queue so
* as a **hacky** alternative we'll wait for an empty Promise to complete which runs
* on the micro-task queue so will force a run-to-completion emptying the queue
* of any pending micro-task
*/
export function exhaustMicrotaskQueue(): Promise<void> {
return new Promise<void>((resolve) => resolve());
}

View File

@ -1,8 +1,145 @@
import { OverlayRenderContainer } from '../overlayRenderContainer';
import { Droptarget } from '../dnd/droptarget';
import { IDockviewPanel } from '../dockview/dockviewPanel';
import { Emitter } from '../events';
import { IRenderable, OverlayRenderContainer } from '../overlayRenderContainer';
import { fromPartial } from '@total-typescript/shoehorn';
import { Writable, exhaustMicrotaskQueue } from './__test_utils__/utils';
describe('overlayRenderContainer', () => {
test('abc', () => {
const el = document.createElement('div');
const cut = new OverlayRenderContainer(el);
test('add a view that is not currently in the DOM', async () => {
const parentContainer = document.createElement('div');
const cut = new OverlayRenderContainer(parentContainer);
const panelContentEl = document.createElement('div');
const onDidVisibilityChange = new Emitter<any>();
const onDidDimensionsChange = new Emitter<any>();
const panel = fromPartial<IDockviewPanel>({
api: {
id: 'test_panel_id',
onDidVisibilityChange: onDidVisibilityChange.event,
onDidDimensionsChange: onDidDimensionsChange.event,
isVisible: true,
},
view: {
content: {
element: panelContentEl,
},
},
group: {
api: {
location: 'grid',
},
},
});
const dropTarget = fromPartial<Droptarget>({});
const refContainerEl = document.createElement('div');
const referenceContainer: IRenderable = {
element: refContainerEl,
dropTarget,
};
(parentContainer as jest.Mocked<HTMLDivElement>).getBoundingClientRect =
jest
.fn<DOMRect, []>()
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 100,
top: 200,
width: 1000,
height: 500,
})
)
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 101,
top: 201,
width: 1000,
height: 500,
})
)
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 100,
top: 200,
width: 1000,
height: 500,
})
);
(refContainerEl as jest.Mocked<HTMLDivElement>).getBoundingClientRect =
jest
.fn<DOMRect, []>()
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 150,
top: 300,
width: 100,
height: 200,
})
)
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 150,
top: 300,
width: 101,
height: 201,
})
)
.mockReturnValueOnce(
fromPartial<DOMRect>({
left: 150,
top: 300,
width: 100,
height: 200,
})
);
const container = cut.setReferenceContentContainer(
panel,
referenceContainer
);
await exhaustMicrotaskQueue();
expect(panelContentEl.parentElement).toBe(container);
expect(container.parentElement).toBe(parentContainer);
expect(container.style.display).toBe('');
expect(container.style.left).toBe('50px');
expect(container.style.top).toBe('100px');
expect(container.style.width).toBe('100px');
expect(container.style.height).toBe('200px');
expect(refContainerEl.getBoundingClientRect).toHaveBeenCalledTimes(1);
onDidDimensionsChange.fire({});
expect(container.style.display).toBe('');
expect(container.style.left).toBe('49px');
expect(container.style.top).toBe('99px');
expect(container.style.width).toBe('101px');
expect(container.style.height).toBe('201px');
expect(refContainerEl.getBoundingClientRect).toHaveBeenCalledTimes(2);
(panel as Writable<IDockviewPanel>).api.isVisible = false;
onDidVisibilityChange.fire({});
expect(container.style.display).toBe('none');
expect(refContainerEl.getBoundingClientRect).toHaveBeenCalledTimes(2);
(panel as Writable<IDockviewPanel>).api.isVisible = true;
onDidVisibilityChange.fire({});
expect(container.style.display).toBe('');
expect(container.style.left).toBe('50px');
expect(container.style.top).toBe('100px');
expect(container.style.width).toBe('100px');
expect(container.style.height).toBe('200px');
expect(refContainerEl.getBoundingClientRect).toHaveBeenCalledTimes(3);
});
});

View File

@ -89,6 +89,14 @@ export class OverlayRenderContainer extends CompositeDisposable {
);
};
const visibilityChanged = () => {
if (panel.api.isVisible) {
resize();
}
focusContainer.style.display = panel.api.isVisible ? '' : 'none';
};
const disposable = new CompositeDisposable(
/**
* since container is positioned absoutely we must explicitly forward
@ -117,9 +125,13 @@ export class OverlayRenderContainer extends CompositeDisposable {
* the content is still maintained within the DOM hence DOM specific attributes
* such as scroll position are maintained when next made visible.
*/
focusContainer.style.display = event.isVisible ? '' : 'none';
visibilityChanged();
}),
panel.api.onDidDimensionsChange(() => {
if (!panel.api.isVisible) {
return;
}
resize();
}),
{
@ -140,7 +152,7 @@ export class OverlayRenderContainer extends CompositeDisposable {
* calling the first resize as other size-altering events may still occur before
* the end of the stack-frame.
*/
resize();
visibilityChanged();
});
this.map[panel.api.id].disposable = disposable;