"""Tests for scroll collection state and target generation.""" from __future__ import annotations import pytest from tools.scroll.collector import ScrollCollector class TestNextTarget: def test_target_mode_distance_range(self): sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900) for _ in range(20): result = sc.next_target(current_scrollY=2000) dist = abs(result["target_scrollY"] - 2000) assert 500 <= dist <= 3000 assert result["direction"] in ("up", "down") def test_fast_mode_distance_range(self): sc = ScrollCollector(mode="fast", count=10, page_height=10000, viewport_height=900) for _ in range(20): result = sc.next_target(current_scrollY=5000) dist = abs(result["target_scrollY"] - 5000) assert 3000 <= dist <= 8000 def test_precise_mode_distance_range(self): sc = ScrollCollector(mode="precise", count=10, page_height=10000, viewport_height=900) for _ in range(20): result = sc.next_target(current_scrollY=3000) dist = abs(result["target_scrollY"] - 3000) assert 200 <= dist <= 800 def test_target_within_page_bounds(self): sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900) result = sc.next_target(current_scrollY=1000) assert 0 <= result["target_scrollY"] <= 10000 result = sc.next_target(current_scrollY=9000) assert 0 <= result["target_scrollY"] <= 10000 def test_success_zone_by_mode(self): sc = ScrollCollector(mode="target", count=10, page_height=10000) assert sc.success_radius == 80 sc2 = ScrollCollector(mode="fast", count=10, page_height=10000) assert sc2.success_radius == 120 sc3 = ScrollCollector(mode="precise", count=10, page_height=10000) assert sc3.success_radius == 40 def test_target_always_reachable(self): """Target must always be reachable: user can scroll to bring it into success zone.""" sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900) viewport_center = 450 # 900 / 2 max_scroll_top = 10000 - 900 # 9100 for current in [0, 100, 500, 2000, 5000, 8000, 9000]: for _ in range(10): result = sc.next_target(current_scrollY=current) target = result["target_scrollY"] # The scrollTop needed to bring target into viewport center needed_scroll = target - viewport_center + 25 # Must be achievable (0 <= needed_scroll <= max_scroll_top) # With success_radius=80, there's a window, not exact match needed reachable_min = viewport_center - sc.success_radius reachable_max = max_scroll_top + viewport_center + sc.success_radius assert reachable_min <= target <= reachable_max, ( f"Target {target} not reachable from scrollY={current}" )