from __future__ import annotations from html.parser import HTMLParser from pathlib import Path import shutil import subprocess import pytest NODE = shutil.which("node") APP_JS = Path("src/yolo_webui/static/app.js") INDEX_HTML = Path("src/yolo_webui/static/index.html") STYLE_CSS = Path("src/yolo_webui/static/style.css") class _MarkupCollector(HTMLParser): def __init__(self) -> None: super().__init__() self.by_id: dict[str, dict[str, str | None]] = {} self.options: dict[str, str] = {} self._option_value: str | None = None def handle_starttag( self, tag: str, attrs: list[tuple[str, str | None]], ) -> None: attributes = dict(attrs) if element_id := attributes.get("id"): self.by_id[element_id] = attributes if tag == "option": self._option_value = attributes.get("value") def handle_data(self, data: str) -> None: if self._option_value is not None: self.options[self._option_value] = ( self.options.get(self._option_value, "") + data ).strip() def handle_endtag(self, tag: str) -> None: if tag == "option": self._option_value = None @pytest.mark.skipif(NODE is None, reason="Node.js is required for frontend checks") def test_frontend_javascript_syntax() -> None: subprocess.run([NODE, "--check", str(APP_JS)], check=True) @pytest.mark.skipif(NODE is None, reason="Node.js is required for frontend checks") def test_frontend_interactions_smoke() -> None: subprocess.run([NODE, "tests/frontend_smoke.js"], check=True) def test_export_controls_have_correct_formats_constraints_and_styles() -> None: parser = _MarkupCollector() parser.feed(INDEX_HTML.read_text(encoding="utf-8")) assert parser.options["saved_model"].startswith("TensorFlow SavedModel") assert parser.options["pb"] == "TensorFlow GraphDef (.pb)" assert "triton" not in parser.options assert parser.by_id["export-imgsz"]["min"] == "32" assert parser.by_id["export-imgsz"]["max"] == "8192" assert parser.by_id["export-imgsz"]["step"] == "1" assert parser.by_id["export-batch"]["min"] == "1" assert parser.by_id["export-batch"]["max"] == "1024" assert parser.by_id["export-batch"]["step"] == "1" assert parser.by_id["export-workspace"]["min"] == "1" assert parser.by_id["export-workspace"]["max"] == "64" assert parser.by_id["export-workspace"]["step"] == "0.5" css = STYLE_CSS.read_text(encoding="utf-8") assert "#export-config-pane" in css assert "#export-run-pane" in css assert "#export-log-container::-webkit-scrollbar" in css assert "#export-status-card.status-exporting" in css assert "#export-status-card.status-failed" in css