UX-15: mutations fail named checks, not crashes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(HERE, "tools"))
|
||||
logging.disable(logging.WARNING) # the validator's own log lines
|
||||
|
||||
from aiohttp import ClientSession, web as aioweb # noqa: E402
|
||||
from aiohttp import ClientSession, ContentTypeError, web as aioweb # noqa: E402
|
||||
|
||||
import translations_lint as TL # noqa: E402
|
||||
import ux13_demo as D # noqa: E402
|
||||
@@ -264,7 +264,10 @@ async def _get(s, url):
|
||||
|
||||
async def _post(s, url, body):
|
||||
async with s.post(url, json=body) as r:
|
||||
return r.status, await r.json()
|
||||
try:
|
||||
return r.status, await r.json()
|
||||
except (ValueError, ContentTypeError): # e.g. a plain-text 500
|
||||
return r.status, {}
|
||||
|
||||
|
||||
STATES = [state("sensor.grid", "402"), state("number.inv1_power", "0"),
|
||||
@@ -790,18 +793,18 @@ async def _f1(s, root, sup):
|
||||
|
||||
_r, _sup = asyncio.run(session(Controller(SITE, STATES, Store(), grid=402.0),
|
||||
SITE, _f1))
|
||||
print(f" empty day price: steps {_r['price']['steps']}")
|
||||
print(f" empty day price: steps {_r['price'].get('steps')}")
|
||||
check("F1: a price the page cannot turn into options blocks step 4, beside "
|
||||
"its own field",
|
||||
_r["price"]["steps"]["4"] >= 1
|
||||
_r["price"].get("steps", {}).get("4", 0) >= 1
|
||||
and {"field": "ui.day_price", "card": None, "tier": "bad",
|
||||
"text": WS_D["no_price"]["description"]} in _r["price"]["messages"])
|
||||
"text": WS_D["no_price"]["description"]} in _r["price"].get("messages", []))
|
||||
check("F1: ...and the last step's live checks still run on the rest",
|
||||
[x["tier"] for x in _r["price"].get("setup", [])
|
||||
if "number.inv1_power" in x["text"]] == ["ok"]
|
||||
and any("402 W" in x["text"] for x in _r["price"]["setup"]))
|
||||
check("F1: no inverter card blocks step 2, not the last step alone",
|
||||
_r["none"]["steps"]["2"] >= 1)
|
||||
_r["none"].get("steps", {}).get("2", 0) >= 1)
|
||||
check("F1: the save refuses it (422) and says which step to go back to",
|
||||
_r["save"][0] == 422 and _r["save"][1]["steps"]["4"] >= 1
|
||||
and _sup.writes == [])
|
||||
|
||||
@@ -339,10 +339,14 @@ class Session:
|
||||
|
||||
|
||||
def _refused(coro):
|
||||
"""True only for the read-only refusal; a request that reached the
|
||||
session (AssertionError there) or no refusal at all is False."""
|
||||
try:
|
||||
asyncio.run(coro)
|
||||
except H.ReadOnly:
|
||||
return True
|
||||
except Exception: # noqa: BLE001
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
@@ -372,8 +376,10 @@ check("control: a normal HomeAssistant does send the write", _sent
|
||||
try:
|
||||
M.Controller(dict(_ok), _ro, None, None, stop=asyncio.Event())
|
||||
_built = True
|
||||
except ValueError:
|
||||
_built = False
|
||||
except ValueError as err:
|
||||
_built = "read-only" not in str(err)
|
||||
except Exception: # noqa: BLE001
|
||||
_built = True # it got past the check and failed on something else
|
||||
check("no controller can be built on a read-only HomeAssistant", not _built)
|
||||
try:
|
||||
setuponly.SetupOnly(SHIPPED, _rw, None)
|
||||
|
||||
Reference in New Issue
Block a user