@@ -72,13 +72,16 @@ async def test_first_run_examples_endpoint(first_run_client):
7272async def test_first_run_create_empty_config (first_run_client ):
7373 """POST /api/config/create with mode=empty should create a valid config."""
7474 client , config_path = first_run_client
75- resp = await client .post ("/api/config/create" , json = {
76- "mode" : "empty" ,
77- "release_name" : "Test Release" ,
78- "target_month" : 6 ,
79- "target_year" : 2025 ,
80- "branch_pattern" : "release/{YYYY}.{MM}" ,
81- })
75+ resp = await client .post (
76+ "/api/config/create" ,
77+ json = {
78+ "mode" : "empty" ,
79+ "release_name" : "Test Release" ,
80+ "target_month" : 6 ,
81+ "target_year" : 2025 ,
82+ "branch_pattern" : "release/{YYYY}.{MM}" ,
83+ },
84+ )
8285 assert resp .status_code == 200
8386 data = resp .json ()
8487 assert data ["ok" ] is True
@@ -104,10 +107,13 @@ async def test_first_run_create_import_config(first_run_client):
104107 },
105108 "repositories" : [],
106109 }
107- resp = await client .post ("/api/config/create" , json = {
108- "mode" : "import" ,
109- "config" : imported ,
110- })
110+ resp = await client .post (
111+ "/api/config/create" ,
112+ json = {
113+ "mode" : "import" ,
114+ "config" : imported ,
115+ },
116+ )
111117 assert resp .status_code == 200
112118 data = resp .json ()
113119 assert data ["ok" ] is True
@@ -118,10 +124,13 @@ async def test_first_run_create_import_config(first_run_client):
118124async def test_first_run_create_invalid_config (first_run_client ):
119125 """POST /api/config/create with invalid data should return 422."""
120126 client , config_path = first_run_client
121- resp = await client .post ("/api/config/create" , json = {
122- "mode" : "import" ,
123- "config" : {"invalid" : True },
124- })
127+ resp = await client .post (
128+ "/api/config/create" ,
129+ json = {
130+ "mode" : "import" ,
131+ "config" : {"invalid" : True },
132+ },
133+ )
125134 assert resp .status_code == 422
126135 assert not config_path .exists ()
127136
@@ -154,12 +163,15 @@ async def test_first_run_after_config_created_dashboard_works(tmp_path: Path):
154163 transport = ASGITransport (app = app )
155164 async with AsyncClient (transport = transport , base_url = "http://test" ) as client :
156165 # Create config first
157- resp = await client .post ("/api/config/create" , json = {
158- "mode" : "empty" ,
159- "release_name" : "Post-Create Test" ,
160- "target_month" : 1 ,
161- "target_year" : 2025 ,
162- })
166+ resp = await client .post (
167+ "/api/config/create" ,
168+ json = {
169+ "mode" : "empty" ,
170+ "release_name" : "Post-Create Test" ,
171+ "target_month" : 1 ,
172+ "target_year" : 2025 ,
173+ },
174+ )
163175 assert resp .status_code == 200
164176
165177 # Now dashboard should serve normal content (state was initialized)
@@ -172,13 +184,15 @@ class TestRendererFirstRun:
172184
173185 def test_render_first_run_returns_html (self ):
174186 from releaseboard .presentation .renderer import DashboardRenderer
187+
175188 renderer = DashboardRenderer ()
176189 html = renderer .render_first_run (locale = "en" , config_path = "releaseboard.json" )
177190 assert "<!DOCTYPE html>" in html or "<!doctype html>" in html .lower ()
178191 assert "ReleaseBoard" in html
179192
180193 def test_render_first_run_contains_form_elements (self ):
181194 from releaseboard .presentation .renderer import DashboardRenderer
195+
182196 renderer = DashboardRenderer ()
183197 html = renderer .render_first_run (locale = "en" )
184198 # Should have form inputs for release config
@@ -187,6 +201,7 @@ def test_render_first_run_contains_form_elements(self):
187201
188202 def test_render_first_run_polish_locale (self ):
189203 from releaseboard .presentation .renderer import DashboardRenderer
204+
190205 renderer = DashboardRenderer ()
191206 html = renderer .render_first_run (locale = "pl" )
192207 assert "<!DOCTYPE html>" in html or "<!doctype html>" in html .lower ()
@@ -198,7 +213,11 @@ class TestFirstRunI18n:
198213 def test_en_first_run_keys_exist (self ):
199214 locale_path = (
200215 Path (__file__ ).resolve ().parent .parent
201- / "src" / "releaseboard" / "i18n" / "locales" / "en.json"
216+ / "src"
217+ / "releaseboard"
218+ / "i18n"
219+ / "locales"
220+ / "en.json"
202221 )
203222 data = json .loads (locale_path .read_text (encoding = "utf-8" ))
204223 required_keys = [
@@ -217,7 +236,11 @@ def test_en_first_run_keys_exist(self):
217236 def test_pl_first_run_keys_exist (self ):
218237 locale_path = (
219238 Path (__file__ ).resolve ().parent .parent
220- / "src" / "releaseboard" / "i18n" / "locales" / "pl.json"
239+ / "src"
240+ / "releaseboard"
241+ / "i18n"
242+ / "locales"
243+ / "pl.json"
221244 )
222245 data = json .loads (locale_path .read_text (encoding = "utf-8" ))
223246 required_keys = [
@@ -242,13 +265,15 @@ def test_serve_command_no_exists_constraint(self):
242265 import inspect
243266
244267 from releaseboard .cli .app import serve
268+
245269 sig = inspect .signature (serve )
246270 # The function should accept a Path without filesystem validation
247271 assert "config" in sig .parameters
248272
249273 def test_create_app_accepts_first_run (self ):
250274 """create_app should accept first_run keyword argument."""
251275 import inspect
276+
252277 sig = inspect .signature (create_app )
253278 assert "first_run" in sig .parameters
254279
@@ -258,6 +283,7 @@ class TestFirstRunShellParity:
258283
259284 def _render (self , locale = "en" ):
260285 from releaseboard .presentation .renderer import DashboardRenderer
286+
261287 return DashboardRenderer ().render_first_run (locale = locale )
262288
263289 def test_has_sticky_header (self ):
@@ -323,7 +349,11 @@ def test_polish_locale_renders_correctly(self):
323349 def test_prepare_config_i18n_keys_exist (self ):
324350 locale_path = (
325351 Path (__file__ ).resolve ().parent .parent
326- / "src" / "releaseboard" / "i18n" / "locales" / "en.json"
352+ / "src"
353+ / "releaseboard"
354+ / "i18n"
355+ / "locales"
356+ / "en.json"
327357 )
328358 data = json .loads (locale_path .read_text (encoding = "utf-8" ))
329359 assert "first_run.prepare_config" in data
@@ -338,7 +368,10 @@ def test_dashboard_has_open_wizard_param_handler(self):
338368 """The interactive scripts should check for open_wizard query param."""
339369 template_path = (
340370 Path (__file__ ).resolve ().parent .parent
341- / "src" / "releaseboard" / "presentation" / "templates"
371+ / "src"
372+ / "releaseboard"
373+ / "presentation"
374+ / "templates"
342375 / "_scripts_interactive.html.j2"
343376 )
344377 content = template_path .read_text (encoding = "utf-8" )
@@ -354,6 +387,7 @@ class TestFirstRunLogoLayout:
354387
355388 def _render (self , locale : str = "en" ) -> str :
356389 from releaseboard .presentation .renderer import DashboardRenderer
390+
357391 renderer = DashboardRenderer ()
358392 return renderer .render_first_run (locale = locale )
359393
@@ -383,6 +417,7 @@ class TestFirstRunLangRestore:
383417
384418 def _render (self ) -> str :
385419 from releaseboard .presentation .renderer import DashboardRenderer
420+
386421 renderer = DashboardRenderer ()
387422 return renderer .render_first_run ()
388423
@@ -406,7 +441,10 @@ def test_first_run_footer_has_rp_version_support(self):
406441 """First-run footer template must handle rp_version."""
407442 template_path = (
408443 Path (__file__ ).resolve ().parent .parent
409- / "src" / "releaseboard" / "presentation" / "templates"
444+ / "src"
445+ / "releaseboard"
446+ / "presentation"
447+ / "templates"
410448 / "first_run.html.j2"
411449 )
412450 content = template_path .read_text (encoding = "utf-8" )
@@ -416,18 +454,24 @@ def test_dashboard_footer_uses_dynamic_version(self):
416454 """Dashboard footer must use vm.version, not hardcoded version."""
417455 template_path = (
418456 Path (__file__ ).resolve ().parent .parent
419- / "src" / "releaseboard" / "presentation" / "templates"
457+ / "src"
458+ / "releaseboard"
459+ / "presentation"
460+ / "templates"
420461 / "_footer.html.j2"
421462 )
422463 content = template_path .read_text (encoding = "utf-8" )
423464 assert "v{{ vm.version }}" in content
424- assert "v1.10 .0" not in content # no hardcoded version
465+ assert "v1.1 .0" not in content # no hardcoded version
425466
426467 def test_dashboard_footer_has_rp_version_conditional (self ):
427468 """Dashboard footer must include vm.rp_version conditional."""
428469 template_path = (
429470 Path (__file__ ).resolve ().parent .parent
430- / "src" / "releaseboard" / "presentation" / "templates"
471+ / "src"
472+ / "releaseboard"
473+ / "presentation"
474+ / "templates"
431475 / "_footer.html.j2"
432476 )
433477 content = template_path .read_text (encoding = "utf-8" )
@@ -438,6 +482,7 @@ def test_view_model_has_rp_version_field(self):
438482 import dataclasses
439483
440484 from releaseboard .presentation .view_models import DashboardViewModel
485+
441486 field_names = [f .name for f in dataclasses .fields (DashboardViewModel )]
442487 assert "rp_version" in field_names
443488
@@ -460,6 +505,7 @@ def _render_empty_dashboard(self) -> str:
460505 vm .interactive = True
461506
462507 from releaseboard .presentation .renderer import DashboardRenderer
508+
463509 renderer = DashboardRenderer ()
464510 return renderer .render (vm )
465511
@@ -503,6 +549,7 @@ def test_empty_repos_state_not_shown_when_repos_exist(self):
503549 vm .interactive = True
504550
505551 from releaseboard .presentation .renderer import DashboardRenderer
552+
506553 renderer = DashboardRenderer ()
507554 html = renderer .render (vm )
508555 assert 'id="emptyReposState"' not in html
@@ -538,6 +585,7 @@ def test_non_empty_state_shows_metrics_and_filters(self):
538585 vm .interactive = True
539586
540587 from releaseboard .presentation .renderer import DashboardRenderer
588+
541589 renderer = DashboardRenderer ()
542590 html = renderer .render (vm )
543591 assert 'class="metrics-grid' in html
@@ -551,7 +599,11 @@ class TestEmptyStateI18nKeys:
551599 def test_en_empty_state_keys_exist (self ):
552600 locale_path = (
553601 Path (__file__ ).resolve ().parent .parent
554- / "src" / "releaseboard" / "i18n" / "locales" / "en.json"
602+ / "src"
603+ / "releaseboard"
604+ / "i18n"
605+ / "locales"
606+ / "en.json"
555607 )
556608 data = json .loads (locale_path .read_text (encoding = "utf-8" ))
557609 for key in [
@@ -566,7 +618,11 @@ def test_en_empty_state_keys_exist(self):
566618 def test_pl_empty_state_keys_exist (self ):
567619 locale_path = (
568620 Path (__file__ ).resolve ().parent .parent
569- / "src" / "releaseboard" / "i18n" / "locales" / "pl.json"
621+ / "src"
622+ / "releaseboard"
623+ / "i18n"
624+ / "locales"
625+ / "pl.json"
570626 )
571627 data = json .loads (locale_path .read_text (encoding = "utf-8" ))
572628 for key in [
@@ -590,6 +646,7 @@ class TestTripleLogoFix:
590646 def test_light_logo_visible_dark_hidden (self ):
591647 """fr-logo-light visible, dark/midnight hidden."""
592648 from releaseboard .presentation .renderer import DashboardRenderer
649+
593650 renderer = DashboardRenderer ()
594651 html = renderer .render_first_run (locale = "en" )
595652 # The fix: .fr-header-logo .fr-logo-light { display: block }
@@ -600,11 +657,13 @@ def test_light_logo_visible_dark_hidden(self):
600657 def test_no_blanket_svg_display_block (self ):
601658 """Must NOT have .fr-header-logo svg { display: block } which causes triple render."""
602659 from releaseboard .presentation .renderer import DashboardRenderer
660+
603661 renderer = DashboardRenderer ()
604662 html = renderer .render_first_run (locale = "en" )
605663 import re
664+
606665 # Must not have a rule that forces display:block on ALL svgs inside fr-header-logo
607- matches = re .findall (r' \.fr-header-logo\s+svg\s*\{[^}]*display\s*:\s*block' , html )
666+ matches = re .findall (r" \.fr-header-logo\s+svg\s*\{[^}]*display\s*:\s*block" , html )
608667 assert len (matches ) == 0 , "Must not force display:block on all SVGs inside .fr-header-logo"
609668
610669
@@ -613,6 +672,7 @@ class TestLocalePreloadFirstRun:
613672
614673 def test_locale_preload_script_present (self ):
615674 from releaseboard .presentation .renderer import DashboardRenderer
675+
616676 renderer = DashboardRenderer ()
617677 html = renderer .render_first_run (locale = "en" )
618678 assert "localStorage.getItem('rb_locale')" in html
@@ -621,6 +681,7 @@ def test_locale_preload_script_present(self):
621681 def test_language_switch_saves_to_localstorage (self ):
622682 """First-run language switch must save to localStorage rb_locale."""
623683 from releaseboard .presentation .renderer import DashboardRenderer
684+
624685 renderer = DashboardRenderer ()
625686 html = renderer .render_first_run (locale = "en" )
626687 assert "localStorage.setItem('rb_locale'" in html
@@ -632,18 +693,21 @@ class TestRedirectUrlsCarryLang:
632693 def test_with_lang_helper_defined (self ):
633694 """withLang() helper must be present to append ?lang= to redirect URLs."""
634695 from releaseboard .presentation .renderer import DashboardRenderer
696+
635697 renderer = DashboardRenderer ()
636698 html = renderer .render_first_run (locale = "en" )
637699 assert "function withLang(url)" in html
638700
639701 def test_create_fresh_uses_with_lang (self ):
640702 from releaseboard .presentation .renderer import DashboardRenderer
703+
641704 renderer = DashboardRenderer ()
642705 html = renderer .render_first_run (locale = "en" )
643706 assert "withLang(data.redirect)" in html
644707
645708 def test_prepare_config_uses_with_lang (self ):
646709 from releaseboard .presentation .renderer import DashboardRenderer
710+
647711 renderer = DashboardRenderer ()
648712 html = renderer .render_first_run (locale = "en" )
649713 assert "withLang('/?open_wizard=1')" in html
0 commit comments