File size: 2,586 Bytes
da65740
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from pathlib import Path

from src.progress import progress_from_events


def test_old_failed_step_does_not_poison_later_validation_waiting():
    result = progress_from_events([
        {"ts": "2026-06-02T10:00:00+00:00", "step": "repair", "status": "failed", "message": "first attempt failed"},
        {"ts": "2026-06-02T10:01:00+00:00", "step": "api_validation", "status": "waiting", "message": "waiting validation"},
    ], state={"status": "running"})
    assert result["status"] == "running"
    assert result["current_step"] == "api_validation"
    statuses = {item["step"]: item["status"] for item in result["timeline"]}
    assert statuses["repair"] == "done"
    assert statuses["api_validation"] == "running"


def test_failed_state_only_wins_when_current_step_failed():
    result = progress_from_events([
        {"ts": "2026-06-02T10:00:00+00:00", "step": "api_validation", "status": "failed"},
    ], state={"status": "failed"})
    assert result["status"] == "failed"
    statuses = {item["step"]: item["status"] for item in result["timeline"]}
    assert statuses["api_validation"] == "failed"


def test_events_list_has_no_view_all_button_and_is_scrollable():
    html = Path("web/index.html").read_text(encoding="utf-8")
    js = Path("web/static/progress.js").read_text(encoding="utf-8")
    css = Path("web/static/app.css").read_text(encoding="utf-8")
    assert "viewAllEvents" not in html
    assert "toggleAllEvents" not in js
    assert "root.scrollTop=0" in js
    assert "max-height:184px" in css


def test_timeline_ensures_visible_without_recentering():
    js = Path("web/static/progress.js").read_text(encoding="utf-8")
    assert "function ensureTimelineStepVisible" in js
    assert "target.offsetLeft-(root.clientWidth-target.clientWidth)/2" not in js
    assert "targetRight>visibleRight-margin" in js


def test_polling_has_inflight_guard_and_lower_latency():
    js = Path("web/static/app.js").read_text(encoding="utf-8")
    assert "state.progressPollInFlight" in js
    assert "setInterval(refreshProgress,2000)" in js
    assert ">8000" in js


def test_resume_latest_falls_back_to_latest_run():
    app = Path("app.py").read_text(encoding="utf-8")
    js = Path("web/static/app.js").read_text(encoding="utf-8")
    assert "selected = resumable or (runs[0] if runs else None)" in app
    assert '"latest_run"' in app
    assert "await loadRuns(true)" in js
    assert "setButtonBusy('resumeLatestRun'" in js


def test_app_version_v70():
    assert '"version": "v70-progress-resume-events-latency"' in Path("app.py").read_text(encoding="utf-8")