feat(n7web): add pet settings and day night themes
This commit is contained in:
@@ -807,7 +807,7 @@ operations:
|
||||
def test_static_console_and_runtime_endpoint(self) -> None:
|
||||
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
|
||||
html = response.read().decode("utf-8")
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-136", timeout=3) as response:
|
||||
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-139", timeout=3) as response:
|
||||
app_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/gesture-control.js?v=android-pad-9", timeout=3
|
||||
@@ -834,11 +834,11 @@ operations:
|
||||
) as response:
|
||||
speech_worklet = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/self-extension.js?v=pet-acrylic-48", timeout=3
|
||||
f"{self.base_url}/self-extension.js?v=pet-settings-49", timeout=3
|
||||
) as response:
|
||||
extension_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/self-extension.css?v=pet-acrylic-48", timeout=3
|
||||
f"{self.base_url}/self-extension.css?v=pet-settings-49", timeout=3
|
||||
) as response:
|
||||
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
|
||||
with self.opener.open(
|
||||
@@ -854,7 +854,7 @@ operations:
|
||||
) as response:
|
||||
energy_styles = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/codepen-glass-theme.css?v=creative-cloud-1", timeout=3
|
||||
f"{self.base_url}/codepen-glass-theme.css?v=creative-cloud-2", timeout=3
|
||||
) as response:
|
||||
glass_theme = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
@@ -887,7 +887,7 @@ operations:
|
||||
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
|
||||
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
|
||||
self.assertNotIn("透明车体 · 实体设备", html)
|
||||
self.assertIn('src="/app.js?v=dual-seat-136"', html)
|
||||
self.assertIn('src="/app.js?v=dual-seat-139"', html)
|
||||
self.assertIn('href="/styles.css?v=dual-seat-23"', html)
|
||||
self.assertIn('src="/gesture-control.js?v=android-pad-9"', html)
|
||||
self.assertNotIn('class="vehicle-system-hud"', html)
|
||||
@@ -900,8 +900,8 @@ operations:
|
||||
self.assertIn('<body class="console-v2">', html)
|
||||
self.assertIn('id="v2BootScreen"', html)
|
||||
self.assertIn('正在加载车机控制与实时状态', html)
|
||||
self.assertIn('src="/self-extension.js?v=pet-acrylic-48"', html)
|
||||
self.assertIn('href="/self-extension.css?v=pet-acrylic-48"', html)
|
||||
self.assertIn('src="/self-extension.js?v=pet-settings-49"', html)
|
||||
self.assertIn('href="/self-extension.css?v=pet-settings-49"', html)
|
||||
self.assertNotIn("self-calibration", html)
|
||||
self.assertNotIn("self-repair", html)
|
||||
self.assertNotIn("self-evolution", html)
|
||||
@@ -912,7 +912,7 @@ operations:
|
||||
self.assertIn('src="/assistant-chat.js?v=codex-assistant-32"', html)
|
||||
self.assertIn('href="/energy-monitor.css?v=energy-monitor-4"', html)
|
||||
self.assertIn('src="/energy-monitor.js?v=energy-monitor-4"', html)
|
||||
self.assertIn('href="/codepen-glass-theme.css?v=creative-cloud-1"', html)
|
||||
self.assertIn('href="/codepen-glass-theme.css?v=creative-cloud-2"', html)
|
||||
self.assertIn("--glass-shell:", glass_theme)
|
||||
self.assertIn("backdrop-filter: blur(22px) saturate(1.25)", glass_theme)
|
||||
self.assertNotIn('"admin"', console_script)
|
||||
@@ -1194,14 +1194,14 @@ operations:
|
||||
self.assertIn("CAN 指令已提交,等待车辆状态确认", console_script)
|
||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v298"', service_worker)
|
||||
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v302"', service_worker)
|
||||
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
||||
self.assertIn('/console-v2.js?v=local-first-70', service_worker)
|
||||
self.assertIn('/assistant-chat.css?v=codex-assistant-28', service_worker)
|
||||
self.assertIn('/assistant-chat.js?v=codex-assistant-32', service_worker)
|
||||
self.assertIn('/energy-monitor.css?v=energy-monitor-4', service_worker)
|
||||
self.assertIn('/energy-monitor.js?v=energy-monitor-4', service_worker)
|
||||
self.assertIn('"/app.js?v=dual-seat-136"', service_worker)
|
||||
self.assertIn('"/app.js?v=dual-seat-139"', service_worker)
|
||||
self.assertIn('"/speech-input.js?v=sensevoice-13"', service_worker)
|
||||
self.assertIn('"/speech-input.css?v=sensevoice-7"', service_worker)
|
||||
self.assertIn('"/speech-audio-worklet.js?v=sensevoice-5"', service_worker)
|
||||
@@ -1658,7 +1658,7 @@ operations:
|
||||
) as response:
|
||||
extension_script = response.read().decode("utf-8")
|
||||
with self.opener.open(
|
||||
f"{self.base_url}/app.js?v=dual-seat-136", timeout=3
|
||||
f"{self.base_url}/app.js?v=dual-seat-139", timeout=3
|
||||
) as response:
|
||||
app_script = response.read().decode("utf-8")
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ def test_console_contains_ai_assistant_surface():
|
||||
|
||||
def test_codex_assistant_assets_are_versioned_together_in_the_service_worker():
|
||||
service_worker = (ROOT / "apps/web-console/service-worker.js").read_text(encoding="utf-8")
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
|
||||
assert '"/assistant-chat.css?v=codex-assistant-28"' in service_worker
|
||||
assert '"/assistant-chat.js?v=codex-assistant-32"' in service_worker
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ def test_energy_monitor_assets_are_versioned_and_cached() -> None:
|
||||
assert html.index("/assistant-chat.js?v=codex-assistant-32") < html.index(
|
||||
"/energy-monitor.js?v=energy-monitor-4"
|
||||
)
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
|
||||
|
||||
|
||||
def test_energy_monitor_uses_the_fifth_shared_dock_icon_and_starts_closed() -> None:
|
||||
|
||||
@@ -42,20 +42,29 @@ def test_theme_asset_versions_are_consistent_with_the_pwa_shell() -> None:
|
||||
for asset in (
|
||||
"/styles.css?v=dual-seat-23",
|
||||
"/console-v2.css?v=delivery-state-69",
|
||||
"/self-extension.css?v=pet-acrylic-48",
|
||||
"/self-extension.css?v=pet-settings-49",
|
||||
"/speech-input.css?v=sensevoice-7",
|
||||
"/codepen-glass-theme.css?v=creative-cloud-1",
|
||||
"/codepen-glass-theme.css?v=creative-cloud-2",
|
||||
):
|
||||
assert asset in html
|
||||
assert f'"{asset}"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
|
||||
|
||||
|
||||
def test_reference_glass_theme_covers_the_complete_workspace() -> None:
|
||||
html = source("index.html")
|
||||
theme = source("codepen-glass-theme.css")
|
||||
app = source("app.js")
|
||||
|
||||
assert '<meta name="theme-color" content="#17182b" />' in html
|
||||
assert '<meta name="theme-color" content="#17182b" id="themeColorMeta" />' in html
|
||||
assert 'const key = "cognitive-agent.glass-theme"' in html
|
||||
assert 'id="glassThemeToggle"' in html
|
||||
assert 'data-theme-icon="sun"' in html
|
||||
assert 'data-theme-icon="moon"' in html
|
||||
assert 'const GLASS_THEME_STORAGE_KEY = "cognitive-agent.glass-theme"' in app
|
||||
assert "localStorage.setItem(GLASS_THEME_STORAGE_KEY, normalized)" in app
|
||||
assert "document.cookie = `${GLASS_THEME_STORAGE_KEY}=${normalized}" in app
|
||||
assert 'new CustomEvent("cognitive-agent:theme-change"' in app
|
||||
for contract in (
|
||||
"--glass-shell:",
|
||||
"--glass-panel:",
|
||||
@@ -66,11 +75,20 @@ def test_reference_glass_theme_covers_the_complete_workspace() -> None:
|
||||
".joint-twin-shell > .twin-band",
|
||||
"#v2ExtensionPanel .v2-extension-sync-mount",
|
||||
".v2-pet-card",
|
||||
".v2-pet-presence-card",
|
||||
".v2-pet-settings-dialog",
|
||||
".mode-gallery",
|
||||
".v2-nfc-dialog",
|
||||
".energy-monitor-page",
|
||||
):
|
||||
assert contract in theme
|
||||
assert 'html[data-glass-theme="light"] body.console-v2' in theme
|
||||
assert ".glass-theme-toggle" in theme
|
||||
assert "width: 100vw !important" in theme
|
||||
assert "height: 100dvh !important" in theme
|
||||
assert "margin: 0 !important" in theme
|
||||
assert "border: 0 !important" in theme
|
||||
assert "border-radius: 0 !important" in theme
|
||||
|
||||
|
||||
def test_vehicle_twin_icons_and_nested_overlays_use_semantic_tokens() -> None:
|
||||
|
||||
@@ -47,14 +47,16 @@ class FrontendVehicleStateSyncContractTests(unittest.TestCase):
|
||||
self.extension_source,
|
||||
)
|
||||
|
||||
def test_shared_twin_theme_is_fixed_to_user(self) -> None:
|
||||
def test_shared_twin_theme_tracks_persistent_day_and_night_mode(self) -> None:
|
||||
self.assertIn("function applyTwinSceneTheme(", self.app_source)
|
||||
self.assertIn('canvas.dataset.themeRole = "user"', self.app_source)
|
||||
self.assertIn("function currentTwinThemeRole()", self.app_source)
|
||||
self.assertIn("function currentTwinThemePalette()", self.app_source)
|
||||
self.assertIn("canvas.dataset.themeRole = role", self.app_source)
|
||||
self.assertIn(
|
||||
'canvas.dataset.themeAccent = `#${palette.accent.toString(16).padStart(6, "0")}`',
|
||||
self.app_source,
|
||||
)
|
||||
for glass_theme_token in (
|
||||
for night_theme_token in (
|
||||
"accent: 0x7b70f5",
|
||||
"sceneBackground: 0x111426",
|
||||
"floor: 0x1a2038",
|
||||
@@ -64,7 +66,20 @@ class FrontendVehicleStateSyncContractTests(unittest.TestCase):
|
||||
"glass: 0x4d8ed2",
|
||||
"lamp: 0x4385cf",
|
||||
):
|
||||
self.assertIn(glass_theme_token, self.app_source)
|
||||
self.assertIn(night_theme_token, self.app_source)
|
||||
for day_theme_token in (
|
||||
"accent: 0x2f80ed",
|
||||
"sceneBackground: 0xeff6ff",
|
||||
"floor: 0xe5f0fd",
|
||||
"vehicleBody: 0x91c6f5",
|
||||
"vehicleOutline: 0x2879d8",
|
||||
"seatShell: 0x2b76c9",
|
||||
"glass: 0x4b9bea",
|
||||
"lamp: 0x2e7fd4",
|
||||
):
|
||||
self.assertIn(day_theme_token, self.app_source)
|
||||
self.assertIn('"cognitive-agent:theme-change"', self.app_source)
|
||||
self.assertIn("applyTwinReferenceVehicleTheme(twin.referenceVehicle, palette)", self.app_source)
|
||||
self.assertNotIn("accent: 0x0e7773", self.app_source)
|
||||
self.assertNotIn("cognitive-agent:demo-role-change", self.app_source)
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ def test_unified_console_exposes_device_id_based_nfc_authorization() -> None:
|
||||
assert '.v2-nfc-command-list' in styles
|
||||
assert '.v2-nfc-command-option' in styles
|
||||
assert '.v2-nfc-select-all' in styles
|
||||
assert 'self-extension.js?v=pet-acrylic-48' in html
|
||||
assert 'self-extension.css?v=pet-acrylic-48' in html
|
||||
assert 'self-extension.js?v=pet-settings-49' in html
|
||||
assert 'self-extension.css?v=pet-settings-49' in html
|
||||
|
||||
|
||||
def test_unified_console_exposes_gscu_tcp_configuration_and_actions() -> None:
|
||||
@@ -134,7 +134,7 @@ def test_server_exposes_nfc_snapshot_through_same_origin_extension_api() -> None
|
||||
assert "frame-src 'self' http://*:3001" in server
|
||||
|
||||
|
||||
def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> None:
|
||||
def test_pet_settings_dialog_edits_durable_cards_and_homepage_only_shows_detected_pet() -> None:
|
||||
script = source("self-extension.js")
|
||||
styles = source("self-extension.css")
|
||||
service = (ROOT / "src" / "cognitive_agent" / "application" / "pet_cards.py").read_text(
|
||||
@@ -145,6 +145,16 @@ def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> N
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
assert 'class="v2-pet-card-region"' in script
|
||||
assert 'id="extensionPetSettingsDialog"' in script
|
||||
assert 'data-open-pet-settings' in script
|
||||
assert 'function renderPetCardEditor()' in script
|
||||
assert 'function renderPetSettingsDialog()' in script
|
||||
assert 'function bindPetSettingsDialogEvents()' in script
|
||||
assert 'function renderDetectedPetCard(card)' in script
|
||||
assert 'mount.dataset.hasPets = String(Boolean(nfcPet))' in script
|
||||
assert '${nfcPet ? renderDetectedPetCard(nfcPet) : ""}' in script
|
||||
assert '${renderPetCardRegion()}' not in script
|
||||
assert 'function renderPetCardRegion()' not in script
|
||||
assert 'data-pet-field="pet_name"' in script
|
||||
assert 'data-pet-field="action"' in script
|
||||
assert '<output>${card.nfc_id ?' in script
|
||||
@@ -165,6 +175,9 @@ def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> N
|
||||
assert 'if (nextRevision < petCardSnapshot.revision) return false' in script
|
||||
assert '.v2-pet-card-region' in styles
|
||||
assert '.v2-pet-card-list' in styles
|
||||
assert '.v2-pet-settings-dialog' in styles
|
||||
assert '.v2-pet-settings-body' in styles
|
||||
assert '.v2-pet-presence-card' in styles
|
||||
assert '.v2-nfc-pet-binding' in styles
|
||||
assert 'grid-template-columns: minmax(0, 1fr);' in styles
|
||||
assert 'scrollbar-gutter: stable' in styles
|
||||
|
||||
@@ -18,14 +18,14 @@ def test_vue_presentation_assets_are_local_ordered_and_cached() -> None:
|
||||
presentation = "/vue-ui.js?v=vue-presentation-3"
|
||||
|
||||
assert html.index(runtime) < html.index(presentation) < html.index(
|
||||
"/app.js?v=dual-seat-136"
|
||||
"/app.js?v=dual-seat-139"
|
||||
)
|
||||
assert html.index(presentation) < html.index(
|
||||
"/assistant-chat.js?v=codex-assistant-32"
|
||||
)
|
||||
assert f'"{runtime}"' in service_worker
|
||||
assert f'"{presentation}"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v298"' in service_worker
|
||||
assert 'const CACHE_VERSION = "cognitive-agent-pad-v302"' in service_worker
|
||||
assert "unpkg.com" not in html
|
||||
assert "cdn.jsdelivr.net" not in html
|
||||
|
||||
|
||||
Reference in New Issue
Block a user