"""Static + Node checks for the B-44 visual rework. Covers unique ids, nav copy, drawer/directory breakpoints, eight-column event table, and the exported keyboard/amount helpers. """ from __future__ import annotations from pathlib import Path import re import subprocess import unittest ROOT = Path(__file__).resolve().parents[1] WEB = ROOT / "web" class B44FrontendContractTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.admin = (WEB / "admin.html").read_text(encoding="utf-8") cls.company = (WEB / "company.html").read_text(encoding="utf-8") cls.css = (WEB / "styles.css").read_text(encoding="utf-8") cls.js = (WEB / "app.js").read_text(encoding="utf-8") def test_admin_ids_are_unique(self) -> None: self.assertEqual(1, self.admin.count('id="companyLedgers"')) self.assertEqual(1, self.admin.count('id="balanceLedgers"')) self.assertIn('data-view="pair"', self.admin) self.assertRegex(self.admin, r'data-view="pair"[^>]*>[\s\S]*?往来查询') self.assertIn("

往来查询

", self.admin) self.assertIn("转为异常后,该记录暂不纳入余额计算", self.admin) self.assertIn('id="auditExceptionNote"', self.admin) def test_company_balance_groups_and_nav(self) -> None: self.assertIn('id="companyBalanceGroups"', self.company) self.assertNotIn('id="companyBalanceLine"', self.company) self.assertRegex(self.company, r'data-view="balances"[^>]*>[\s\S]*?往来余额') self.assertIn("

往来余额

", self.company) def test_css_directory_and_drawer_breakpoints(self) -> None: self.assertIn("@media (max-width: 768px)", self.css) self.assertIn("@media (max-width: 375px)", self.css) self.assertIn("@media (max-width: 1179px)", self.css) self.assertIn("@media (max-width: 767px)", self.css) self.assertIn(".drawer {", self.css) self.assertIn("width: 640px", self.css) self.assertIn(".drawer { width: 480px; }", self.css) self.assertIn(".drawer { width: 100%; }", self.css) self.assertIn(".drawer .pair-balance-line.is-six", self.css) self.assertIn("repeat(3, 1fr)", self.css) self.assertIn(".drawer .event-table { min-width: 860px; }", self.css) self.assertIn(".company-row.is-balance-counterparty", self.css) self.assertIn(".ledger-hide-md", self.css) def test_js_selectors_and_event_table(self) -> None: self.assertIn('loadAdminBalances($("#balanceLedgers"))', self.js) self.assertNotIn('loadAdminBalances($("#companyLedgers"))', self.js) self.assertIn("交易日期", self.js) self.assertIn("本方账户", self.js) self.assertIn("对方账户", self.js) self.assertIn("摘要", self.js) self.assertIn("匹配状态", self.js) self.assertIn("function eventTableHead()", self.js) self.assertIn("colspan=\"8\"", self.js) self.assertIn("function cycleTab(", self.js) self.assertIn("function drawerEscAction(", self.js) self.assertIn("function eventIsNegative(", self.js) self.assertIn("fmtAbsMoney", self.js) self.assertIn("is-balance-counterparty", self.js) heads = re.search( r"function eventTableHead\(\) \{\s*return `([^`]+)`", self.js, ) self.assertIsNotNone(heads) markup = heads.group(1) self.assertNotIn("来源", markup) for label in ("交易日期", "方向", "科目", "本方账户", "对方账户", "摘要", "匹配状态", "金额"): self.assertIn(label, markup) self.assertEqual(8, len(re.findall(r" None: result = subprocess.run( ["node", str(ROOT / "tests" / "b44_ui_check.js")], capture_output=True, text=True, cwd=str(ROOT), ) self.assertEqual(0, result.returncode, result.stdout + result.stderr) self.assertIn("b44_ui_check ok", result.stdout) if __name__ == "__main__": unittest.main()