gabriel / musehub public
test_musehub_ui_similarity_ssr.py python
219 lines 8.3 KB
cd448303 Initial extraction of MuseHub from maestro monorepo. Gabriel Cardona <gabriel@tellurstori.com> 7d ago
1 """SSR-specific tests for the similarity and emotion-diff pages.
2
3 Covers the migration from client-side JS chart rendering to server-side SVG
4 and Jinja2 templates per issue #567.
5
6 Tests:
7 - test_similarity_page_renders_svg_server_side — <svg> present in HTML response
8 - test_similarity_page_renders_dimension_labels — dimension labels in SVG text
9 - test_similarity_page_renders_correlation_values — score pct in breakdown table
10 - test_emotion_diff_page_renders_timeline_bars — delta bar divs in HTML
11 - test_emotion_diff_page_no_js_chart_lib — no ChartJS or D3 references in page
12 - test_similarity_page_no_js_chart_lib — no ChartJS or D3 references in page
13 - test_emotion_diff_page_renders_svg_server_side — <svg> elements in both radars
14 - test_emotion_diff_page_renders_dimension_labels — all 8 axis labels in SVG
15 - test_similarity_page_renders_overall_badge — overall pct badge in HTML
16 - test_emotion_diff_page_renders_delta_table — per-axis delta table present
17 """
18 from __future__ import annotations
19
20 import pytest
21 from httpx import AsyncClient
22 from sqlalchemy.ext.asyncio import AsyncSession
23
24 from musehub.db.musehub_models import MusehubRepo
25
26
27 # ---------------------------------------------------------------------------
28 # Helpers
29 # ---------------------------------------------------------------------------
30
31
32 async def _make_repo(db_session: AsyncSession) -> str:
33 """Seed a minimal repo and return its repo_id."""
34 repo = MusehubRepo(
35 name="ssr-test-beats",
36 owner="ssruser",
37 slug="ssr-test-beats",
38 visibility="private",
39 owner_user_id="ssr-owner",
40 )
41 db_session.add(repo)
42 await db_session.commit()
43 await db_session.refresh(repo)
44 return str(repo.repo_id)
45
46
47 _SIM_URL = "/musehub/ui/ssruser/ssr-test-beats/similarity/main...feature"
48 _EDIFF_URL = "/musehub/ui/ssruser/ssr-test-beats/emotion-diff/main...feature"
49
50
51 # ---------------------------------------------------------------------------
52 # Similarity SSR tests
53 # ---------------------------------------------------------------------------
54
55
56 @pytest.mark.anyio
57 async def test_similarity_page_renders_svg_server_side(
58 client: AsyncClient,
59 db_session: AsyncSession,
60 ) -> None:
61 """GET similarity page returns HTML containing a server-rendered <svg> element."""
62 await _make_repo(db_session)
63 response = await client.get(_SIM_URL)
64 assert response.status_code == 200
65 body = response.text
66 assert "<svg" in body, "Expected server-rendered <svg> element in response body"
67 assert "viewBox" in body, "Expected viewBox attribute on SVG (server-rendered)"
68
69
70 @pytest.mark.anyio
71 async def test_similarity_page_renders_dimension_labels(
72 client: AsyncClient,
73 db_session: AsyncSession,
74 ) -> None:
75 """Similarity page SVG contains all 10 dimension axis labels server-side."""
76 await _make_repo(db_session)
77 response = await client.get(_SIM_URL)
78 assert response.status_code == 200
79 body = response.text
80 for label in ("Pitch", "Rhythm", "Tempo", "Dynamics", "Harmony",
81 "Form", "Blend", "Groove", "Contour", "Emotion"):
82 assert label in body, f"Dimension label '{label}' missing from server-rendered page"
83
84
85 @pytest.mark.anyio
86 async def test_similarity_page_renders_correlation_values(
87 client: AsyncClient,
88 db_session: AsyncSession,
89 ) -> None:
90 """Similarity page contains numeric percentage values in the breakdown table."""
91 await _make_repo(db_session)
92 response = await client.get(_SIM_URL)
93 assert response.status_code == 200
94 body = response.text
95 # The dimension breakdown table renders scores as "XX%" via server-side Jinja2
96 assert "%" in body, "Expected percentage values in breakdown table"
97 assert "Dimension Breakdown" in body
98 assert "overall musical similarity" in body
99
100
101 @pytest.mark.anyio
102 async def test_similarity_page_renders_overall_badge(
103 client: AsyncClient,
104 db_session: AsyncSession,
105 ) -> None:
106 """Similarity page contains the overall percentage badge rendered server-side."""
107 await _make_repo(db_session)
108 response = await client.get(_SIM_URL)
109 assert response.status_code == 200
110 body = response.text
111 assert "overall musical similarity" in body
112 # Badge is rendered as a Jinja2 expression — should be a numeric %
113 assert "%" in body
114
115
116 @pytest.mark.anyio
117 async def test_similarity_page_no_js_chart_lib(
118 client: AsyncClient,
119 db_session: AsyncSession,
120 ) -> None:
121 """Similarity page does not reference client-side chart libraries (ChartJS, D3)."""
122 await _make_repo(db_session)
123 response = await client.get(_SIM_URL)
124 assert response.status_code == 200
125 body = response.text
126 assert "chart.js" not in body.lower(), "ChartJS must not be present in SSR page"
127 assert "d3.js" not in body.lower(), "D3 must not be present in SSR page"
128 assert "cdn.jsdelivr.net/npm/chart" not in body.lower()
129
130
131 # ---------------------------------------------------------------------------
132 # Emotion-diff SSR tests
133 # ---------------------------------------------------------------------------
134
135
136 @pytest.mark.anyio
137 async def test_emotion_diff_page_renders_timeline_bars(
138 client: AsyncClient,
139 db_session: AsyncSession,
140 ) -> None:
141 """Emotion-diff page renders per-axis delta bar divs (CSS bars, no JS)."""
142 await _make_repo(db_session)
143 response = await client.get(_EDIFF_URL)
144 assert response.status_code == 200
145 body = response.text
146 # Delta bar divs are rendered server-side with inline CSS width/left
147 assert "Per-Axis Delta" in body
148 assert "bar_left_pct" not in body, (
149 "Jinja2 variable names must not leak into HTML — template may have a render error"
150 )
151 # The delta table rows contain direction labels rendered server-side
152 for direction_label in ("increase", "decrease", "unchanged"):
153 # At least one of these must appear (depends on computed delta)
154 if direction_label in body:
155 break
156 else:
157 pytest.fail("No direction label (increase/decrease/unchanged) found in delta table")
158
159
160 @pytest.mark.anyio
161 async def test_emotion_diff_page_no_js_chart_lib(
162 client: AsyncClient,
163 db_session: AsyncSession,
164 ) -> None:
165 """Emotion-diff page does not reference ChartJS or D3 chart libraries."""
166 await _make_repo(db_session)
167 response = await client.get(_EDIFF_URL)
168 assert response.status_code == 200
169 body = response.text
170 assert "chart.js" not in body.lower(), "ChartJS must not be present in SSR page"
171 assert "d3.js" not in body.lower(), "D3 must not be present in SSR page"
172 assert "cdn.jsdelivr.net/npm/chart" not in body.lower()
173
174
175 @pytest.mark.anyio
176 async def test_emotion_diff_page_renders_svg_server_side(
177 client: AsyncClient,
178 db_session: AsyncSession,
179 ) -> None:
180 """Emotion-diff page returns HTML containing server-rendered <svg> radar elements."""
181 await _make_repo(db_session)
182 response = await client.get(_EDIFF_URL)
183 assert response.status_code == 200
184 body = response.text
185 assert "<svg" in body, "Expected server-rendered <svg> elements in response body"
186 # Side-by-side radars: both base (#58a6ff) and head (#f0883e) colors appear
187 assert "#58a6ff" in body, "Base radar color missing — base SVG not rendered"
188 assert "#f0883e" in body, "Head radar color missing — head SVG not rendered"
189
190
191 @pytest.mark.anyio
192 async def test_emotion_diff_page_renders_dimension_labels(
193 client: AsyncClient,
194 db_session: AsyncSession,
195 ) -> None:
196 """Emotion-diff page SVG contains all 8 emotional axis labels server-side."""
197 await _make_repo(db_session)
198 response = await client.get(_EDIFF_URL)
199 assert response.status_code == 200
200 body = response.text
201 for label in ("Valence", "Energy", "Tension", "Complexity",
202 "Warmth", "Brightness", "Darkness", "Playfulness"):
203 assert label in body, f"Emotion axis label '{label}' missing from server-rendered page"
204
205
206 @pytest.mark.anyio
207 async def test_emotion_diff_page_renders_delta_table(
208 client: AsyncClient,
209 db_session: AsyncSession,
210 ) -> None:
211 """Emotion-diff page contains the per-axis delta breakdown table."""
212 await _make_repo(db_session)
213 response = await client.get(_EDIFF_URL)
214 assert response.status_code == 200
215 body = response.text
216 assert "Per-Axis Delta" in body
217 assert "8-Dimension Emotional Signature" in body
218 assert "Listen Base" in body
219 assert "Listen Head" in body