gabriel / musehub public
test_musehub_js_cleanup.py python
171 lines 7.1 KB
cd448303 Initial extraction of MuseHub from maestro monorepo. Gabriel Cardona <gabriel@tellurstori.com> 7d ago
1 """Regression tests for the musehub.js cleanup (issue #586).
2
3 Verifies that displaced client-side rendering code has been removed from
4 musehub.js and all Jinja2 templates after the complete HTMX/SSR migration.
5
6 Covers:
7 - test_musehub_js_does_not_contain_render_rows — renderRows not in musehub.js
8 - test_musehub_js_does_not_contain_build_bulk_toolbar — buildBulkToolbar not in musehub.js
9 - test_musehub_js_does_not_contain_render_filter_sidebar — renderFilterSidebar not in musehub.js
10 - test_musehub_js_file_size_under_target — file < 20 KB after cleanup
11 - test_explore_base_html_deleted — explore_base.html has been removed
12 - test_all_template_page_script_blocks_empty_or_minimal — no legacy data-fetching
13 patterns survive in any page template
14 """
15
16 from __future__ import annotations
17
18 import pathlib
19
20 import pytest
21
22
23 # ── Paths ─────────────────────────────────────────────────────────────────────
24
25 _REPO_ROOT = pathlib.Path(__file__).parent.parent
26 _MUSEHUB_JS = _REPO_ROOT / "musehub" / "templates" / "musehub" / "static" / "musehub.js"
27 _TEMPLATE_ROOT = _REPO_ROOT / "musehub" / "templates" / "musehub"
28 _EXPLORE_BASE = _TEMPLATE_ROOT / "explore_base.html"
29
30 # ── Helpers ───────────────────────────────────────────────────────────────────
31
32 def _musehub_js_text() -> str:
33 """Return the full text of musehub.js, or empty string if absent."""
34 if not _MUSEHUB_JS.exists():
35 return ""
36 return _MUSEHUB_JS.read_text(encoding="utf-8")
37
38
39 def _all_page_templates() -> list[pathlib.Path]:
40 """Return all .html files under the musehub pages/ directory."""
41 pages_dir = _TEMPLATE_ROOT / "pages"
42 return list(pages_dir.glob("*.html"))
43
44
45 # ── Tests: musehub.js dead-code removal ───────────────────────────────────────
46
47
48 def test_musehub_js_does_not_contain_render_rows() -> None:
49 """renderRows was the main issue-list DOM renderer — now replaced by Jinja2."""
50 assert "renderRows" not in _musehub_js_text(), (
51 "renderRows() still present in musehub.js — it must be removed; "
52 "issue list HTML is now server-rendered."
53 )
54
55
56 def test_musehub_js_does_not_contain_build_bulk_toolbar() -> None:
57 """buildBulkToolbar was a client-side bulk-action UI builder — now gone."""
58 assert "buildBulkToolbar" not in _musehub_js_text(), (
59 "buildBulkToolbar() still present in musehub.js — it must be removed; "
60 "bulk toolbar HTML is now part of the server-rendered issue list fragment."
61 )
62
63
64 def test_musehub_js_does_not_contain_render_filter_sidebar() -> None:
65 """renderFilterSidebar was a client-side sidebar renderer — now Jinja2."""
66 assert "renderFilterSidebar" not in _musehub_js_text(), (
67 "renderFilterSidebar() still present in musehub.js — it must be removed; "
68 "filter sidebar is now rendered server-side."
69 )
70
71
72 def test_musehub_js_does_not_contain_load_issues() -> None:
73 """loadIssues was the client-side data-fetcher — replaced by route handlers."""
74 assert "function loadIssues" not in _musehub_js_text(), (
75 "loadIssues() still present in musehub.js — it must be removed; "
76 "issue data is now fetched server-side by the FastAPI route."
77 )
78
79
80 def test_musehub_js_does_not_contain_load_labels() -> None:
81 """loadLabels was a client-side data-fetcher for issue-list sidebar."""
82 assert "function loadLabels" not in _musehub_js_text(), (
83 "loadLabels() still present in musehub.js — replaced by server-side rendering."
84 )
85
86
87 def test_musehub_js_does_not_contain_render_right_sidebar() -> None:
88 """renderRightSidebar was a client-side renderer — now handled by Jinja2."""
89 assert "renderRightSidebar" not in _musehub_js_text(), (
90 "renderRightSidebar() still present in musehub.js — must be removed."
91 )
92
93
94 def test_musehub_js_file_size_under_target() -> None:
95 """File must be under 20 KB after cleanup (was 3–4 K lines before migration)."""
96 if not _MUSEHUB_JS.exists():
97 pytest.skip("musehub.js not found")
98 size_bytes = _MUSEHUB_JS.stat().st_size
99 limit_bytes = 20 * 1024 # 20 KB
100 assert size_bytes < limit_bytes, (
101 f"musehub.js is {size_bytes:,} bytes — exceeds 20 KB cleanup target. "
102 "Audit the file and remove any remaining dead code."
103 )
104
105
106 # ── Tests: template cleanup ────────────────────────────────────────────────────
107
108
109 def test_explore_base_html_deleted() -> None:
110 """explore_base.html must be deleted — no template extends it any more."""
111 assert not _EXPLORE_BASE.exists(), (
112 "explore_base.html still exists at "
113 f"{_EXPLORE_BASE} — it is no longer referenced by any "
114 "template and should be removed."
115 )
116
117
118 def test_all_template_page_script_blocks_empty_or_minimal() -> None:
119 """No page template should contain legacy client-side data-fetching patterns.
120
121 After the SSR/HTMX migration, the displaced fetch functions and state
122 variables must not appear in any {% block page_script %} section.
123 This is a regression guard: if a future merge re-introduces these patterns
124 the test will catch it immediately.
125 """
126 # Patterns that were removed as part of the HTMX migration.
127 # Their presence in any template indicates un-migrated client-side rendering.
128 displaced_patterns: list[str] = [
129 "function loadIssues",
130 "function loadLabels",
131 "function loadMilestones",
132 "function renderRows",
133 "function renderFilterSidebar",
134 "function renderRightSidebar",
135 "function buildBulkToolbar",
136 "function buildTemplatePicker",
137 "function loadCommentCounts",
138 "function loadReactionSummaries",
139 "function loadStashes",
140 "function loadNotifications",
141 "function loadReleases",
142 "function loadSessions",
143 "function loadCollaborators",
144 "function loadSettings",
145 "function loadActivity",
146 "const allIssues",
147 "let allIssues",
148 "var allIssues",
149 "const cachedOpen",
150 "let cachedOpen",
151 "const cachedClosed",
152 "let cachedClosed",
153 "const allLabels",
154 "let allLabels",
155 "const allMilestones",
156 "let allMilestones",
157 ]
158
159 violations: list[str] = []
160 for template in _all_page_templates():
161 text = template.read_text(encoding="utf-8")
162 for pattern in displaced_patterns:
163 if pattern in text:
164 violations.append(f"{template.name}: found '{pattern}'")
165
166 assert not violations, (
167 "Legacy client-side rendering patterns found in page templates.\n"
168 "These functions/variables were displaced by server-side rendering "
169 "and must be removed:\n"
170 + "\n".join(f" • {v}" for v in violations)
171 )