ui-copilot / tests /test_roadmap.py
ksri77's picture
feat: Module 7 β€” Improvement Roadmap (7 categorised buckets in API response)
0a8a8f9
Raw
History Blame Contribute Delete
5.33 kB
"""
Module 7 β€” Improvement Roadmap: AnalysisResult.roadmap buckets.
"""
from __future__ import annotations
import pytest
from backend.models.issue import Category
from backend.services import scoring_engine
from tests.fixtures import bad_page, clean_page
@pytest.fixture
def bad_result():
return scoring_engine.analyze(bad_page())
@pytest.fixture
def clean_result():
return scoring_engine.analyze(clean_page())
# ── top_issues ────────────────────────────────────────────────────────────────
class TestTopIssues:
def test_at_most_ten(self, bad_result):
assert len(bad_result.top_issues) <= 10
def test_sorted_by_gain_desc(self, bad_result):
gains = [i.estimated_gain for i in bad_result.top_issues]
assert gains == sorted(gains, reverse=True)
def test_subset_of_all_issues(self, bad_result):
for issue in bad_result.top_issues:
assert issue in bad_result.issues
def test_empty_when_no_issues(self, clean_result):
assert len(clean_result.top_issues) <= 10
# ── quick_wins ────────────────────────────────────────────────────────────────
class TestQuickWins:
def test_all_are_minutes(self, bad_result):
for i in bad_result.quick_wins:
assert "minute" in i.estimated_time
def test_all_have_positive_gain(self, bad_result):
for i in bad_result.quick_wins:
assert i.estimated_gain >= 1.0
def test_not_empty_on_bad_page(self, bad_result):
assert bad_result.quick_wins, "bad_page should produce at least one quick win"
# ── high_impact ───────────────────────────────────────────────────────────────
class TestHighImpact:
def test_at_most_five(self, bad_result):
assert len(bad_result.high_impact) <= 5
def test_all_above_threshold(self, bad_result):
for i in bad_result.high_impact:
assert i.estimated_gain >= 2.0
def test_sorted_by_gain_desc(self, bad_result):
gains = [i.estimated_gain for i in bad_result.high_impact]
assert gains == sorted(gains, reverse=True)
# ── easy_fixes ────────────────────────────────────────────────────────────────
class TestEasyFixes:
def test_all_are_minutes(self, bad_result):
for i in bad_result.easy_fixes:
assert "minute" in i.estimated_time
def test_not_empty_on_bad_page(self, bad_result):
assert bad_result.easy_fixes
# ── accessibility_fixes ───────────────────────────────────────────────────────
class TestAccessibilityFixes:
def test_all_are_accessibility_category(self, bad_result):
for i in bad_result.accessibility_fixes:
assert i.category == Category.ACCESSIBILITY
def test_not_empty_on_bad_page(self, bad_result):
assert bad_result.accessibility_fixes
# ── visual_improvements ───────────────────────────────────────────────────────
class TestVisualImprovements:
def test_all_are_visual_categories(self, bad_result):
allowed = {Category.VISUAL_HIERARCHY, Category.TYPOGRAPHY}
for i in bad_result.visual_improvements:
assert i.category in allowed
def test_not_empty_on_bad_page(self, bad_result):
assert bad_result.visual_improvements
# ── consistency_improvements ──────────────────────────────────────────────────
class TestConsistencyImprovements:
def test_all_are_consistency_category(self, bad_result):
for i in bad_result.consistency_improvements:
assert i.category == Category.CONSISTENCY
def test_not_empty_on_bad_page(self, bad_result):
assert bad_result.consistency_improvements
# ── roadmap dict ──────────────────────────────────────────────────────────────
class TestRoadmapDict:
_EXPECTED_KEYS = {
"top_issues", "quick_wins", "high_impact", "easy_fixes",
"accessibility_fixes", "visual_improvements", "consistency_improvements",
}
def test_roadmap_has_all_keys(self, bad_result):
assert set(bad_result.roadmap.keys()) == self._EXPECTED_KEYS
def test_roadmap_values_are_lists(self, bad_result):
for key, value in bad_result.roadmap.items():
assert isinstance(value, list), f"{key} should be a list"
def test_clean_page_roadmap_has_all_keys(self, clean_result):
assert set(clean_result.roadmap.keys()) == self._EXPECTED_KEYS