import { describe, expect, it } from 'vitest' import { nearestIndex, scrollEdges } from './geometry' describe('nearestIndex', () => { it('returns the index of the offset closest to the scroll position', () => { const offsets = [0, 100, 200, 300, 400] expect(nearestIndex(offsets, 0)).toBe(0) expect(nearestIndex(offsets, 190)).toBe(2) expect(nearestIndex(offsets, 260)).toBe(3) }) it('tracks the left-most visible card after paging forward', () => { // 10 cards, 100px apart; scrolled two pages of 4 → left edge at card 4. const offsets = Array.from({ length: 10 }, (_, i) => i * 100) expect(nearestIndex(offsets, 400)).toBe(4) }) it('resolves the clamped end to the left-most visible card, not the last', () => { // 10 cards, ~4.5 visible; at the clamped end the focused card is mid-list, // never the final card. This is the drift the fix prevents. const offsets = Array.from({ length: 10 }, (_, i) => i * 100) expect(nearestIndex(offsets, 560)).toBe(6) expect(nearestIndex(offsets, 560)).not.toBe(offsets.length - 1) }) it('breaks ties toward the lower index', () => { expect(nearestIndex([0, 100, 200], 50)).toBe(0) }) it('defaults to 0 for an empty list', () => { expect(nearestIndex([], 123)).toBe(0) }) }) describe('scrollEdges', () => { const scrollWidth = 1000 const clientWidth = 450 // max scroll = 550 it('reports the start when scrolled to 0', () => { expect(scrollEdges(0, scrollWidth, clientWidth)).toEqual({ atStart: true, atEnd: false, }) }) it('reports the end only when scrolled to the maximum', () => { expect(scrollEdges(300, scrollWidth, clientWidth).atEnd).toBe(false) expect(scrollEdges(550, scrollWidth, clientWidth)).toEqual({ atStart: false, atEnd: true, }) }) it('does not report the end early just because the last card is visible', () => { // The last card is on-screen from scrollLeft 500, but we are not at the // end until scrollLeft reaches its 550 maximum. This is the "one extra // click to disable" bug the fix removes. expect(scrollEdges(500, scrollWidth, clientWidth).atEnd).toBe(false) }) it('treats a non-overflowing container as both start and end', () => { expect(scrollEdges(0, 400, 450)).toEqual({ atStart: true, atEnd: true }) }) })