Add sub-component support via self-referential device hierarchy
This commit is contained in:
@@ -885,3 +885,99 @@ def test_device_charge_all_no_installed(seeded_client):
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert b"No installed batteries" in resp.data
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Sub-components (self-referential device hierarchy)
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def _setup_rc_car(client):
|
||||
"""Create RC Car Set with Remote and Car sub-components and 6 AA batteries."""
|
||||
client.post("/device/add", data={"name": "RC Car Set", "battery_slots": "6", "battery_size": "AA"})
|
||||
# id=1 above; add sub-components with parent_id=1
|
||||
client.post("/device/add", data={"name": "Remote", "battery_slots": "2",
|
||||
"battery_size": "AA", "parent_id": "1"})
|
||||
client.post("/device/add", data={"name": "Car", "battery_slots": "4",
|
||||
"battery_size": "AA", "parent_id": "1"})
|
||||
for i in range(1, 7):
|
||||
client.post("/battery/add", data={"brand": "Eneloop", "label": f"E{i:03d}", "size": "AA"})
|
||||
|
||||
|
||||
def test_add_subcomponent(client):
|
||||
_setup_rc_car(client)
|
||||
# Parent detail shows sub-components
|
||||
resp = client.get("/device/1")
|
||||
assert resp.status_code == 200
|
||||
assert b"Remote" in resp.data
|
||||
assert b"Car" in resp.data
|
||||
# Child detail shows breadcrumb back to parent
|
||||
resp = client.get("/device/2")
|
||||
assert resp.status_code == 200
|
||||
assert b"RC Car Set" in resp.data
|
||||
assert b"Remote" in resp.data
|
||||
|
||||
|
||||
def test_subcomponent_prevents_deep_nesting(client):
|
||||
_setup_rc_car(client)
|
||||
# id=2 is "Remote", which already has parent_id=1
|
||||
resp = client.post("/device/add", data={"name": "Button", "battery_slots": "1",
|
||||
"battery_size": "AA", "parent_id": "2"})
|
||||
assert resp.status_code == 400
|
||||
assert b"one level" in resp.data.lower() or b"nest" in resp.data.lower()
|
||||
|
||||
|
||||
def test_subcomponent_install_batteries(client):
|
||||
_setup_rc_car(client)
|
||||
# Install 2 batteries into Remote (device id=2)
|
||||
resp = client.post("/device/2/install-one", data={"battery_id": "1"}, follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
resp = client.post("/device/2/install-one", data={"battery_id": "2"}, follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
# Remote is now full (2/2); a third battery should be blocked
|
||||
resp = client.post("/device/2/install-one", data={"battery_id": "3"}, follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
assert b"full" in resp.data.lower()
|
||||
|
||||
|
||||
def test_dashboard_shows_parent_slash_child(client):
|
||||
_setup_rc_car(client)
|
||||
client.post("/device/2/install-one", data={"battery_id": "1"})
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
assert b"RC Car Set" in resp.data
|
||||
assert b"Remote" in resp.data
|
||||
|
||||
|
||||
def test_delete_parent_promotes_children(client):
|
||||
_setup_rc_car(client)
|
||||
client.post("/device/1/delete", follow_redirects=True)
|
||||
# Child devices still exist
|
||||
resp = client.get("/device/2")
|
||||
assert resp.status_code == 200
|
||||
resp = client.get("/device/3")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
def test_device_without_parent_unchanged(client):
|
||||
client.post("/device/add", data={"name": "Torch", "battery_slots": "2", "battery_size": "AA"})
|
||||
client.post("/battery/add", data={"brand": "Eneloop", "count": "1"})
|
||||
resp = client.post("/device/1/install-one", data={"battery_id": "1"}, follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
assert b"1 / 2" in resp.data
|
||||
|
||||
|
||||
def test_subcomponent_ha_entity_id(client):
|
||||
client.post("/device/add", data={"name": "Hub", "battery_slots": "1", "battery_size": "AA"})
|
||||
resp = client.post(
|
||||
"/device/add",
|
||||
data={"name": "Sensor A", "battery_slots": "1", "battery_size": "AA",
|
||||
"parent_id": "1", "ha_entity_id": "sensor.sensor_a_battery"},
|
||||
follow_redirects=True,
|
||||
)
|
||||
# Redirects to parent detail on success
|
||||
assert resp.status_code == 200
|
||||
assert b"Sensor A" in resp.data
|
||||
# Child detail shows parent breadcrumb
|
||||
resp = client.get("/device/2")
|
||||
assert resp.status_code == 200
|
||||
assert b"Hub" in resp.data
|
||||
|
||||
Reference in New Issue
Block a user