fix(runtime): fail closed on hemx request errors

Preserve pending recovery while making failed HTTP responses non-applicable as effects. The runtime now restores aria-busy with pending state and emits inspectable hemx:error details with HTTP status for failed requests.

req: runtime/005

req: convention/007
This commit is contained in:
slhx agent
2026-06-22 22:22:26 +02:00
parent 1aa92d8d9d
commit f1aa232c94
4 changed files with 50 additions and 3 deletions
+18
View File
@@ -16,6 +16,19 @@ fn runtime_exposes_debug_api_before_startup_side_effects() {
assert!(source.contains("emit(root, \"hemx:bind-error\", String(error));"));
}
#[test]
fn runtime_reports_http_failures_without_applying_effects() {
// req: runtime/005
let source = hemx_js::RUNTIME_JS;
assert!(source.contains("function httpError(response)"));
assert!(source.contains("if (!response.ok) throw httpError(response)"));
assert!(source.contains("error.status = response.status"));
assert!(source.contains(
"emit(rootOf(target), \"hemx:error\", { message: String(error), status: error.status || null })"
));
}
#[test]
fn runtime_posts_urlencoded_forms_by_default() {
let source = hemx_js::RUNTIME_JS;
@@ -110,6 +123,11 @@ fn runtime_toggles_pending_conventions_around_requests() {
assert!(source.contains("hadClass: el.classList.contains(klass)"));
assert!(source.contains("if (state.hadClass) el.classList.add(state.className)"));
assert!(source.contains("const indicatorStates = new WeakMap()"));
assert!(source.contains("const busyStates = new WeakMap()"));
assert!(source.contains("function toggleBusy(el, on)"));
assert!(source.contains("el.setAttribute(\"aria-busy\", \"true\")"));
assert!(source.contains("el.removeAttribute(\"aria-busy\")"));
assert!(source.contains("toggleBusy(el, on)"));
assert!(source.contains("function toggleIndicator(indicator, on)"));
assert!(source.contains("toggleIndicator(i, on)"));
assert!(source.contains("indicator.hidden = state.hidden"));