Files
Cognitive_Agent/tests/unit/test_self_extension_nfc_sync_contract.py
T

105 lines
3.7 KiB
Python

from __future__ import annotations
from pathlib import Path
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
SOURCE_PATH = REPOSITORY_ROOT / "apps" / "web-console" / "self-extension.js"
def _function_source(source: str, signature: str, next_signature: str) -> str:
start = source.index(signature)
end = source.index(next_signature, start)
return source[start:end]
def test_nfc_binding_waits_for_durable_catalog_before_success() -> None:
source = SOURCE_PATH.read_text(encoding="utf-8")
bind = _function_source(
source,
" async function bindCurrentNfcToExisting() {",
"\n async function unbindCurrentNfc()",
)
persistence = bind.index("await bindCardToDevice(device, cardUid);")
success = bind.index("NFC 已关联设备 ID")
assert persistence < success
assert "NFC 设备授权保存失败" in bind
assert "void bindCardToDevice" not in bind
def test_peripheral_catalog_sync_is_serialized_and_tracks_backend_revision() -> None:
source = SOURCE_PATH.read_text(encoding="utf-8")
sync = _function_source(
source,
" async function syncPeripheralCatalog(",
"\n async function bindCardToDevice",
)
assert "peripheralCatalogSyncQueue" in sync
assert "const nextCatalog = peripheralCatalog();" in sync
assert "catalog_revision: peripheralCatalogRevision" in sync
assert "result.catalog_revision" in sync
assert "applyDurablePeripheralCatalog(" in sync
assert "if (throwOnError) throw error;" in sync
def test_backend_catalog_is_authoritative_for_persistent_device_cards() -> None:
source = SOURCE_PATH.read_text(encoding="utf-8")
hydrate = _function_source(
source,
" async function hydratePeripheralCatalog() {",
"\n function vehicleCatalog",
)
bootstrap = source[source.index(" void hydratePeripheralCatalog()") :]
assert "applyDurablePeripheralCatalog(" in hydrate
assert "if (!catalog.length)" in hydrate
assert "renderAll();" in hydrate
assert ".finally(() => syncPeripheralCatalog())" not in bootstrap
assert "return syncPeripheralCatalog();" in bootstrap
def test_bound_card_can_be_reassigned_to_a_new_device() -> None:
source = SOURCE_PATH.read_text(encoding="utf-8")
render = _function_source(
source,
" function renderNfcDialog(",
"\n function buildUnifiedNfcDialog",
)
bind = _function_source(
source,
" async function bindCurrentNfcToExisting() {",
"\n async function unbindCurrentNfc()",
)
assert "alternativeDeviceGroups" in render
assert "item.deviceId !== linkedDevice.id" in render
assert "state.devices.find((device) => device.id === item.deviceId)?.cardUid" in render
assert "data-nfc-bind-existing" in render
assert "将当前 NFC 改绑到新设备 ID" in render
assert "const previousDevice = linkedDeviceForCard(cardUid);" in bind
assert "NFC 已从设备 ID" in bind
assert "if (!capabilities.length)" in bind
def test_device_card_surfaces_extension_toy_mqtt_delivery() -> None:
source = SOURCE_PATH.read_text(encoding="utf-8")
apply_toy = _function_source(
source,
" function applyExtensionToySnapshot(",
"\n function applyNfcSnapshot",
)
apply_nfc = _function_source(
source,
" function applyNfcSnapshot(",
"\n async function refreshNfcStatus",
)
assert 'state === "burst_complete"' in apply_toy
assert 'state === "burst_failed"' in apply_toy
assert "burst_published_count" in apply_toy
assert "extensionToySnapshot.last_error" in apply_toy
assert "applyExtensionToySnapshot(value.extension_toy" in apply_nfc
assert "正在准备 extension/toy 消息" in apply_nfc