import { describe, expect, it } from 'vitest'; import { flingDir, pushSample, type Sample } from './fling'; /** A straight drag from (0,0) by (dx,dy) over `ms`, sampled every 16 ms. */ function drag(dx: number, dy: number, ms: number): Sample[] { const out: Sample[] = []; for (let t = 0; t <= ms; t += 16) pushSample(out, { x: (dx * t) / ms, y: (dy * t) / ms, t }); return out; } describe('flingDir', () => { it('maps a flick to the side it reveals', () => { expect(flingDir(drag(-200, 0, 96))).toBe('right'); expect(flingDir(drag(200, 0, 96))).toBe('left'); expect(flingDir(drag(0, -200, 96))).toBe('down'); expect(flingDir(drag(0, 200, 96))).toBe('up'); }); it('ignores slow drags', () => { expect(flingDir(drag(-200, 0, 800))).toBeNull(); }); it('ignores diagonal flicks', () => { expect(flingDir(drag(-200, -150, 96))).toBeNull(); }); it('ignores a drag that stops before lifting', () => { const s = drag(-300, 0, 96); const end = s.at(-1)!; for (let t = 16; t <= 160; t += 16) pushSample(s, { ...end, t: end.t + t }); expect(flingDir(s)).toBeNull(); }); it('needs at least two samples', () => { expect(flingDir([])).toBeNull(); expect(flingDir([{ x: 0, y: 0, t: 0 }])).toBeNull(); }); it('keeps the trail short', () => { const s = drag(-2000, 0, 2000); expect(s.at(-1)!.t - s[0].t).toBeLessThanOrEqual(216); }); });