test(techdemo): build e2e posts from handles

Keep valid techdemo E2E interactions on generated Handle values plus the axum handle-field constant, leaving only the unknown-id negative case as raw wire input.

req: dx/003

req: examples/003
This commit is contained in:
slhx agent
2026-06-02 00:06:53 +02:00
parent cb64f8d30f
commit e9bc145b22
+68 -23
View File
@@ -1,5 +1,6 @@
use scraper::{Html, Selector}; use scraper::{Html, Selector};
use slhx::{Effect, EffectBatch, Payload, EFFECT_BATCH_ABI_VERSION}; use slhx::{Effect, EffectBatch, Handle, Payload, EFFECT_BATCH_ABI_VERSION};
use slhx_axum::SLHX_HANDLE_FIELD;
use slhx_techdemo::ui::BUILD_FINGERPRINT; use slhx_techdemo::ui::BUILD_FINGERPRINT;
use slhx_techdemo::ui::control_center::handles; use slhx_techdemo::ui::control_center::handles;
use slhx_techdemo::ui::issue_card::handles as card_handles; use slhx_techdemo::ui::issue_card::handles as card_handles;
@@ -11,6 +12,17 @@ use std::time::{Duration, Instant};
const ADDR: &str = "127.0.0.1:3002"; const ADDR: &str = "127.0.0.1:3002";
fn handle_body<I>(handle: Handle<I>, fields: &[(&str, &str)]) -> String {
let mut body = format!("{SLHX_HANDLE_FIELD}={handle}");
for (name, value) in fields {
body.push('&');
body.push_str(name);
body.push('=');
body.push_str(value);
}
body
}
struct Server { struct Server {
child: Child, child: Child,
} }
@@ -86,9 +98,13 @@ fn product_is_e2e_working_over_http() {
let launch = post( let launch = post(
"/", "/",
&format!( &handle_body(
"__h={}&title=Design+hero+moment&lane=product&impact=9", handles::launch_work,
handles::launch_work &[
("title", "Design+hero+moment"),
("lane", "product"),
("impact", "9"),
],
), ),
); );
assert_effect_response(&launch); assert_effect_response(&launch);
@@ -105,9 +121,9 @@ fn product_is_e2e_working_over_http() {
let default_impact = post( let default_impact = post(
"/", "/",
&format!( &handle_body(
"__h={}&title=Default+impact&lane=compiler", handles::launch_work,
handles::launch_work &[("title", "Default+impact"), ("lane", "compiler")],
), ),
); );
assert_effect_response(&default_impact); assert_effect_response(&default_impact);
@@ -117,9 +133,13 @@ fn product_is_e2e_working_over_http() {
let low_impact = post( let low_impact = post(
"/", "/",
&format!( &handle_body(
"__h={}&title=Low+impact&lane=runtime&impact=0", handles::launch_work,
handles::launch_work &[
("title", "Low+impact"),
("lane", "runtime"),
("impact", "0"),
],
), ),
); );
assert_effect_response(&low_impact); assert_effect_response(&low_impact);
@@ -128,9 +148,13 @@ fn product_is_e2e_working_over_http() {
let high_impact = post( let high_impact = post(
"/", "/",
&format!( &handle_body(
"__h={}&title=High+impact&lane=runtime&impact=99", handles::launch_work,
handles::launch_work &[
("title", "High+impact"),
("lane", "runtime"),
("impact", "99"),
],
), ),
); );
assert_effect_response(&high_impact); assert_effect_response(&high_impact);
@@ -139,7 +163,7 @@ fn product_is_e2e_working_over_http() {
let missing_title = post( let missing_title = post(
"/", "/",
&format!("__h={}&lane=runtime&impact=8", handles::launch_work), &handle_body(handles::launch_work, &[("lane", "runtime"), ("impact", "8")]),
); );
assert_effect_response(&missing_title); assert_effect_response(&missing_title);
let missing_title_batch = missing_title.batch(); let missing_title_batch = missing_title.batch();
@@ -149,37 +173,52 @@ fn product_is_e2e_working_over_http() {
let move_to_lane = post( let move_to_lane = post(
"/", "/",
&format!("__h={}&work_id=4&lane=runtime", lane_handles::move_to_lane), &handle_body(
lane_handles::move_to_lane,
&[("work_id", "4"), ("lane", "runtime")],
),
); );
assert_effect_response(&move_to_lane); assert_effect_response(&move_to_lane);
let move_to_lane_batch = move_to_lane.batch(); let move_to_lane_batch = move_to_lane.batch();
assert_card(&move_to_lane_batch, "Design hero moment", "Runtime", "Active", "width:99%"); assert_card(&move_to_lane_batch, "Design hero moment", "Runtime", "Active", "width:99%");
assert_payload_contains(&move_to_lane_batch, "Drag-and-drop move persisted"); assert_payload_contains(&move_to_lane_batch, "Drag-and-drop move persisted");
let inspect = post("/", &format!("__h={}&work_id=4", card_handles::spotlight_work)); let inspect = post(
"/",
&handle_body(card_handles::spotlight_work, &[("work_id", "4")]),
);
assert_effect_response(&inspect); assert_effect_response(&inspect);
let inspect_batch = inspect.batch(); let inspect_batch = inspect.batch();
assert_payload_contains(&inspect_batch, "Design hero moment · lane=Runtime"); assert_payload_contains(&inspect_batch, "Design hero moment · lane=Runtime");
assert_payload_contains(&inspect_batch, "Inspector focused"); assert_payload_contains(&inspect_batch, "Inspector focused");
let advance = post("/", &format!("__h={}&work_id=4", card_handles::advance_work)); let advance = post(
"/",
&handle_body(card_handles::advance_work, &[("work_id", "4")]),
);
assert_effect_response(&advance); assert_effect_response(&advance);
let advance_batch = advance.batch(); let advance_batch = advance.batch();
assert_payload_contains(&advance_batch, "Pipeline advanced"); assert_payload_contains(&advance_batch, "Pipeline advanced");
assert_payload_contains(&advance_batch, "<span class=\"pill\">Active</span>"); assert_payload_contains(&advance_batch, "<span class=\"pill\">Active</span>");
let advance_default = post("/", &format!("__h={}&work_id=5", card_handles::advance_work)); let advance_default = post(
"/",
&handle_body(card_handles::advance_work, &[("work_id", "5")]),
);
assert_effect_response(&advance_default); assert_effect_response(&advance_default);
let advance_default_batch = advance_default.batch(); let advance_default_batch = advance_default.batch();
assert_payload_contains(&advance_default_batch, "Default impact"); assert_payload_contains(&advance_default_batch, "Default impact");
assert_card(&advance_default_batch, "Default impact", "Compiler", "Active", "width:55%"); assert_card(&advance_default_batch, "Default impact", "Compiler", "Active", "width:55%");
let ship_default = post("/", &format!("__h={}&work_id=5", card_handles::advance_work)); let ship_default = post(
"/",
&handle_body(card_handles::advance_work, &[("work_id", "5")]),
);
assert_effect_response(&ship_default); assert_effect_response(&ship_default);
let ship_default_batch = ship_default.batch(); let ship_default_batch = ship_default.batch();
assert_card(&ship_default_batch, "Default impact", "Product", "Shipped", "width:55%"); assert_card(&ship_default_batch, "Default impact", "Product", "Shipped", "width:55%");
let simulated_push = post("/", &format!("__h={}", handles::simulate_push)); let simulated_push = post("/", &handle_body(handles::simulate_push, &[]));
assert_effect_response(&simulated_push); assert_effect_response(&simulated_push);
let push_batch = simulated_push.batch(); let push_batch = simulated_push.batch();
assert_payload_contains(&push_batch, "SSE tick"); assert_payload_contains(&push_batch, "SSE tick");
@@ -187,12 +226,18 @@ fn product_is_e2e_working_over_http() {
assert_payload_contains(&push_batch, "Simulated push event produced the same EffectBatch shape"); assert_payload_contains(&push_batch, "Simulated push event produced the same EffectBatch shape");
assert_emit(&push_batch, "slhx:island-orbit", "activity rows"); assert_emit(&push_batch, "slhx:island-orbit", "activity rows");
let delete_missing = post("/", &format!("__h={}&work_id=999", card_handles::delete_work)); let delete_missing = post(
"/",
&handle_body(card_handles::delete_work, &[("work_id", "999")]),
);
assert_effect_response(&delete_missing); assert_effect_response(&delete_missing);
let delete_missing_batch = delete_missing.batch(); let delete_missing_batch = delete_missing.batch();
assert_payload_not_contains(&delete_missing_batch, "Deleted card #999"); assert_payload_not_contains(&delete_missing_batch, "Deleted card #999");
let delete = post("/", &format!("__h={}&work_id=4", card_handles::delete_work)); let delete = post(
"/",
&handle_body(card_handles::delete_work, &[("work_id", "4")]),
);
assert_effect_response(&delete); assert_effect_response(&delete);
let delete_batch = delete.batch(); let delete_batch = delete.batch();
assert_payload_contains(&delete_batch, "Card removed"); assert_payload_contains(&delete_batch, "Card removed");
@@ -200,7 +245,7 @@ fn product_is_e2e_working_over_http() {
assert_payload_not_contains(&delete_batch, "data-key=\"4\""); assert_payload_not_contains(&delete_batch, "data-key=\"4\"");
assert_payload_contains(&delete_batch, "Default impact"); assert_payload_contains(&delete_batch, "Default impact");
let reset = post("/", &format!("__h={}", handles::reset_demo)); let reset = post("/", &handle_body(handles::reset_demo, &[]));
assert_effect_response(&reset); assert_effect_response(&reset);
let reset_batch = reset.batch(); let reset_batch = reset.batch();
assert_payload_contains(&reset_batch, "Demo reset from Rust state"); assert_payload_contains(&reset_batch, "Demo reset from Rust state");