from __future__ import annotations 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_unified_console_exposes_device_id_based_nfc_authorization() -> None: script = source("self-extension.js") styles = source("self-extension.css") html = source("index.html") assert 'data-open-nfc-binding' in script assert '靠近读卡器后' in script assert '

NFC 设备授权

' in script assert 'NFC 设备授权' in script assert 'api("nfc/status")' in script assert 'function bindCardToDevice(device, cardUid)' in script assert 'function infraredDeviceGroups()' in script assert 'function configuredCapabilities(deviceId = null)' in script assert 'data-nfc-device-select' in script assert 'data-nfc-capability-enabled' in script assert 'data-nfc-select-all' in script assert '全部命令已默认选中' in script assert 'function createToyFromNfc()' not in script assert 'data-nfc-learn-capability' not in script assert 'data-nfc-relearn-capability' not in script assert 'data-nfc-continue-learning' not in script assert 'function importLegacyProfiles(value)' in script assert 'N7WEB_REQUEST_IR_TOY_PROFILES' in script assert 'IR_TOY_LEGACY_PROFILES' in script assert 'value.legacy_profiles' in script assert 'value.legacy_bridge_addresses' in script assert 'device.cardUid = normalizedUid' in script assert 'const targetSlot = relearning ? Number(capability.slot) : allocateSlot()' in script assert 'sendGatewayCommand("read", { slot: learning.draft.slot })' in script assert 'function infraredSignalFromResponse(value)' in script assert 'function infraredFingerprint(signal)' in script assert '学习指令已下发,但物理槽位回读为空' in script assert 'signalSource: "n7web"' in script assert 'if (capability.signalSource === "n7web") return' in script assert 'const activeCatalog = sensedCardUid' in script assert 'normalizeCardUid(item.card_uid) === sensedCardUid' in script assert '&& item.status === "learned"' in script assert 'slot: capability.slot' in script assert 'device_aliases: device?.aliases || []' in script assert 'async function hydratePeripheralCatalog()' in script assert 'api("peripherals")' in script assert 'signalSource: "backend_catalog"' in script assert '当前未感应到外设' in script assert '将已绑定设备 ID 的 NFC 卡靠近读卡器后显示命令' in script assert '.v2-nfc-inline' in styles assert '.v2-nfc-dialog' in styles 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 def test_unified_console_exposes_gscu_tcp_configuration_and_actions() -> None: script = source("self-extension.js") styles = source("self-extension.css") assert 'id="extensionGscuTcpHost"' in script assert 'id="extensionGscuTcpPort"' in script assert 'id="extensionGscuDeviceId"' in script assert 'id="extensionGscuObjectNames"' in script assert 'id="extensionGscuActionNames"' in script assert 'id="extensionGscuTcpResultDetails"' in script assert 'id="extensionGscuNamedCommands"' in script assert 'data-open-gscu-tcp' in script assert 'api("gscu/config"' in script assert 'api("gscu/slots")' in script assert 'method: "PUT"' in script assert 'method: "DELETE"' in script assert '"gscu/erase-all"' in script assert 'verification: "slot_readback"' in script assert "学习指令已下发,但槽位回读失败" in script assert "确认擦除 GSCU1B 中的全部红外码吗" in script assert "GSCU1B 设备中的该红外码不会被擦除" in script assert "async function upsertNamedInfraredCommand(" in script assert "device_id: normalizedDeviceId" in script assert "object_names: normalizedObjects" in script assert "action_names: normalizedActions" in script assert "object_names: objectNames" in script assert "action_names: actionNames" in script assert "button.disabled = true;" in script assert "buttons.forEach((item) => { item.disabled = true; });" not in script for action in ( "info", "learn", "cancel", "emit", "read", "write", "restart", "wifi-lock", "erase", "reset", "raw", ): assert f'data-gscu-action="{action}"' in script assert ".v2-gscu-tcp-dialog" in styles assert ".v2-gscu-config-form" in styles assert "#extensionGscuTcpResult" in styles assert "#extensionGscuNamedCommands" in styles assert ".v2-gscu-device-group" in styles assert ".v2-gscu-device-command-grid" in styles assert ".v2-gscu-result" in styles assert "max-height: min(42vh, 360px)" in styles def test_server_exposes_nfc_snapshot_through_same_origin_extension_api() -> None: server = (ROOT / "src" / "cognitive_agent" / "server.py").read_text(encoding="utf-8") assert 'nfc = NfcReaderService()' in server assert 'pets = PetCardService(' in server assert 'path == "/api/extension/nfc/status"' in server assert 'path == "/api/extension/pets"' in server assert '"pet_cards": self.pets.snapshot()' in server assert 'path == "/api/extension/peripherals"' in server assert '"nfc": self.nfc.snapshot()' in server assert 'SeatDemoHandler.nfc.start()' in server assert 'SeatDemoHandler.pets.start()' in server assert 'SeatDemoHandler.pets.close()' in server assert 'SeatDemoHandler.nfc.close()' in server assert "frame-src 'self' http://*:3001" in server def test_homepage_exposes_durable_editable_pet_cards_and_nfc_only_binding() -> None: script = source("self-extension.js") styles = source("self-extension.css") service = (ROOT / "src" / "cognitive_agent" / "application" / "pet_cards.py").read_text( encoding="utf-8" ) mqtt = ( ROOT / "src" / "cognitive_agent" / "infrastructure" / "can" / "mqtt_transport.py" ).read_text(encoding="utf-8") assert 'class="v2-pet-card-region"' in script assert 'data-pet-field="pet_name"' in script assert 'data-pet-field="action"' in script assert '${card.nfc_id ?' in script assert 'data-pet-open-nfc' not in script assert 'data-nfc-pet-select' in script assert 'data-nfc-bind-pet' in script assert 'bind-current-nfc' in script assert 'api(`pets/${encodeURIComponent(cardId)}`' in script assert 'burst_count' in script assert 'burst_window_ms' in script assert 'label: "已发送 3 帧"' in script assert 'MQTT PET CARD' not in script assert 'data-pet-publish-note' not in script assert '宠物名 ' not in script assert '宠物动作 ' not in script assert '卡片 ID ' not in script assert 'n7/pet' in script 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-nfc-pet-binding' in styles assert 'grid-template-columns: minmax(0, 1fr);' in styles assert 'scrollbar-gutter: stable' in styles assert 'backdrop-filter: blur(18px) saturate(1.35)' in styles assert 'height: 58px' in styles assert 'class PetCardService' in service assert 'PET_MQTT_TOPIC = "n7/pet"' in service assert 'def bind_current_nfc' in service assert '"pet_name": str(card["pet_name"])' in service assert '"nfc_id": nfc_id' in service assert '"action": str(card["action"])' in service assert 'PET_BURST_COUNT = 3' in service assert 'PET_BURST_WINDOW_S = 1.0' in service assert '"burst_complete"' in service assert 'MQTT_PET_TOPIC = "n7/pet"' in mqtt assert 'def publish_pet_message' in mqtt def test_main_parsed_control_panel_renders_validated_infrared_operations() -> None: console = source("console-v2.js") styles = source("console-v2.css") html = source("index.html") assert 'capability === "infrared.emit"' in console assert 'channel: "IR"' in console assert 'frameLabel: "GSCU1B TCP"' in console assert "下发控制指令" in console assert "已解析控制指令" not in console assert 'li[data-can-channel="IR"]' in styles assert "console-v2.js?v=local-first-70" in html assert 'speech_semantic: "语音语义"' in console