feat(techdemo): add opaque island bridge

Add a canvas leaf-widget island to the techdemo that receives server snapshots through Effect::event/CustomEvent while keeping slhx core and runtime semantics unchanged.

req: interop/001

req: examples/001

req: examples/005
This commit is contained in:
slhx agent
2026-05-26 07:29:51 +02:00
parent 28ee1b5111
commit 9d3f70e9fe
10 changed files with 179 additions and 7 deletions
+2
View File
@@ -50,6 +50,7 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
assert_text(&driver, "A Linear-class work system without a frontend framework").await?;
assert_text(&driver, "Compile checked handles").await?;
assert_text(&driver, "No selectors. Generated resources address every target.").await?;
assert_text(&driver, "Opaque island bridge").await?;
wait_for_runtime(&driver).await?;
driver
@@ -58,6 +59,7 @@ async fn browser_drives_typed_product_end_to_end() -> WebDriverResult<()> {
.click()
.await?;
wait_for_text(&driver, &slot_selector(ui::control_center::slots::notice), "Push simulated").await?;
wait_for_text(&driver, "[data-island-readout]", "activity rows").await?;
driver.find(By::Css("button.primary-action")).await?.click().await?;
wait_for_text(&driver, ".work-card[data-key='4']", "Ship typed effects").await?;
+23 -1
View File
@@ -55,13 +55,23 @@ fn product_is_e2e_working_over_http() {
assert_selector_count_at_least(&document, "[data-hid]", 8);
assert_selector_count_at_least(&document, "[data-sid]", 7);
assert_selector_count_at_least(&document, ".work-card", 3);
assert_selector_count_at_least(&document, "[data-slhx-island=orbit]", 1);
assert_text(&document, "Opaque island bridge");
assert!(home.text().contains("data-island-snapshot="));
assert!(home.text().contains("data-slhx-sse=\"/events\""));
assert!(home.text().contains("/island.js"));
let runtime = get("/slhx.js");
assert_eq!(runtime.status, 200);
assert!(runtime.header("content-type").contains("javascript"));
assert!(runtime.text().contains("const HID = \"data-hid\""));
let island = get("/island.js");
assert_eq!(island.status, 200);
assert!(island.header("content-type").contains("javascript"));
assert!(island.text().contains("slhx:island-orbit"));
assert!(island.text().contains("data-slhx-island"));
let architecture = request("GET", "/architecture", &[("X-SLHX-Partial", "1")], "");
assert_eq!(architecture.status, 200);
assert!(architecture.header("x-slhx-partial").contains("true"));
@@ -76,7 +86,8 @@ fn product_is_e2e_working_over_http() {
assert_card(&launch_batch, "Design hero moment", "Product", "Draft", "width:99%");
assert_payload_contains(&launch_batch, "Launch accepted");
assert_payload_contains(&launch_batch, "Launched card #4");
assert!(launch_batch.ops.len() >= 5, "launch should update multiple generated targets");
assert_emit(&launch_batch, "slhx:island-orbit", "activity rows");
assert!(launch_batch.ops.len() >= 6, "launch should update generated targets and notify the island");
let default_impact = post("/", "__h=539242093&title=Default+impact&lane=compiler");
assert_effect_response(&default_impact);
@@ -139,6 +150,7 @@ fn product_is_e2e_working_over_http() {
assert_payload_contains(&push_batch, "SSE tick");
assert_payload_contains(&push_batch, "Push simulated · no client app code");
assert_payload_contains(&push_batch, "Simulated push event produced the same EffectBatch shape");
assert_emit(&push_batch, "slhx:island-orbit", "activity rows");
let delete_missing = post("/", "__h=165211725&work_id=999");
assert_effect_response(&delete_missing);
@@ -191,6 +203,16 @@ fn assert_payload_contains(batch: &EffectBatch, needle: &str) {
);
}
fn assert_emit(batch: &EffectBatch, name: &str, needle: &str) {
assert!(
batch.ops.iter().any(|op| match op {
Effect::Emit { name: actual, payload } => actual == name && payload.contains(needle),
_ => false,
}),
"missing emit {name:?} containing {needle:?} in {batch:#?}"
);
}
fn assert_card(batch: &EffectBatch, title: &str, lane: &str, stage: &str, impact_style: &str) {
let board = board_html(batch);
let document = Html::parse_fragment(&board);