Enforce root-owned adapter lifecycles
This commit is contained in:
+39
-13
@@ -14,10 +14,10 @@ fn runtime_exposes_debug_api_before_startup_side_effects() {
|
||||
.find("if (document.readyState === \"loading\") document.addEventListener(\"DOMContentLoaded\", start)")
|
||||
.expect("runtime starts after declaration");
|
||||
assert!(api < start);
|
||||
assert!(source.contains("try {\n bootstrapState(root);"));
|
||||
assert!(source.contains("emit(root, \"hemx:state-error\", String(error));"));
|
||||
assert!(source.contains("try {\n bindRoot(root);"));
|
||||
assert!(source.contains("emit(root, \"hemx:bind-error\", String(error));"));
|
||||
assert!(source.contains("roots().forEach(bindEnhancedRoot)"));
|
||||
assert!(source.contains("bindAdapter(root, \"events\", () => bindRoot(root))"));
|
||||
assert!(source.contains("bindAdapter(root, \"sse\", () => bindSse(root))"));
|
||||
assert!(source.contains("emit(root, `hemx:${name}-error`, String(error))"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -113,7 +113,7 @@ fn runtime_targets_generated_resources_not_response_selectors() {
|
||||
assert!(source.contains("function firstElement(scope, predicate)"));
|
||||
assert!(source.contains("function generatedResource(el, id)"));
|
||||
assert!(source.contains("return firstElement(scope, (el) => attrEquals(el, \"data-hemx-key\", key) && withinGeneratedResource(el, scope, id))"));
|
||||
assert!(source.contains("if (node.hasAttribute && node.hasAttribute(ROOT)) continue"));
|
||||
assert!(source.contains("node.hasAttribute(ROOT) || node.hasAttribute(ISLAND)"));
|
||||
assert!(source.contains("if (!applyOp(scope, op)) return"));
|
||||
assert!(!source.contains("canApplyOp"));
|
||||
assert!(source.contains("if (op.position === \"first\") target.prepend"));
|
||||
@@ -158,7 +158,7 @@ fn runtime_supports_revealed_scheduling() {
|
||||
assert!(source.contains("window.addEventListener(\"pageshow\", restoreRevealed)"));
|
||||
assert!(source.contains("revealed.delete(el)"));
|
||||
assert!(source.contains("record.addedNodes.forEach((node) =>"));
|
||||
assert!(source.contains("descendantRoots(node).forEach(bindRoot)"));
|
||||
assert!(source.contains("descendantRoots(node).forEach(bindEnhancedRoot)"));
|
||||
assert!(source.contains("const owner = rootOf(node.parentElement)"));
|
||||
assert!(source.contains("bindPolling(owner)"));
|
||||
assert!(source.contains("bindRevealed(owner)"));
|
||||
@@ -360,15 +360,13 @@ fn runtime_refuses_partial_updates_on_fingerprint_mismatch() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_malformed_bootstrap_state_reports_and_continues() {
|
||||
fn runtime_has_no_mirrored_client_application_store() {
|
||||
let source = hemx_js::RUNTIME_JS;
|
||||
|
||||
assert!(source.contains("function bootstrapState(root)"));
|
||||
assert!(source.contains("try {\n const store = atomStore(root);"));
|
||||
assert!(source.contains("atomStores.delete(root)"));
|
||||
assert!(source.contains("emit(root, \"hemx:state-error\", String(error))"));
|
||||
assert!(source.contains("bindRoot(root)"));
|
||||
assert!(source.contains("bindSse(root)"));
|
||||
assert!(!source.contains("atomStore"));
|
||||
assert!(!source.contains("bootstrapState"));
|
||||
assert!(!source.contains("data-hemx-st"));
|
||||
assert!(!source.contains("decodeAtomState"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -405,6 +403,34 @@ fn runtime_applies_binary_websocket_effect_batches_inside_roots() {
|
||||
assert!(source.contains("if (socket) socket.close()"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_binds_adapters_once_and_cleans_removed_fragments() {
|
||||
let source = hemx_js::RUNTIME_JS;
|
||||
|
||||
assert!(source.contains("const boundRoots = new WeakSet()"));
|
||||
assert!(source.contains("if (boundRoots.has(root)) return;"));
|
||||
assert!(source.contains("if (rootOf(event.target) !== root) return;"));
|
||||
assert!(source.contains("if (rootOf(el) !== root) return;"));
|
||||
assert!(source.contains("descendantRoots(node).forEach(bindEnhancedRoot)"));
|
||||
assert!(source.contains("function bindAdapter(root, name, bind)"));
|
||||
assert!(source.contains("cleanupRemovedFragment(node)"));
|
||||
assert!(source.contains("source.close()"));
|
||||
assert!(source.contains("socket.close()"));
|
||||
assert!(source.contains("observer.disconnect()"));
|
||||
assert!(source.contains("stopDescendantPolling(node)"));
|
||||
assert!(source.contains("boundRoots.delete(root)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_preserves_explicit_island_subtrees() {
|
||||
let source = hemx_js::RUNTIME_JS;
|
||||
|
||||
assert!(source.contains("const ISLAND = \"data-hemx-island\""));
|
||||
assert!(source.contains("node.hasAttribute(ROOT) || node.hasAttribute(ISLAND)"));
|
||||
assert!(source.contains("preserveIslands(target, nodes)"));
|
||||
assert!(source.contains("island.replaceWith(preserved)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_page_swaps_lowered_slot_ids() {
|
||||
let source = hemx_js::RUNTIME_JS;
|
||||
|
||||
Reference in New Issue
Block a user