import { describe, expect, test } from "bun:test"; import { createInitialAppState } from "@editor/initial-state"; import { viewportFitArtboardCommand, viewportPanCommand, viewportResetCommand, viewportSetSizeCommand, viewportSetZoomCommand, viewportZoomAroundPointCommand, } from "./viewport"; const context = () => ({ state: createInitialAppState("Test") }); describe("viewport commands", () => { test("pans viewport center", () => { const next = viewportPanCommand.execute(context(), { delta: { x: 10, y: -5 } }); expect(next.editor.viewport.center).toEqual({ x: 10, y: -5 }); }); test("sets zoom with minimum clamp", () => { const next = viewportSetZoomCommand.execute(context(), { zoom: -1 }); expect(next.editor.viewport.zoom).toBe(0.01); }); test("sets non-negative viewport size", () => { const next = viewportSetSizeCommand.execute(context(), { w: 800, h: -1 }); expect(next.editor.viewport.size).toEqual({ w: 800, h: 0 }); }); test("zooms around a viewport point", () => { const state = viewportSetSizeCommand.execute(context(), { w: 100, h: 100 }); const next = viewportZoomAroundPointCommand.execute({ state }, { zoom: 2, point: { x: 100, y: 50 } }); expect(next.editor.viewport.zoom).toBe(2); expect(next.editor.viewport.center).toEqual({ x: 25, y: 0 }); }); test("fits an artboard in the viewport", () => { const state = { ...viewportSetSizeCommand.execute(context(), { w: 1000, h: 800 }), document: { ...context().state.document, artboards: [{ id: "artboard-1", name: "Artboard", bounds: { x: -400, y: -300, w: 800, h: 600 }, backgroundColor: "transparent", visible: true, locked: false, layers: [] }], }, }; const next = viewportFitArtboardCommand.execute({ state }, { artboardId: "artboard-1", padding: 100 }); expect(next.editor.viewport.center).toEqual({ x: 0, y: 0 }); expect(next.editor.viewport.zoom).toBe(1); }); test("fit artboard centers even before viewport size is known", () => { const state = { ...context().state, document: { ...context().state.document, artboards: [{ id: "artboard-1", name: "Artboard", bounds: { x: 10, y: 20, w: 100, h: 200 }, backgroundColor: "transparent", visible: true, locked: false, layers: [] }], }, }; const next = viewportFitArtboardCommand.execute({ state }, { artboardId: "artboard-1" }); expect(next.editor.viewport.center).toEqual({ x: 60, y: 120 }); expect(next.editor.viewport.zoom).toBe(1); }); test("resets viewport but preserves size", () => { const sized = viewportSetSizeCommand.execute(context(), { w: 640, h: 480 }); const panned = viewportPanCommand.execute({ state: sized }, { delta: { x: 4, y: 8 } }); const next = viewportResetCommand.execute({ state: panned }, undefined); expect(next.editor.viewport).toEqual({ center: { x: 0, y: 0 }, zoom: 1, rotation: 0, size: { w: 640, h: 480 } }); }); });