Add support for pre-defined zoom/pan settings.
This commit is contained in:
@@ -0,0 +1,658 @@
|
||||
import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom';
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { mock, mockClear } from 'vitest-mock-extended';
|
||||
import { ZoomController } from '../../../src/components-lib/zoom/zoom-controller';
|
||||
import { ResizeObserverMock, requestAnimationFrameMock } from '../../test-utils';
|
||||
|
||||
vi.mock('@dermotduffy/panzoom');
|
||||
vi.mock('lodash-es/debounce', () => ({
|
||||
default: vi.fn((fn) => fn),
|
||||
}));
|
||||
|
||||
// https://github.com/jsdom/jsdom/issues/2527
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).PointerEvent = MouseEvent;
|
||||
|
||||
const triggerResizeObserver = (): void => {
|
||||
const resizeObserverTrigger = vi.mocked(global.ResizeObserver).mock.calls[0][0];
|
||||
resizeObserverTrigger([], mock<ResizeObserver>());
|
||||
};
|
||||
|
||||
const setElementToDefaultCardSize = (element: HTMLElement, multiple?: number): void => {
|
||||
element.getBoundingClientRect = vi.fn().mockReturnValue({
|
||||
width: 492 * (multiple ?? 1),
|
||||
height: 276.75 * (multiple ?? 1),
|
||||
});
|
||||
};
|
||||
|
||||
// @vitest-environment jsdom
|
||||
describe('ZoomController', () => {
|
||||
const mediaSpy = vi.spyOn(window, 'matchMedia');
|
||||
|
||||
const createMockPanZoom = (): PanzoomObject => {
|
||||
const panzoom = mock<PanzoomObject>();
|
||||
panzoom.getScale.mockReturnValue(1.0);
|
||||
panzoom.getPan.mockReturnValue({ x: 0, y: 0 });
|
||||
return panzoom;
|
||||
};
|
||||
|
||||
const createAndRegisterZoom = (element: HTMLElement): ZoomController => {
|
||||
const zoom = new ZoomController(element);
|
||||
zoom.activate();
|
||||
return zoom;
|
||||
};
|
||||
|
||||
const createTouch = (target: HTMLElement): Touch => {
|
||||
return {
|
||||
clientX: 0,
|
||||
clientY: 0,
|
||||
force: 0,
|
||||
identifier: 0,
|
||||
pageX: 0,
|
||||
pageY: 0,
|
||||
radiusX: 0,
|
||||
radiusY: 0,
|
||||
rotationAngle: 0,
|
||||
screenX: 0,
|
||||
screenY: 0,
|
||||
target: target,
|
||||
};
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal('ResizeObserver', ResizeObserverMock);
|
||||
window.requestAnimationFrame = requestAnimationFrameMock;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(Panzoom).mockReset();
|
||||
vi.mocked(global.ResizeObserver).mockClear();
|
||||
mediaSpy.mockReturnValue(<MediaQueryList>{ matches: true });
|
||||
});
|
||||
|
||||
it('should be creatable', () => {
|
||||
const element = document.createElement('div');
|
||||
const zoom = new ZoomController(element);
|
||||
expect(zoom).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('should pan and zoom', () => {
|
||||
it('should respond with pointer', () => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
// Won't zoom without control key.
|
||||
const ev_1 = new WheelEvent('wheel', { bubbles: false, deltaY: -120 });
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(panzoom.zoomWithWheel).not.toBeCalled();
|
||||
|
||||
const ev_2 = new WheelEvent('wheel', {
|
||||
bubbles: false,
|
||||
deltaY: -120,
|
||||
ctrlKey: true,
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(panzoom.zoomWithWheel).toBeCalledWith(ev_2);
|
||||
|
||||
panzoom.getScale = vi.fn().mockReturnValue(1.2);
|
||||
|
||||
const ev_3 = new PointerEvent('pointerdown');
|
||||
element.dispatchEvent(ev_3);
|
||||
expect(panzoom.handleDown).toBeCalledWith(ev_3);
|
||||
|
||||
const ev_4 = new PointerEvent('pointermove');
|
||||
element.dispatchEvent(ev_4);
|
||||
expect(panzoom.handleMove).toBeCalledWith(ev_4);
|
||||
|
||||
const ev_5 = new PointerEvent('pointerup');
|
||||
element.dispatchEvent(ev_5);
|
||||
expect(panzoom.handleUp).toBeCalledWith(ev_5);
|
||||
});
|
||||
|
||||
it('should not respond to pointer when not zoomed', () => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new PointerEvent('pointerdown');
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(panzoom.handleDown).not.toBeCalledWith(ev_1);
|
||||
|
||||
const ev_2 = new PointerEvent('pointermove');
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(panzoom.handleDown).not.toBeCalledWith(ev_2);
|
||||
|
||||
const ev_3 = new PointerEvent('pointerup');
|
||||
element.dispatchEvent(ev_3);
|
||||
expect(panzoom.handleDown).not.toBeCalledWith(ev_3);
|
||||
});
|
||||
|
||||
it('should respond with touch', () => {
|
||||
mediaSpy.mockReturnValue(<MediaQueryList>{ matches: false });
|
||||
|
||||
const element = document.createElement('div');
|
||||
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new TouchEvent('touchstart', {
|
||||
bubbles: false,
|
||||
touches: [createTouch(element), createTouch(element)],
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(panzoom.handleDown).toBeCalledWith(ev_1);
|
||||
|
||||
panzoom.getScale = vi.fn().mockReturnValue(1.2);
|
||||
|
||||
const ev_3 = new TouchEvent('touchstart');
|
||||
element.dispatchEvent(ev_3);
|
||||
expect(panzoom.handleDown).toBeCalledWith(ev_3);
|
||||
|
||||
const ev_4 = new TouchEvent('touchmove');
|
||||
element.dispatchEvent(ev_4);
|
||||
expect(panzoom.handleMove).toBeCalledWith(ev_4);
|
||||
|
||||
const ev_5 = new TouchEvent('touchend');
|
||||
element.dispatchEvent(ev_5);
|
||||
expect(panzoom.handleUp).toBeCalledWith(ev_5);
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore click after pointerdown', () => {
|
||||
const outer = document.createElement('div');
|
||||
const inner = document.createElement('div');
|
||||
outer.appendChild(inner);
|
||||
const clickHandler = vi.fn();
|
||||
outer.addEventListener('click', clickHandler);
|
||||
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
createAndRegisterZoom(inner);
|
||||
|
||||
// Simulate being zoomed in.
|
||||
panzoom.getScale = vi.fn().mockReturnValue(1.2);
|
||||
|
||||
// A click on its own will be fine.
|
||||
const click_1 = new MouseEvent('click', { bubbles: true });
|
||||
inner.dispatchEvent(click_1);
|
||||
expect(clickHandler).toBeCalledTimes(1);
|
||||
|
||||
// A click after a pointerdown will be ignored.
|
||||
const pointerdown_1 = new PointerEvent('pointerdown');
|
||||
inner.dispatchEvent(pointerdown_1);
|
||||
|
||||
const click_2 = new MouseEvent('click', { bubbles: true });
|
||||
inner.dispatchEvent(click_2);
|
||||
|
||||
// Click will have been ignored.
|
||||
//expect(clickHandler).toBeCalledTimes(1);
|
||||
|
||||
// Simulate being zoomed out.
|
||||
panzoom.getScale = vi.fn().mockReturnValue(1.0);
|
||||
const pointerdown_2 = new PointerEvent('pointerdown');
|
||||
inner.dispatchEvent(pointerdown_2);
|
||||
|
||||
const click_3 = new MouseEvent('click', { bubbles: true });
|
||||
inner.dispatchEvent(click_3);
|
||||
|
||||
// Click will have been processed.
|
||||
expect(clickHandler).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it('deactivate should remove event handlers', () => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
createAndRegisterZoom(element).deactivate();
|
||||
|
||||
const ev_1 = new WheelEvent('wheel', {
|
||||
bubbles: false,
|
||||
deltaY: -120,
|
||||
ctrlKey: true,
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(panzoom.zoomWithWheel).not.toBeCalled();
|
||||
});
|
||||
|
||||
describe('should fire events', () => {
|
||||
it('on zoom/unzoom', () => {
|
||||
const element = document.createElement('div');
|
||||
const zoomedFunc = vi.fn();
|
||||
const unzoomedFunc = vi.fn();
|
||||
element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc);
|
||||
element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc);
|
||||
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1.2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(zoomedFunc).toBeCalled();
|
||||
expect(unzoomedFunc).not.toBeCalled();
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(unzoomedFunc).toBeCalled();
|
||||
});
|
||||
|
||||
it('when state has not changed or spurious events received', () => {
|
||||
const element = document.createElement('div');
|
||||
const zoomedFunc = vi.fn();
|
||||
const unzoomedFunc = vi.fn();
|
||||
element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc);
|
||||
element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc);
|
||||
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
|
||||
// Unzoomed event with scale === 1, this._zoomed will already be false.
|
||||
expect(unzoomedFunc).not.toBeCalled();
|
||||
expect(zoomedFunc).not.toBeCalled();
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1.2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(zoomedFunc).toBeCalledTimes(1);
|
||||
expect(unzoomedFunc).not.toBeCalled();
|
||||
|
||||
// Another call when already zoomed will be ignored.
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(zoomedFunc).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('on default/non-default', () => {
|
||||
it('without explicit default', () => {
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const defaultFunc = vi.fn();
|
||||
element.addEventListener('frigate-card:zoom:default', defaultFunc);
|
||||
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1.2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(defaultFunc).toBeCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: false } }),
|
||||
);
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(defaultFunc).toBeCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: true } }),
|
||||
);
|
||||
});
|
||||
|
||||
it('with complete explicit default', () => {
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const defaultFunc = vi.fn();
|
||||
element.addEventListener('frigate-card:zoom:default', defaultFunc);
|
||||
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
const controller = createAndRegisterZoom(element);
|
||||
controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(defaultFunc).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: false } }),
|
||||
);
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 115.62,
|
||||
y: 63.6525,
|
||||
scale: 2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(defaultFunc).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: true } }),
|
||||
);
|
||||
});
|
||||
|
||||
it('with partial explicit default', () => {
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const defaultFunc = vi.fn();
|
||||
element.addEventListener('frigate-card:zoom:default', defaultFunc);
|
||||
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
const controller = createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 51,
|
||||
y: 51,
|
||||
scale: 2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(defaultFunc).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: false } }),
|
||||
);
|
||||
|
||||
controller.setDefaultConfig({});
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(defaultFunc).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ detail: { isDefault: true } }),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('should automatically set correct zoom', () => {
|
||||
it('with start', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = new ZoomController(element);
|
||||
controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
|
||||
// Controller was not activated, config setting will not update pan/zoom.
|
||||
expect(panzoom.zoom).not.toBeCalled();
|
||||
expect(panzoom.pan).not.toBeCalled();
|
||||
|
||||
controller.activate();
|
||||
expect(Panzoom).toBeCalledWith(
|
||||
expect.anything(),
|
||||
expect.objectContaining({
|
||||
contain: "outside",
|
||||
cursor: undefined,
|
||||
maxScale: 10,
|
||||
minScale: 1,
|
||||
noBind: true,
|
||||
touchAction: "",
|
||||
startScale: 2,
|
||||
startX: 115.62,
|
||||
startY: 63.6525,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('with set of default config', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = createAndRegisterZoom(element);
|
||||
controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
|
||||
triggerResizeObserver();
|
||||
|
||||
expect(panzoom.zoom).toBeCalledWith(2, { animate: false });
|
||||
expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { animate: false });
|
||||
});
|
||||
|
||||
it('with set of config when a default is already set', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = createAndRegisterZoom(element);
|
||||
|
||||
// This call will do nothing since this is what zoom/pan already are.
|
||||
controller.setDefaultConfig({ zoom: 1, pan: { x: 0, y: 0 } });
|
||||
|
||||
expect(panzoom.zoom).not.toBeCalled();
|
||||
expect(panzoom.pan).not.toBeCalled();
|
||||
|
||||
controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
|
||||
expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false });
|
||||
expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, {
|
||||
animate: false,
|
||||
});
|
||||
|
||||
controller.setConfig({ zoom: 3, pan: { x: 5, y: 6 } });
|
||||
|
||||
expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 3, { animate: false });
|
||||
expect(panzoom.pan).toHaveBeenNthCalledWith(2, 147.6, 81.18, {
|
||||
animate: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('with repeated calls with same values', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = createAndRegisterZoom(element);
|
||||
|
||||
controller.setConfig({ zoom: 1 });
|
||||
expect(panzoom.zoom).not.toHaveBeenCalled();
|
||||
|
||||
controller.setConfig({ pan: { x: 50, y: 50 } });
|
||||
expect(panzoom.zoom).not.toHaveBeenCalled();
|
||||
|
||||
controller.setConfig({ zoom: 1, pan: { x: 50, y: 50 } });
|
||||
expect(panzoom.zoom).not.toHaveBeenCalled();
|
||||
|
||||
controller.setConfig({});
|
||||
expect(panzoom.zoom).not.toHaveBeenCalled();
|
||||
|
||||
controller.setConfig({ zoom: 2 });
|
||||
|
||||
expect(panzoom.zoom).toBeCalledTimes(1);
|
||||
expect(panzoom.pan).toBeCalledTimes(1);
|
||||
expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false });
|
||||
expect(panzoom.pan).toHaveBeenNthCalledWith(1, 0, 0, {
|
||||
animate: false,
|
||||
});
|
||||
|
||||
vi.mocked(panzoom.getScale).mockReturnValue(2);
|
||||
vi.mocked(panzoom.getPan).mockReturnValue({ x: 0, y: 0 });
|
||||
controller.setConfig({ zoom: 2 });
|
||||
|
||||
expect(panzoom.zoom).toBeCalledTimes(1);
|
||||
expect(panzoom.pan).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('when config is set to empty', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = createAndRegisterZoom(element);
|
||||
controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
mockClear(panzoom);
|
||||
|
||||
controller.setConfig({});
|
||||
|
||||
// Should fall back to default.
|
||||
expect(panzoom.zoom).toBeCalledWith(2, { animate: false });
|
||||
expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, {
|
||||
animate: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('when resized', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
const controller = createAndRegisterZoom(element);
|
||||
controller.setConfig({ zoom: 2, pan: { x: 3, y: 4 } });
|
||||
|
||||
expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false });
|
||||
expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, {
|
||||
animate: false,
|
||||
});
|
||||
|
||||
vi.mocked(panzoom.getScale).mockReturnValue(2);
|
||||
vi.mocked(panzoom.getPan).mockReturnValue({ x: 3, y: 4 });
|
||||
|
||||
setElementToDefaultCardSize(element);
|
||||
triggerResizeObserver();
|
||||
|
||||
expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 2, { animate: false });
|
||||
expect(panzoom.pan).toHaveBeenNthCalledWith(2, 57.81, 31.82625, {
|
||||
animate: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('when not yet activated', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
setElementToDefaultCardSize(element);
|
||||
|
||||
new ZoomController(element);
|
||||
|
||||
triggerResizeObserver();
|
||||
|
||||
expect(panzoom.zoom).not.toBeCalled();
|
||||
expect(panzoom.pan).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('when element has no size', () => {
|
||||
const panzoom = createMockPanZoom();
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(panzoom);
|
||||
|
||||
const element = document.createElement('div');
|
||||
element.getBoundingClientRect = vi.fn().mockReturnValue({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
triggerResizeObserver();
|
||||
|
||||
expect(panzoom.zoom).not.toBeCalled();
|
||||
expect(panzoom.pan).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should set touch action on zoom/unzoom', () => {
|
||||
const element = document.createElement('div');
|
||||
vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom());
|
||||
|
||||
createAndRegisterZoom(element);
|
||||
|
||||
const ev_1 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1.2,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_1);
|
||||
expect(element.style.touchAction).toBe('none');
|
||||
|
||||
const ev_2 = new CustomEvent<PanzoomEventDetail>('panzoomchange', {
|
||||
detail: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
isSVG: false,
|
||||
originalEvent: new PointerEvent('pointermove'),
|
||||
},
|
||||
});
|
||||
element.dispatchEvent(ev_2);
|
||||
expect(element.style.touchAction).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
generateViewContextForZoomChange,
|
||||
handleZoomDefaultEvent,
|
||||
} from '../../../src/components-lib/zoom/zoom-view-context';
|
||||
|
||||
describe('generateViewContextForZoomChangeRequest', () => {
|
||||
it('with config', () => {
|
||||
expect(
|
||||
generateViewContextForZoomChange('target', {
|
||||
zoom: {
|
||||
pan: { x: 1, y: 2 },
|
||||
zoom: 3,
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
zoom: {
|
||||
target: {
|
||||
zoom: {
|
||||
pan: { x: 1, y: 2 },
|
||||
zoom: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('without config', () => {
|
||||
expect(generateViewContextForZoomChange('target')).toEqual({
|
||||
zoom: {
|
||||
target: {
|
||||
zoom: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateViewContextForZoomDefault', () => {
|
||||
it('default', () => {
|
||||
expect(generateViewContextForZoomChange('target', { isDefault: true })).toEqual({
|
||||
zoom: {
|
||||
target: {
|
||||
isDefault: true,
|
||||
zoom: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('not default', () => {
|
||||
expect(generateViewContextForZoomChange('target', { isDefault: false })).toEqual({
|
||||
zoom: {
|
||||
target: {
|
||||
isDefault: false,
|
||||
zoom: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// @vitest-environment jsdom
|
||||
it('handleZoomDefaultEvent', () => {
|
||||
const element = document.createElement('div');
|
||||
const callback = vi.fn();
|
||||
element.addEventListener('frigate-card:view:change-context', callback);
|
||||
handleZoomDefaultEvent(
|
||||
element,
|
||||
new CustomEvent('frigate-card:zoom:default', { detail: { isDefault: true } }),
|
||||
'target',
|
||||
);
|
||||
expect(callback).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
detail: {
|
||||
zoom: {
|
||||
target: {
|
||||
zoom: null,
|
||||
isDefault: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user