Merge PR #962: Tests: the Options dialog's Cancel, Esc and the close button restore the settings (#878)

crates/ui-egui/src/dialogs.rs: kept both test modules (about_credits_tests, preferences_tests).
This commit is contained in:
aiongg
2026-10-24 06:14:48 +00:00
3 changed files with 136 additions and 0 deletions
+1
View File
@@ -158,6 +158,7 @@ app's JSON control channel (`deckcraft --control PORT`).
| 2026-10-17 | While a placeholder's text is being edited, a click on a shape in front of it selects that shape instead of moving the caret, as in PowerPoint (#931) |
| 2026-10-16 | Symbol-font characters: a run's U+F0xx symbol code (from `<a:sym typeface="Symbol"/>`) now draws from the installed Symbol face even when it has no private-use mapping — Apple's Symbol on macOS maps the glyphs to real Unicode, so the code is remapped to that character (the Adobe Symbol encoding) instead of falling to a look-alike. Bullets and metafile text take the same remap |
| 2026-10-15 | Native saves keep an imported chart's embedded workbook, drawings and relationships; headless PPTX → edit → native save/reopen → PPTX tests verify the payloads and stale-workbook rejection |
| 2026-10-20 | Tests: the Options dialog's Cancel, Esc and close button put the settings back the way they were (#878) |
| 2026-10-15 | PPTX trigger sequences keep separate On Click steps, including paragraph builds; synthetic import/edit/save/reopen and headless show regressions |
| 2026-10-16 | Export: PNG with a transparent background — the slide background is left out, only the slide's content is drawn (Export… dialog, File › Export, web download, `file.export`/`file.render` `transparentBackground`, `deckcraft-cli render --transparent`) (#784) |
| 2026-10-16 | Arrange ▸ Align: Align to Slide and Align Selected Objects, as in PowerPoint. One object aligns to the slide and several to each other until the other choice is ticked; the choice holds for that selection and also drives Distribute |
+4
View File
@@ -3762,3 +3762,7 @@ mod about_credits_tests {
}
}
}
#[cfg(test)]
#[path = "preferences_tests.rs"]
mod preferences_tests;
+131
View File
@@ -0,0 +1,131 @@
//! The Preferences (Options) dialog: controls apply as they change and Cancel, Esc and the
//! window's close button put the settings back the way they were (#752, reported as #878).
use deckcraft_engine::Session;
use egui_kittest::kittest::{NodeT, Queryable};
use egui_kittest::{Harness, Node};
use serde_json::json;
use crate::theme::Brightness;
use crate::{Services, SlideApp};
/// The slider itself, not the label drawn beside it.
fn interface_size<'a>(h: &'a Harness<'_, SlideApp>) -> Node<'a> {
h.get_all_by_label("Interface size").find(|n| n.accesskit_node().role() == egui::accesskit::Role::Slider).expect("the slider is there")
}
fn harness() -> Harness<'static, SlideApp> {
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_ui_state(
|ui, app: &mut SlideApp| {
app.logic(ui.ctx());
app.ui(ui);
},
SlideApp::new(Session::with_new(), Services::default()),
);
// The app keeps asking for frames, so step instead of run().
h.run_steps(3);
h
}
fn open_options(h: &mut Harness<'_, SlideApp>) {
h.state_mut().run("app.preferences", json!({})).expect("open Options");
h.run_steps(3);
}
fn dark(app: &SlideApp) -> bool {
app.ui.brightness == Brightness::Dark
}
/// A checkbox applies as it is toggled and Cancel puts the old value back.
#[test]
fn options_cancel_undoes_the_changes() {
let mut h = harness();
let was = h.state().session.prefs.smart_guides;
open_options(&mut h);
h.query_by_label("Show smart guides").expect("the checkbox is there").click();
h.run_steps(2);
assert_eq!(h.state().session.prefs.smart_guides, !was, "the change applies as it is made");
h.query_by_label("Cancel").expect("the Cancel button is there").click();
h.run_steps(2);
assert_eq!(h.state().session.prefs.smart_guides, was, "Cancel restores the setting");
assert!(h.state().dialog.is_none(), "and the dialog closes");
}
/// Every Editing setting and the name field go back on Cancel, not only the first checkbox: a
/// reporter who changed a different control and saw Cancel do nothing has the same answer.
#[test]
fn options_cancel_undoes_every_editing_setting() {
let mut h = harness();
let before = h.state().session.prefs.clone();
open_options(&mut h);
for label in ["Snap objects to grid", "Replace straight quotes with smart quotes", "AutoCorrect as you type"] {
h.query_by_label(label).unwrap_or_else(|| panic!("the {label} checkbox is there")).click();
h.run_steps(1);
}
// The name field: it writes into the settings as it is typed.
// The name field is the last text input of the dialog (the label is a separate widget).
let name = h.get_all_by_role(egui::accesskit::Role::TextInput).last().expect("the name field is there");
name.click();
h.run_steps(1);
h.event(egui::Event::Text("Z".into()));
h.run_steps(1);
let changed = h.state().session.prefs.clone();
assert_ne!(
(changed.snap_to_grid, changed.smart_quotes, changed.autocorrect),
(before.snap_to_grid, before.smart_quotes, before.autocorrect),
"the settings apply as they are changed"
);
assert_ne!(changed.author, before.author, "the name applies as it is typed: {:?}", changed.author);
h.query_by_label("Cancel").expect("the Cancel button is there").click();
h.run_steps(2);
let after = h.state().session.prefs.clone();
assert_eq!(after.snap_to_grid, before.snap_to_grid, "snap to grid is restored");
assert_eq!(after.smart_quotes, before.smart_quotes, "smart quotes are restored");
assert_eq!(after.autocorrect, before.autocorrect, "autocorrect is restored");
assert_eq!(after.author, before.author, "the name is restored");
}
/// The appearance toggle and the interface size go back on Cancel, too; Esc acts as Cancel.
#[test]
fn options_cancel_puts_the_appearance_and_scale_back() {
let mut h = harness();
let (dark_before, scale_before) = (dark(h.state()), h.state().ui.ui_scale);
open_options(&mut h);
h.query_by_label("Dark appearance").expect("the checkbox is there").click();
h.run_steps(2);
assert!(dark(h.state()), "the appearance applies as it is toggled");
// Clicking the slider's middle sets it near the middle of its range, away from the default.
interface_size(&h).click();
h.run_steps(2);
let scale_in_dialog = h.state().ui.ui_scale;
assert!((scale_in_dialog - scale_before).abs() > 1e-3, "the slider applied a new size");
h.key_press(egui::Key::Escape);
h.run_steps(2);
assert_eq!(dark(h.state()), dark_before, "Esc restores the appearance");
assert!((h.state().ui.ui_scale - scale_before).abs() < 1e-3, "Esc restores the size");
assert!(h.state().dialog.is_none(), "and the dialog closes");
}
/// The window's close button is the same as Cancel: the settings go back.
#[test]
fn options_close_button_restores_the_settings() {
let mut h = harness();
let was = h.state().session.prefs.smart_guides;
open_options(&mut h);
h.query_by_label("Show smart guides").expect("the checkbox is there").click();
h.run_steps(2);
assert_eq!(h.state().session.prefs.smart_guides, !was, "the change applies as it is made");
h.get_all_by_label("Close window").next().expect("the window's close button is there").click();
h.run_steps(2);
assert_eq!(h.state().session.prefs.smart_guides, was, "the close button restores the setting");
assert!(h.state().dialog.is_none(), "and the dialog closes");
}