@@ -628,11 +628,19 @@ def _assert_clean_init(result: HarnessResult) -> None:
628628
629629
630630class TestVersionFooter :
631- """The version footer at the bottom of the settings page reads from
632- /api/settings/info on init and renders ``ha-mcp < version>`` so an
633- operator can see the running build without leaving the UI.
631+ """The footer at the bottom of the settings page reads from
632+ /api/settings/info on init and renders the running version and installation
633+ method so an operator can identify the active build without leaving the UI.
634634 """
635635
636+ @staticmethod
637+ def _footer_text (result : HarnessResult ) -> str :
638+ match = re .search (r'id="versionFooterText">([^<]*)</div>' , result .dom )
639+ assert match is not None , (
640+ f"version footer missing; dom tail: { result .dom [- 1500 :]} "
641+ )
642+ return match .group (1 )
643+
636644 def test_version_rendered_from_settings_info (self , settings_script : str ) -> None :
637645 fetches = {
638646 ** DEFAULT_FETCHES ,
@@ -654,8 +662,103 @@ def test_version_rendered_from_settings_info(self, settings_script: str) -> None
654662 invoke = "await new Promise(r => setTimeout(r, 200));" ,
655663 )
656664 _assert_clean_init (result )
657- assert "ha-mcp 7.5.0.dev400" in result .dom , (
658- f"version footer missing or wrong; dom tail: { result .dom [- 1500 :]} "
665+ assert self ._footer_text (result ) == "ha-mcp 7.5.0.dev400"
666+
667+ @pytest .mark .parametrize (
668+ ("deployment_mode" , "expected_label" ),
669+ [
670+ ("embedded" , "embedded" ),
671+ ("sidecar" , "sidecar" ),
672+ ("addon" , "app/add-on" ),
673+ ("docker" , "container/docker" ),
674+ ("pyinstaller" , "standalone binary" ),
675+ ("git" , "source checkout" ),
676+ ("pypi" , "python package" ),
677+ ("unknown" , "unknown" ),
678+ ("future-mode" , "future-mode" ),
679+ ("constructor" , "constructor" ),
680+ ],
681+ )
682+ def test_installation_method_rendered_from_settings_info (
683+ self ,
684+ settings_script : str ,
685+ deployment_mode : str ,
686+ expected_label : str ,
687+ ) -> None :
688+ fetches = {
689+ ** DEFAULT_FETCHES ,
690+ "/api/settings/info" : {
691+ "status" : 200 ,
692+ "json" : {
693+ "is_addon" : deployment_mode == "addon" ,
694+ "is_sidecar" : deployment_mode == "sidecar" ,
695+ "deployment_mode" : deployment_mode ,
696+ "instance_id" : "test-id" ,
697+ "started_at" : 0 ,
698+ "version" : "8.2.0" ,
699+ },
700+ },
701+ }
702+ result = run_script (
703+ settings_script ,
704+ initial_html = MIN_DOM ,
705+ fetch_map = fetches ,
706+ invoke = "await new Promise(r => setTimeout(r, 200));" ,
707+ )
708+ _assert_clean_init (result )
709+ assert (
710+ self ._footer_text (result )
711+ == f"ha-mcp 8.2.0 · installation: { expected_label } "
712+ )
713+
714+ @pytest .mark .parametrize (
715+ ("deployment_mode" , "translated_label" ),
716+ [("embedded" , "intégré" ), ("sidecar" , "accompagnement" )],
717+ )
718+ def test_server_mode_labels_stay_raw_when_footer_phrase_is_localized (
719+ self ,
720+ settings_script : str ,
721+ deployment_mode : str ,
722+ translated_label : str ,
723+ ) -> None :
724+ from ha_mcp .settings_ui ._i18n import build_payload , serialize_payload
725+
726+ catalog = build_payload ("fr" )
727+ catalog ["messages" ].update (
728+ {
729+ "footer.installation" : "mode d’installation : {method}" ,
730+ f"footer.deployment.{ deployment_mode } " : translated_label ,
731+ }
732+ )
733+ payload = serialize_payload (catalog )
734+ localized_dom = MIN_DOM .replace (
735+ "</body>" ,
736+ f'<script id="ha-mcp-i18n" type="application/json">{ payload } </script>'
737+ "</body>" ,
738+ )
739+ fetches = {
740+ ** DEFAULT_FETCHES ,
741+ "/api/settings/info" : {
742+ "status" : 200 ,
743+ "json" : {
744+ "is_addon" : False ,
745+ "is_sidecar" : deployment_mode == "sidecar" ,
746+ "deployment_mode" : deployment_mode ,
747+ "instance_id" : "test-id" ,
748+ "started_at" : 0 ,
749+ "version" : "8.2.0" ,
750+ },
751+ },
752+ }
753+ result = run_script (
754+ settings_script ,
755+ initial_html = localized_dom ,
756+ fetch_map = fetches ,
757+ invoke = "await new Promise(r => setTimeout(r, 200));" ,
758+ )
759+ _assert_clean_init (result )
760+ assert self ._footer_text (result ) == (
761+ f"ha-mcp 8.2.0 · mode d’installation : { deployment_mode } "
659762 )
660763
661764 def test_version_omitted_when_info_response_lacks_version (
@@ -684,7 +787,7 @@ def test_version_omitted_when_info_response_lacks_version(
684787 invoke = "await new Promise(r => setTimeout(r, 200));" ,
685788 )
686789 _assert_clean_init (result )
687- assert "ha-mcp undefined" not in result . dom
790+ assert self . _footer_text ( result ) == ""
688791
689792
690793class TestXssGuard :
0 commit comments