import { act, fireEvent, screen } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { DEFAULT_TOOLCRAFT_ORIENTATION_POSE, getToolcraftOrientationPoseFromPointerDelta, readToolcraftOrientationPose, } from "./orientation-gizmo-math"; import { expectOrientationPoseClose, mockOrientationGizmoBounds, renderOrientationGizmoRuntime, } from "./orientation-gizmo-test-harness"; describe("Toolcraft orientation gizmo integration", () => { it("renders one fixed canvas handle without duplicate panel UI", async () => { renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); expect(gizmo.getAttribute("data-toolcraft-canvas-handle")).toBe( "orientation-gizmo", ); expect(gizmo.style.left).toBe("16px"); expect(gizmo.style.bottom).toBe("16px"); expect(screen.getByText("Scale")).toBeTruthy(); expect(screen.queryByText("Orientation")).toBeNull(); }); it("updates live before pointer release through one undoable value gesture", async () => { const store = renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); mockOrientationGizmoBounds(gizmo); fireEvent.pointerDown(gizmo, { button: 0, clientX: 59.5, clientY: 35, pointerId: 1, }); fireEvent.pointerMove(gizmo, { clientX: 47, clientY: 43, pointerId: 1, }); expectOrientationPoseClose( readToolcraftOrientationPose(store.getState().values["view.orbit"]), getToolcraftOrientationPoseFromPointerDelta( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, -12.5, 8, ), ); fireEvent.pointerUp(gizmo, { pointerId: 1 }); act(() => { store.dispatch({ type: "history.undo" }); }); expect(store.getState().values["view.orbit"]).toEqual( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, ); }); it("drags from empty gizmo background and keeps the full threshold delta", async () => { const store = renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); mockOrientationGizmoBounds(gizmo); fireEvent.pointerDown(gizmo, { button: 0, clientX: 35, clientY: 20, pointerId: 11, }); fireEvent.pointerMove(gizmo, { clientX: 37, clientY: 22, pointerId: 11, }); expect(store.getState().values["view.orbit"]).toEqual( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, ); fireEvent.pointerMove(gizmo, { clientX: 39, clientY: 24, pointerId: 11, }); fireEvent.pointerUp(gizmo, { pointerId: 11 }); expectOrientationPoseClose( readToolcraftOrientationPose(store.getState().values["view.orbit"]), getToolcraftOrientationPoseFromPointerDelta( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, 4, 4, ), ); expect(store.getState().history.undo).toHaveLength(1); }); it("keeps an empty-background click inert", async () => { const store = renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); mockOrientationGizmoBounds(gizmo); fireEvent.pointerDown(gizmo, { button: 0, clientX: 35, clientY: 20, pointerId: 12, }); fireEvent.pointerUp(gizmo, { pointerId: 12 }); expect(store.getState().values["view.orbit"]).toEqual( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, ); expect(store.getState().history.undo).toHaveLength(0); }); it("lets presses outside the circular gizmo bubble to canvas pan", async () => { const store = renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); mockOrientationGizmoBounds(gizmo); fireEvent.pointerDown(gizmo, { button: 0, clientX: 1, clientY: 1, pointerId: 13, }); fireEvent.pointerMove(gizmo, { clientX: 11, clientY: 11, pointerId: 13, }); fireEvent.pointerUp(gizmo, { pointerId: 13 }); expect(store.getState().canvas.offset).toEqual({ x: 10, y: 10 }); expect(store.getState().values["view.orbit"]).toEqual( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, ); }); it("ends gizmo drag ownership when pointer capture is lost", async () => { const store = renderOrientationGizmoRuntime(); const gizmo = await screen.findByTestId("toolcraft-orientation-gizmo"); mockOrientationGizmoBounds(gizmo); fireEvent.pointerDown(gizmo, { button: 0, clientX: 59.5, clientY: 35, pointerId: 9, }); fireEvent.lostPointerCapture(gizmo, { pointerId: 9 }); fireEvent.pointerMove(gizmo, { clientX: 45, clientY: 45, pointerId: 9, }); expect(store.getState().values["view.orbit"]).toEqual( DEFAULT_TOOLCRAFT_ORIENTATION_POSE, ); }); });