diff --git a/crates/aura-cli/src/scaffold.rs b/crates/aura-cli/src/scaffold.rs index 7a0a25e..a058c00 100644 --- a/crates/aura-cli/src/scaffold.rs +++ b/crates/aura-cli/src/scaffold.rs @@ -321,6 +321,37 @@ mod tests { assert!(cargo.contains("/crates/aura-core")); } + /// Property (#183, fieldtest F2 gap): the scaffold's own starter node teaches + /// the bound-param build closure. Its rendered `src/lib.rs` declares a param in + /// the node schema and reads a bound value in the build closure (not the + /// param-less `|_|` Identity the template shipped before), and the rendered + /// starter blueprint binds `factor` on the project's own node — so `aura run` + /// exercises the bound-param path with zero hand-editing. (The scaffold→build→ + /// run e2e in tests/project_new.rs re-validates the swap end to end; this pins + /// the copyable template content a newcomer learns from directly.) + #[test] + fn starter_node_declares_and_reads_a_bound_param() { + let spec = spec_for("demo-lab", None); + let lib = render(LIB_RS, &spec); + // (a) the node schema declares a bindable param... + assert!( + lib.contains("ParamSpec"), + "starter node must declare a param in its schema, not `params: vec![]`: {lib}" + ); + // ...and the build closure reads that bound param (p[0]), not `|_|`. + assert!( + lib.contains("p[0].f64()"), + "starter build closure must consume a bound param (p[0].f64()), not `|_|`: {lib}" + ); + // (b) the starter blueprint binds `factor` on the project's own node, so + // `aura run` drives the bound-param path out of the box. + let json = render(SIGNAL_JSON, &spec); + assert!( + json.contains("\"name\":\"factor\""), + "starter blueprint must bind the `factor` param on the project node: {json}" + ); + } + #[test] fn scaffold_refuses_existing_dir_and_missing_engine() { let tmp = std::env::temp_dir().join(format!("aura-scaf-{}", std::process::id()));