import { describe, expect, test } from "bun:test"; import { gradientEditorPlugin } from "../plugins/gradientEditorPlugin"; import { createPointerEvent, createTestCanvas } from "./canvasTestUtils"; const gradient = { rect: { x: 0, y: 0, width: 10, height: 10 }, stops: [ { id: "start", index: 0, type: "start", position: 0, point: { x: 0, y: 0 } }, { id: "stop", index: 1, type: "stop", position: 0.5, point: { x: 5, y: 5 } }, { id: "end", index: 2, type: "end", position: 1, point: { x: 10, y: 10 } }, ], }; describe("gradientEditor plugin", () => { test("hover, drag, and release gradient stop", () => { const moved: any[] = []; const harness = createTestCanvas((canvas) => canvas.addPlugins(gradientEditorPlugin<{ snapshot: string }>({ movementThreshold: 0 })), { data: { zoom: 1, handleSize: 12 }, contextProperties: { canEditGradient: () => true, getGradient: () => gradient, getStateSnapshot: () => ({ snapshot: "state" }), moveStop: (params) => moved.push(params), }, }); harness.handlers.onPointerMove?.(createPointerEvent({ x: 0, y: 0 })); expect(harness.getData().hoveredStopId).toBe("start"); harness.handlers.onPointerDown?.(createPointerEvent({ x: 0, y: 0 })); expect(harness.getMode()).toMatchObject({ type: "draggingGradientStop", stopId: "start" }); expect(harness.getData().activeStopId).toBe("start"); harness.handlers.onPointerMove?.(createPointerEvent({ x: 5, y: 5 })); expect(moved[0]).toMatchObject({ id: "start", position: 0 }); harness.handlers.onPointerMove?.(createPointerEvent({ x: 10, y: 10 })); expect(moved.pop()).toMatchObject({ id: "start", position: 0 }); harness.handlers.onPointerUp?.(createPointerEvent({ x: 10, y: 10 })); expect(harness.getMode().type).toBe("none"); expect(harness.getData().activeStopId).toBeUndefined(); }); test("dragging stop projects onto gradient line and clamps", () => { const moved: any[] = []; const harness = createTestCanvas((canvas) => canvas.addPlugins(gradientEditorPlugin<{ snapshot: string }>({ movementThreshold: 0 })), { data: { zoom: 1, handleSize: 12 }, contextProperties: { canEditGradient: () => true, getGradient: () => gradient, getStateSnapshot: () => ({ snapshot: "state" }), moveStop: (params) => moved.push(params), }, }); harness.handlers.onPointerDown?.(createPointerEvent({ x: 8, y: 8 })); harness.handlers.onPointerMove?.(createPointerEvent({ x: 15, y: 15 })); const stopMove = moved.find((m) => m.id === "stop"); expect(stopMove?.position).toBe(1); expect(stopMove?.point).toEqual({ x: 10, y: 10 }); }); test("pointer leave clears hover and cancel resets state", () => { const harness = createTestCanvas((canvas) => canvas.addPlugins(gradientEditorPlugin<{ snapshot: string }>()), { data: { zoom: 1, handleSize: 12, hoveredStopId: "stop", activeStopId: "stop" }, contextProperties: { canEditGradient: () => true, getGradient: () => gradient, getStateSnapshot: () => ({ snapshot: "state" }), moveStop: () => {}, }, }); harness.handlers.onPointerLeave?.(createPointerEvent({})); expect(harness.getData().hoveredStopId).toBeUndefined(); harness.handlers.onPointerCancel?.(createPointerEvent({})); expect(harness.getData().activeStopId).toBeUndefined(); }); test("does nothing when editing disabled or no gradient", () => { const moved: any[] = []; const harness = createTestCanvas((canvas) => canvas.addPlugins(gradientEditorPlugin<{ snapshot: string }>()), { data: { zoom: 1, handleSize: 12 }, contextProperties: { canEditGradient: () => false, getGradient: () => undefined, getStateSnapshot: () => ({ snapshot: "state" }), moveStop: (params) => moved.push(params), }, }); harness.handlers.onPointerDown?.(createPointerEvent({ x: 0, y: 0 })); harness.handlers.onPointerMove?.(createPointerEvent({ x: 5, y: 5 })); harness.handlers.onPointerUp?.(createPointerEvent({ x: 5, y: 5 })); expect(harness.getMode().type).toBe("none"); expect(moved.length).toBe(0); }); });