import { describe, it, expect, vi } from 'vitest'; import { animateView } from './animateView'; describe('animateView (reduced motion)', () => { const from = { x: 0, y: 0, z: 1 }; const to = { x: 80, y: -30, z: 2 }; it('snaps straight to the target in a single frame when reduced motion is on', () => { const onFrame = vi.fn(); const cancel = animateView(from, to, onFrame, { reducedMotion: true }); expect(onFrame).toHaveBeenCalledTimes(1); expect(onFrame).toHaveBeenCalledWith(to); expect(typeof cancel).toBe('function'); cancel(); }); }); describe('animateView (animated path)', () => { const from = { x: 0, y: 0, z: 1 }; const to = { x: 100, y: 0, z: 2 }; it('tweens across frames and lands exactly on the target', () => { const frames: { x: number }[] = []; const callbacks: FrameRequestCallback[] = []; vi.stubGlobal('performance', { now: () => 0 }); vi.stubGlobal('requestAnimationFrame', (cb: FrameRequestCallback) => callbacks.push(cb)); vi.stubGlobal('cancelAnimationFrame', () => {}); animateView(from, to, (v) => frames.push(v), { durationMs: 100 }); callbacks[0](50); // t = 0.5 → an interpolated frame callbacks[callbacks.length - 1](100); // t = 1 → exact target expect(frames.length).toBeGreaterThanOrEqual(2); expect(frames[0].x).toBeGreaterThan(0); expect(frames[0].x).toBeLessThan(100); expect(frames.at(-1)).toEqual(to); vi.unstubAllGlobals(); }); });