Browser fold arrows: each row is one widget with a stable id, and where the click lands decides what it does (fold arrow with padding, eye, radio, or the row), so an arrow click toggles without also selecting or picking the row or starting a drag; Collapse/Expand tips; ui.at {browser|chevron} and ui.browser for automation; scenario browser_chevrons clicks every folder's arrow (document settings, named views, origin, groups, sketches, construction, canvases, components, bodies, the design) and checks the children; the inch-width units test runs now that params reads unit-less lengths in design units

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-10 07:19:58 +00:00
1 parent fd4d38d31e
commit 9d3cbb4acc
5 files changed
+606 -15

No files matched your search

+23 -1
View File
@@ -24,7 +24,8 @@
//! - `{"camera": {"yaw": rad, "pitch": rad}}` puts the camera at an orbit; `{"view_anim": "top",
//! "max_deg": 10}` animates to a view and fails if any frame turns the view more than that
//! - AT may also be `{"plane": "XY"}` (the middle of an origin plane's square), `{"axis": "Z"}`,
//! `{"dimension": "d1"}` or `{"handle": "arrow"}` (a manipulator handle: see [`publish_handle`])
//! `{"dimension": "d1"}`, `{"handle": "arrow"}` (a manipulator handle: see [`publish_handle`]),
//! `{"browser": "Bodies"}` (a browser row by its label) or `{"chevron": "Bodies"}` (its fold arrow)
//! - `{"autosave": true}`: autosave into the scenario's recovery folder; `{"restart": "crash" |
//! "close"}`: the app dies (or closes) and a new one starts on the same folders
//! - `{"script": "examples/…/x.json"}`: run a command script through the engine; `"$DIR"` in a
@@ -864,6 +865,27 @@ pub fn check(h: &mut Harness, e: &Value) -> Result<(), String> {
return Err(format!("design name: got {}, want {v}", doc["name"]));
}
}
"browser_has" | "browser_lacks" => {
// Browser rows on screen, by label.
let r = h.call("ui.browser", json!({}));
let labels: Vec<String> =
r["result"]["rows"].as_array().into_iter().flatten().filter_map(|x| x["label"].as_str().map(str::to_string)).collect();
for want in v.as_array().into_iter().flatten().filter_map(Value::as_str) {
let there = labels.iter().any(|l| l == want);
if there != (k.as_str() == "browser_has") {
return Err(format!("browser row `{want}` {}: rows {labels:?}", if there { "still shown" } else { "missing" }));
}
}
}
"browser_selected" => {
// Nothing selected and no component picked (a fold click selects nothing).
let r = h.call("ui.browser", json!({}));
let none = r["result"]["selection"].as_array().is_none_or(|a| a.is_empty())
&& r["result"]["picked_components"].as_array().is_none_or(|a| a.is_empty());
if none == v.as_bool().unwrap_or(false) {
return Err(format!("browser selection: {}", r["result"]));
}
}
"query" => {
// {command, params?, path: [keys or indices], value}: a command's result at path.
let cmd = v["command"].as_str().ok_or("query needs `command`")?;