feat(test): bind text assertions to targets

This commit is contained in:
slhx agent
2026-07-13 10:07:40 +02:00
parent e70c863da7
commit 6b4bb97aaa
3 changed files with 65 additions and 5 deletions
+4 -2
View File
@@ -880,8 +880,10 @@ mod tests {
.unwrap() .unwrap()
.batch, .batch,
); );
assert!(lazy.updates_text(gallery::lazy_panel)); lazy.assert_updates_text_containing(
assert!(lazy.payload_contains("Lazy content loaded by server update #1")); gallery::lazy_panel,
"Lazy content loaded by server update #1",
);
let more = inspect_batch( let more = inspect_batch(
InteractionRequest::from(form(gallery::load_more, &[("request", "more")])) InteractionRequest::from(form(gallery::load_more, &[("request", "more")]))
+27 -3
View File
@@ -462,17 +462,41 @@ impl EffectInspector {
self.has_resource(target.__hemx_resource_id()) self.has_resource(target.__hemx_resource_id())
} }
/// Assert that a generated target receives a text update, without matching raw effects. /// Check that a generated target receives a text update, without matching raw effects.
/// req: test/001 req: dx/006 /// req: test/001 req: dx/006
pub fn updates_text(&self, target: impl GeneratedTarget) -> bool { pub fn updates_text(&self, target: impl GeneratedTarget) -> bool {
self.has_text_update_containing(target.__hemx_resource_id(), "")
}
/// Check that a generated target receives a text update containing a fragment.
///
/// This associates the payload condition with the intended target, unlike a separate global
/// [`Self::payload_contains`] check that can accidentally match another operation.
/// req: test/001 req: test/018 req: dx/006
pub fn updates_text_containing(&self, target: impl GeneratedTarget, needle: &str) -> bool {
self.has_text_update_containing(target.__hemx_resource_id(), needle)
}
/// Assert that a generated target receives a text update containing a fragment.
/// req: test/001 req: test/018 req: dx/006
#[track_caller]
pub fn assert_updates_text_containing(&self, target: impl GeneratedTarget, needle: &str) {
let resource = target.__hemx_resource_id(); let resource = target.__hemx_resource_id();
assert!(
self.has_text_update_containing(resource, needle),
"expected a text update for {resource:?} containing {needle:?}; actual effects: {:#?}",
self.batch.ops
);
}
fn has_text_update_containing(&self, resource: ResourceId, needle: &str) -> bool {
self.batch.ops.iter().any(|op| { self.batch.ops.iter().any(|op| {
matches!( matches!(
op, op,
Effect::Put { Effect::Put {
target, target,
payload: Payload::Text(_), payload: Payload::Text(text),
} if target.resource == resource } if target.resource == resource && text.contains(needle)
) )
}) })
} }
+34
View File
@@ -17,6 +17,40 @@ fn inspects_tuple_effects() {
})); }));
} }
#[test]
fn text_update_condition_is_bound_to_the_expected_target() {
// req: test/018
let expected_target = TestTarget(ResourceKind::Slot, 42);
let inspected = hemx_test::inspect(vec![
Effect::Put {
target: ResourceRef::unscoped(ResourceId::new(ResourceKind::Slot, 42)),
payload: Payload::Text(String::from("wrong payload")),
},
Effect::Put {
target: ResourceRef::unscoped(ResourceId::new(ResourceKind::Slot, 7)),
payload: Payload::Text(String::from("expected fragment")),
},
]);
assert!(inspected.updates_text(expected_target));
assert!(inspected.payload_contains("expected fragment"));
assert!(!inspected.updates_text_containing(expected_target, "expected fragment"));
let panic = std::panic::catch_unwind(|| {
inspected.assert_updates_text_containing(expected_target, "expected fragment");
})
.expect_err("a payload on another target must not satisfy the assertion");
let message = panic
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| panic.downcast_ref::<&str>().copied())
.expect("assertion panic must carry a message");
assert!(message.contains("expected fragment"), "{message}");
assert!(message.contains("wrong payload"), "{message}");
assert!(message.contains("ResourceId"), "{message}");
}
#[test] #[test]
fn html_update_assertion_reports_expectation_and_actual_effects() { fn html_update_assertion_reports_expectation_and_actual_effects() {
// req: test/018 // req: test/018