QA targets for the newest UX reports (pending until their owners land): s37 browser chevrons on every node kind (all toggle; no Joints folder yet), s38 view animations to Top/Bottom end without a jump (the last frame turns 22.5 degrees today), s39 view cube edge/corner hover lights 2/3 patches, s40 toolbar Pin/Remove/reorder survive a restart and the workspace switcher spans the toolbar; ui_layout tests: every command dialog docked right at 260-380 px (or 480-560 for tables; the exploded view is 635), other windows fit on screen. Harness: published rects and counts, browser rows/fold arrows as handles, camera and view_anim steps, ui.at cube points, settings carried over a close restart, an adhoc scenario runner

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-08 16:07:33 +00:00
1 parent 1e8fc25976
commit c45f3173fa
11 files changed
+831 -9

No files matched your search

+67
View File
@@ -0,0 +1,67 @@
//! Layout checks over every toolbar command, headless (see `solvecraft_ui_egui::scenario`):
//! each command's dialog opens docked at the viewport's right within its width limits, and
//! every window it opens fits on screen.
use serde_json::{Value, json};
use solvecraft_ui_egui::scenario::{Harness, check};
/// A box body (its sketch finished) to give feature dialogs something to work on.
fn harness() -> Harness {
let mut h = Harness::new();
for (id, p) in [
("SketchCreate", json!({"plane": "XY"})),
("ShapeRectangleTwoPoint", json!({"p0": [0, 0], "p1": [40, 30]})),
("SketchStop", json!({})),
("Extrude", json!({"distance": 10})),
] {
h.call("engine.execute", json!({"command": id, "params": p}));
}
h.frames(3);
h
}
#[test]
#[ignore = "pending: the exploded view dialog opens 635 px wide (solvecraft-ui)"]
fn every_dialog_opens_docked_within_its_width_limits() {
let mut bad = Vec::new();
let mut seen = 0;
for spec in solvecraft_engine::command_specs() {
if spec.tab.is_empty() || spec.tab == "SKETCH" {
continue;
}
let mut h = harness();
h.call("ui.start", json!({"command": spec.id}));
h.frames(4);
if h.app.dialog.is_some() {
seen += 1;
// Command dialogs are 260–380 px (plus their 1 px border), the few with tables
// (motion study, configurations) 480–560.
let w = h.ctx.memory(|m| m.area_rect(egui::Id::new("sc_dialog"))).map_or(0.0, |r| r.width());
let limits = if w > 400.0 { json!({"min": 480, "max": 562}) } else { json!({"min": 260, "max": 382}) };
if let Err(e) = check(&mut h, &json!({ "dialog_docked": limits })) {
bad.push(format!("{}: {e}", spec.id));
}
}
if let Err(e) = check(&mut h, &json!({"windows_fit": {"max_width": 900}})) {
bad.push(format!("{}: {e}", spec.id));
}
}
assert!(seen > 20, "only {seen} commands opened a dialog");
assert!(bad.is_empty(), "{} problems:\n{}", bad.len(), bad.join("\n"));
}
/// Windows that are not command dialogs: each fits on screen.
#[test]
fn other_windows_fit_on_screen() {
let mut bad = Vec::new();
let opens: [(&str, Value); 3] = [("ui.help", json!({"item": "about"})), ("ui.key", json!({"key": "S"})), ("ui.prefs", json!({"open": true}))];
for (m, p) in opens {
let mut h = harness();
h.call(m, p.clone());
h.frames(4);
if let Err(e) = check(&mut h, &json!({"windows_fit": {"max_width": 900}})) {
bad.push(format!("{m} {p}: {e}"));
}
}
assert!(bad.is_empty(), "{}", bad.join("\n"));
}