import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ImageViewer } from './image-viewer';
import { IMAGE_VIEWER_ZOOM_EVENT } from './image-viewer.types';
const MARKUP = `
`;
function setup(opts = {}): { root: HTMLElement; ctrl: ImageViewer } {
document.body.innerHTML = MARKUP;
const root = document.body.firstElementChild as HTMLElement;
return { root, ctrl: new ImageViewer(root, opts) };
}
describe('ImageViewer', () => {
beforeEach(() => { document.body.innerHTML = ''; });
it('throws without content element', () => {
document.body.innerHTML = '';
expect(() => new ImageViewer(document.body.firstElementChild as HTMLElement)).toThrow(/Missing/);
});
it('starts at zoom 0 with 100% indicator', () => {
const { root, ctrl } = setup();
expect(ctrl.currentZoom).toBe(0);
expect(root.querySelector('[data-c42-viewer-indicator]')!.textContent).toBe('100%');
});
it('zooms in via button and emits event', () => {
const { root, ctrl } = setup();
const spy = vi.fn();
root.addEventListener(IMAGE_VIEWER_ZOOM_EVENT, spy);
root.querySelector('[data-c42-viewer-zoom-in]')!.click();
expect(ctrl.currentZoom).toBe(1);
expect(spy).toHaveBeenCalledOnce();
expect((spy.mock.calls[0][0] as CustomEvent).detail.zoom).toBe(1);
});
it('zooms out via button', () => {
const { ctrl } = setup();
ctrl.zoomIn();
ctrl.zoomIn();
ctrl.zoomOut();
expect(ctrl.currentZoom).toBe(1);
});
it('respects maxZoom', () => {
const { ctrl } = setup({ maxZoom: 2 });
ctrl.zoomIn();
ctrl.zoomIn();
ctrl.zoomIn();
expect(ctrl.currentZoom).toBe(2);
});
it('does not go below minZoom', () => {
const { ctrl } = setup();
ctrl.zoomOut();
expect(ctrl.currentZoom).toBe(0);
});
it('resets view', () => {
const { root, ctrl } = setup();
ctrl.zoomIn();
ctrl.zoomIn();
ctrl.resetView();
expect(ctrl.currentZoom).toBe(0);
expect(root.querySelector('[data-c42-viewer-indicator]')!.textContent).toBe('100%');
});
it('toggles expanded state', () => {
const { root, ctrl } = setup();
expect(ctrl.isExpanded).toBe(false);
expect(root.dataset.state).toBe('normal');
root.querySelector('[data-c42-viewer-expand]')!.click();
expect(ctrl.isExpanded).toBe(true);
expect(root.dataset.state).toBe('expanded');
});
it('sets cursor to grab when zoomed', () => {
const { root, ctrl } = setup();
const content = root.querySelector('[data-c42-viewer-content]')!;
expect(content.style.cursor).toBe('default');
ctrl.zoomIn();
expect(content.style.cursor).toBe('grab');
});
it('destroy removes listeners', () => {
const { root, ctrl } = setup();
ctrl.destroy();
root.querySelector('[data-c42-viewer-zoom-in]')!.click();
expect(ctrl.currentZoom).toBe(0);
});
});