142 lines
4.6 KiB
Python
142 lines
4.6 KiB
Python
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
WEB = ROOT / "apps" / "web-console"
|
|
|
|
|
|
def source(name: str) -> str:
|
|
return (WEB / name).read_text(encoding="utf-8")
|
|
|
|
|
|
def test_spatial_ui_contract_is_loaded_last_and_cached() -> None:
|
|
html = source("index.html")
|
|
service_worker = source("service-worker.js")
|
|
asset = "/ui-consistency.css?v=spatial-ui-5"
|
|
|
|
assert asset in html
|
|
assert f'"{asset}"' in service_worker
|
|
assert html.index("/energy-monitor.css") < html.index(asset)
|
|
|
|
|
|
def test_same_kind_surfaces_share_geometry_tokens() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
for token in (
|
|
"--ui-control-height-compact:",
|
|
"--ui-control-height:",
|
|
"--ui-font-card-title:",
|
|
"--ui-font-section-title:",
|
|
"--ui-font-panel-title:",
|
|
"--ui-inline-action-width:",
|
|
"--ui-radius-control:",
|
|
"--ui-radius-item:",
|
|
"--ui-radius-section:",
|
|
"--ui-radius-panel:",
|
|
"--ui-radius-modal:",
|
|
"--ui-shadow-item:",
|
|
"--ui-shadow-panel:",
|
|
"--ui-shadow-modal:",
|
|
):
|
|
assert token in styles
|
|
|
|
for selector in (
|
|
".v2-operation-shell",
|
|
".joint-twin-shell > .twin-band",
|
|
"#v2DevicePanel",
|
|
"#v2ExtensionPanel .v2-extension-sync-mount",
|
|
".mode-gallery",
|
|
".mode-editor",
|
|
".energy-monitor-page",
|
|
".v2-synced-device",
|
|
".v2-extension-gateway",
|
|
".mode-gallery-card",
|
|
".energy-kpi",
|
|
):
|
|
assert selector in styles
|
|
|
|
|
|
def test_same_kind_controls_share_sizes_and_focus_treatment() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
for selector in (
|
|
"#v2PanelControlDock > .v2-panel-control-button",
|
|
".v2-mode-rail .mode-rail-actions > button",
|
|
".v2-device-adjust-toggle",
|
|
".v2-pet-settings-launch",
|
|
".v2-extension-nfc-launch",
|
|
".energy-trend-tabs button",
|
|
".mode-gallery-close",
|
|
".mode-editor-header > button",
|
|
"#energyMonitorClose",
|
|
):
|
|
assert selector in styles
|
|
|
|
assert "box-shadow: var(--ui-focus-ring)" in styles
|
|
assert "outline: none" in styles
|
|
|
|
|
|
def test_panel_titles_and_extension_actions_share_type_and_size_tokens() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
for selector in (
|
|
".v2-operation-heading h2",
|
|
".joint-twin-shell .twin-heading h3",
|
|
".v2-device-sync-board > header h3",
|
|
".v2-extension-sync-heading h3",
|
|
".v2-device-card-focus strong",
|
|
".v2-nfc-inline strong",
|
|
".v2-extension-gateway strong",
|
|
):
|
|
assert selector in styles
|
|
|
|
assert "font-size: var(--ui-font-panel-title) !important" in styles
|
|
assert "font-size: var(--ui-font-card-title) !important" in styles
|
|
assert "grid-template-columns: repeat(2, minmax(0, 1fr))" in styles
|
|
assert "width: var(--ui-inline-action-width)" in styles
|
|
|
|
|
|
def test_pet_and_tcp_dialog_controls_keep_accessible_aligned_layout() -> None:
|
|
styles = source("self-extension.css")
|
|
extension = source("self-extension.js")
|
|
tcp_form = styles.split(".v2-gscu-config-form {", 1)[1].split("}", 1)[0]
|
|
tcp_submit = styles.split(
|
|
".v2-gscu-config-form > .v2-extension-primary {", 1
|
|
)[1].split("}", 1)[0]
|
|
|
|
assert ".v2-extension-dialog .v2-pet-card-region > header > button" in styles
|
|
assert "min-width: 104px" in styles
|
|
assert "align-items: end" in tcp_form
|
|
assert "height: 40px" in tcp_submit
|
|
assert "margin: 0" in tcp_submit
|
|
assert 'id="extensionGscuTcpHostHint"' in extension
|
|
assert 'id="extensionGscuTcpPortHint"' in extension
|
|
assert 'class="visually-hidden" id="extensionPetSettingsDescription"' in extension
|
|
|
|
|
|
def test_compact_sidebar_overrides_cannot_break_shared_geometry() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
assert ".v2-sync-execution-field," in styles
|
|
assert ".v2-can-command-panel" in styles
|
|
assert "border-radius: var(--ui-radius-item) !important" in styles
|
|
assert ".v2-sync-log {" in styles
|
|
assert "border-radius: var(--ui-radius-section) !important" in styles
|
|
|
|
|
|
def test_assistant_composer_hint_stays_inside_narrow_input() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
assert ".v2-request-form .composer-hint" in styles
|
|
assert "left: 16px !important" in styles
|
|
assert "right: auto !important" in styles
|
|
assert "max-width: calc(100% - 132px)" in styles
|
|
|
|
|
|
def test_failed_delivery_uses_one_semantic_status_treatment() -> None:
|
|
styles = source("ui-consistency.css")
|
|
|
|
assert '[data-delivery-state="blocked"]' in styles
|
|
assert '[data-delivery-state="failed"]' in styles
|
|
assert "color: var(--destructive)" in styles
|