diff --git a/apps/web/src/hooks/timelineLivePreview.test.ts b/apps/web/src/hooks/timelineLivePreview.test.ts index 35b32b1..d4a602a 100644 --- a/apps/web/src/hooks/timelineLivePreview.test.ts +++ b/apps/web/src/hooks/timelineLivePreview.test.ts @@ -39,6 +39,17 @@ function createSession(element: HTMLElement): LivePreviewSession { }; } +function renderScheduledPreview(session: LivePreviewSession) { + let frameCallback: FrameRequestCallback | null = null; + vi.stubGlobal("requestAnimationFrame", vi.fn((callback: FrameRequestCallback) => { + frameCallback = callback; + return 1; + })); + + scheduleLivePreview(session); + frameCallback?.(0); +} + describe("timelineLivePreview", () => { beforeEach(() => { vi.unstubAllGlobals(); @@ -132,6 +143,57 @@ describe("timelineLivePreview", () => { expect(datesMatch(null, null)).toBe(false); }); + it("renders move previews with snapped left offsets and residual transforms", () => { + const element = createElement(); + const session = createSession(element); + + session.pointerDeltaX = 50; + session.daysDelta = 1; + + renderScheduledPreview(session); + + expect(session.frame).toBeNull(); + expect(element.style.left).toBe("44px"); + expect(element.style.width).toBe("48px"); + expect(element.style.transform).toBe("scale(1) translateX(18px)"); + }); + + it("clamps resize-start previews to the minimum cell width", () => { + const element = createElement(); + const session = createSession(element); + + session.mode = "resize-start"; + session.cellWidth = 20; + session.targets[0]!.baseLeft = 10; + session.targets[0]!.baseWidth = 60; + session.pointerDeltaX = 80; + session.daysDelta = 1; + + renderScheduledPreview(session); + + expect(element.style.left).toBe("50px"); + expect(element.style.width).toBe("20px"); + expect(element.style.transform).toBe("scale(1)"); + }); + + it("clamps resize-end previews to the minimum cell width", () => { + const element = createElement(); + const session = createSession(element); + + session.mode = "resize-end"; + session.cellWidth = 20; + session.targets[0]!.baseLeft = 10; + session.targets[0]!.baseWidth = 30; + session.pointerDeltaX = -40; + session.daysDelta = 0; + + renderScheduledPreview(session); + + expect(element.style.left).toBe("10px"); + expect(element.style.width).toBe("20px"); + expect(element.style.transform).toBe("scale(1)"); + }); + it("schedules at most one animation frame for a preview session", () => { const element = createElement(); const session = createSession(element);