Files
wyndham-ARR/tests/test_arr_web_task_log_ui.py
2026-08-02 12:56:22 +08:00

84 lines
4.0 KiB
Python

from __future__ import annotations
import unittest
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
STATIC_ROOT = PROJECT_ROOT / "arr_web" / "static"
class TaskLogStaticContractTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.html = (STATIC_ROOT / "index.html").read_text(encoding="utf-8")
cls.styles = (STATIC_ROOT / "styles.css").read_text(encoding="utf-8")
cls.script = (STATIC_ROOT / "app.js").read_text(encoding="utf-8")
def test_header_utility_replaces_mobile_dashboard_entry(self) -> None:
self.assertIn('id="task-log-trigger"', self.html)
self.assertIn('<a class="task-log-link"', self.html)
self.assertIn('aria-haspopup="dialog"', self.html)
self.assertIn('aria-controls="task-log-dialog"', self.html)
self.assertNotIn("手机看板", self.html)
self.assertNotIn('class="h5-link"', self.html)
def test_console_is_outside_the_daily_panel_and_inside_one_dialog(self) -> None:
daily_start = self.html.index('id="panel-daily"')
daily_end = self.html.index('id="panel-monthly"')
daily_panel = self.html[daily_start:daily_end]
self.assertNotIn('id="process-log"', daily_panel)
self.assertEqual(self.html.count('id="process-log"'), 1)
self.assertEqual(self.html.count('id="task-log-dialog"'), 1)
self.assertGreater(
self.html.index('id="task-log-dialog"'),
self.html.index("</main>"),
)
for required_id in (
'id="process-title"',
'id="trace-live-state"',
'id="refresh-trace"',
'id="copy-trace"',
'id="close-task-log"',
):
self.assertIn(required_id, self.html)
def test_dialog_open_close_and_polling_contract(self) -> None:
self.assertIn('$("#task-log-trigger").addEventListener("click", (event) => {', self.script)
self.assertIn("event.preventDefault();", self.script)
self.assertIn("openTaskLog();", self.script)
self.assertIn('$("#close-task-log").addEventListener("click", closeTaskLog)', self.script)
self.assertIn('$("#task-log-dialog").addEventListener("close", clearTracePoll)', self.script)
self.assertIn("|| !taskLogIsOpen()", self.script)
self.assertIn("{ showLog: true }", self.script)
self.assertNotIn('{ scroll: true }', self.script)
def test_upload_keeps_progress_inline_without_opening_log(self) -> None:
self.assertIn('id="upload-progress"', self.html)
self.assertIn('id="upload-progress-track"', self.html)
self.assertIn('role="progressbar"', self.html)
self.assertIn("DAILY_UPLOAD_PROGRESS_STAGES", self.script)
self.assertIn("function startUploadProgress()", self.script)
self.assertIn("function finishUploadProgress(success, label)", self.script)
upload_start = self.script.index("async function handleUpload()")
upload_end = self.script.index("\n async function loadMonthsAndAnalytics", upload_start)
upload_handler = self.script[upload_start:upload_end]
self.assertIn("startUploadProgress()", upload_handler)
self.assertIn("finishUploadProgress", upload_handler)
self.assertNotIn("openTaskLog()", upload_handler)
self.assertNotIn("showLog: true", upload_handler)
def test_dialog_reuses_responsive_accessible_visual_system(self) -> None:
self.assertIn(".task-log-link:hover", self.styles)
self.assertIn(".task-log-link:active", self.styles)
self.assertIn(".task-log-dialog::backdrop", self.styles)
self.assertIn(".upload-progress-track", self.styles)
self.assertIn(".upload-progress.is-success", self.styles)
self.assertIn("max-height: calc(100dvh - 32px)", self.styles)
self.assertIn("@media (max-width: 700px)", self.styles)
self.assertIn("@media (prefers-reduced-motion: reduce)", self.styles)
if __name__ == "__main__":
unittest.main(verbosity=2)