From c217639cb57e768374cc9c3d64d3cc7e02c12662 Mon Sep 17 00:00:00 2001 From: skylar taylor-barrick Date: Sun, 25 Oct 2026 09:21:03 +0100 Subject: [PATCH] test: share migrated GridCraft UI harness setup --- crates/ui-egui/tests/common/mod.rs | 25 +++++++++++ crates/ui-egui/tests/it/advanced_filter.rs | 14 +------ .../ui-egui/tests/it/committed_text_fields.rs | 13 +----- .../ui-egui/tests/it/contextual_ribbon_tab.rs | 23 +---------- crates/ui-egui/tests/it/dialog_confirm.rs | 14 +------ crates/ui-egui/tests/it/file_menu.rs | 15 +------ .../tests/it/fill_handle_double_click.rs | 10 +---- .../tests/it/fill_handle_right_drag.rs | 10 +---- .../ui-egui/tests/it/fill_options_button.rs | 10 +---- crates/ui-egui/tests/it/find_dialog_focus.rs | 14 +------ crates/ui-egui/tests/it/floating_pictures.rs | 15 +------ crates/ui-egui/tests/it/format_painter.rs | 11 +---- crates/ui-egui/tests/it/formula_bar_expand.rs | 11 +---- crates/ui-egui/tests/it/freeze_handles.rs | 12 +----- crates/ui-egui/tests/it/interaction.rs | 11 +---- crates/ui-egui/tests/it/keyboard_shortcuts.rs | 11 +---- crates/ui-egui/tests/it/keytips_generated.rs | 10 +---- crates/ui-egui/tests/it/main.rs | 1 + crates/ui-egui/tests/it/open_encrypted.rs | 13 +----- crates/ui-egui/tests/it/outline.rs | 12 +----- crates/ui-egui/tests/it/page_layout_view.rs | 16 +++----- crates/ui-egui/tests/it/pivot_show_details.rs | 12 +----- .../tests/it/pivot_show_details_menu.rs | 12 +----- crates/ui-egui/tests/it/protect_password.rs | 14 +------ crates/ui-egui/tests/it/right_to_left.rs | 11 +---- .../ui-egui/tests/it/sort_dialog_columns.rs | 11 +---- crates/ui-egui/tests/it/support.rs | 41 +++++++++++++++++++ crates/ui-egui/tests/it/text_box_editing.rs | 15 +++---- crates/ui-egui/tests/it/touch_pan.rs | 11 +---- crates/ui-egui/tests/it/trace_navigation.rs | 11 +---- .../tests/it/translated_form_fields.rs | 14 +------ crates/ui-egui/tests/it/zoom_dialog.rs | 13 +----- crates/ui-egui/tests/keytips.rs | 10 +---- xtask/src/keytips.rs | 13 +----- 34 files changed, 114 insertions(+), 345 deletions(-) create mode 100644 crates/ui-egui/tests/it/support.rs diff --git a/crates/ui-egui/tests/common/mod.rs b/crates/ui-egui/tests/common/mod.rs index 1b91dfcfb..aa7774fc1 100644 --- a/crates/ui-egui/tests/common/mod.rs +++ b/crates/ui-egui/tests/common/mod.rs @@ -12,6 +12,8 @@ use egui_kittest::HarnessBuilder; use gridcraft_engine::Session; use gridcraft_ui_egui::{Services, SheetApp}; +pub type Harness = egui_kittest::Harness<'static, SheetApp>; + /// A kittest builder with the deterministic font set and GridCraft's visuals installed. pub fn builder() -> HarnessBuilder { egui_kittest::Harness::builder().with_context_setup(|ctx| { @@ -30,3 +32,26 @@ pub fn prepare(mut app: SheetApp) -> SheetApp { app.use_prepared_fonts(); app } + +/// Drive `app`'s `logic` then `ui` each frame in a harness built with `builder`. +/// +/// Tests that need a non-standard size, step timing, OS or pixel ratio configure the builder +/// here so those details stay explicit; the shared font and lifecycle setup lives in `builder` +/// and `app`. +pub fn harness_with(builder: HarnessBuilder, app: SheetApp, steps: usize) -> Harness { + let mut h = builder.build_ui_state( + |ui, app: &mut SheetApp| { + let ctx = ui.ctx().clone(); + app.logic(&ctx); + app.ui(ui); + }, + app, + ); + h.run_steps(steps); + h +} + +/// A 1200×800 harness that reports `os` to egui, for platform-specific input. +pub fn os_harness(session: Session, os: egui::os::OperatingSystem) -> Harness { + harness_with(builder().with_os(os).with_size(egui::vec2(1200.0, 800.0)), app(session), 4) +} diff --git a/crates/ui-egui/tests/it/advanced_filter.rs b/crates/ui-egui/tests/it/advanced_filter.rs index 9a1394a09..43b10f4bd 100644 --- a/crates/ui-egui/tests/it/advanced_filter.rs +++ b/crates/ui-egui/tests/it/advanced_filter.rs @@ -1,24 +1,12 @@ //! Advanced Filter's dialog must route both actions to the same engine command. -use egui::vec2; use egui_kittest::kittest::Queryable; -use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use gridcraft_ui_egui::control::{Outcome, handle}; use serde_json::{Value as Json, json}; fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(&ui.ctx().clone()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(6); - h + crate::support::blank_harness(6) } fn control(h: &mut egui_kittest::Harness<'static, SheetApp>, method: &str, params: Json) -> Json { diff --git a/crates/ui-egui/tests/it/committed_text_fields.rs b/crates/ui-egui/tests/it/committed_text_fields.rs index 0dca99c0d..1aaf0b5bb 100644 --- a/crates/ui-egui/tests/it/committed_text_fields.rs +++ b/crates/ui-egui/tests/it/committed_text_fields.rs @@ -1,6 +1,6 @@ //! Text fields over workbook values (chart titles, table name) keep what the user types until they commit it. -use egui::{Event, Key, Modifiers, accesskit::Role, vec2}; +use egui::{Event, Key, Modifiers, accesskit::Role}; use egui_kittest::kittest::Queryable as _; use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; @@ -9,16 +9,7 @@ use serde_json::json; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn session() -> Session { diff --git a/crates/ui-egui/tests/it/contextual_ribbon_tab.rs b/crates/ui-egui/tests/it/contextual_ribbon_tab.rs index be5661d30..d7b15f760 100644 --- a/crates/ui-egui/tests/it/contextual_ribbon_tab.rs +++ b/crates/ui-egui/tests/it/contextual_ribbon_tab.rs @@ -2,7 +2,6 @@ //! The tab remembered in the saved UI state, or left behind when the selection moves away, must //! not leave the ribbon blank: it falls back to Home. -use egui::vec2; use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use serde_json::json; @@ -10,16 +9,7 @@ use serde_json::json; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn session_with_table() -> Session { @@ -34,16 +24,7 @@ fn session_with_table() -> Session { fn app_restored_on(tab: &str, session: Session) -> Harness { let mut app = crate::common::app(session); app.ui.ribbon_tab = tab.into(); - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - app, - ); - h.run_steps(4); - h + crate::support::app_harness(app, 4) } #[test] diff --git a/crates/ui-egui/tests/it/dialog_confirm.rs b/crates/ui-egui/tests/it/dialog_confirm.rs index 1231798ce..9736f700f 100644 --- a/crates/ui-egui/tests/it/dialog_confirm.rs +++ b/crates/ui-egui/tests/it/dialog_confirm.rs @@ -1,24 +1,12 @@ //! `ui.dialog.confirm` runs a dialog's command with the parameters its OK button sends (#1459). -use egui::vec2; -use gridcraft_engine::Session; use gridcraft_engine::model::CfRule; use gridcraft_ui_egui::SheetApp; use gridcraft_ui_egui::control::{Outcome, handle}; use serde_json::{Value as Json, json}; fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(&ui.ctx().clone()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(6); - h + crate::support::blank_harness(6) } fn control(h: &mut egui_kittest::Harness<'static, SheetApp>, method: &str, params: Json) -> Json { diff --git a/crates/ui-egui/tests/it/file_menu.rs b/crates/ui-egui/tests/it/file_menu.rs index 78f7d0fb4..1cf0396f9 100644 --- a/crates/ui-egui/tests/it/file_menu.rs +++ b/crates/ui-egui/tests/it/file_menu.rs @@ -3,23 +3,12 @@ use std::sync::{Arc, Mutex}; use egui_kittest::kittest::Queryable as _; -use gridcraft_engine::{Session, core::CellRef, core::Value}; +use gridcraft_engine::{core::CellRef, core::Value}; use gridcraft_ui_egui::i18n::Language; use gridcraft_ui_egui::{Services, SheetApp}; fn harness(services: Services) -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::prepare(SheetApp::new(session, services)), - ); - h.run_steps(4); - h + crate::support::services_harness(services, 4) } /// Opens File (the Backstage view) and clicks a navigation entry or page button. diff --git a/crates/ui-egui/tests/it/fill_handle_double_click.rs b/crates/ui-egui/tests/it/fill_handle_double_click.rs index f0b46e622..b2ae68916 100644 --- a/crates/ui-egui/tests/it/fill_handle_double_click.rs +++ b/crates/ui-egui/tests/it/fill_handle_double_click.rs @@ -13,15 +13,7 @@ fn harness() -> egui_kittest::Harness<'static, SheetApp> { session.execute("range.setValues", json!({"range": "A1", "values": [[1], [2], [3], [4], [5], [6]]})).unwrap(); session.execute("range.setValues", json!({"range": "B1", "values": [[10], [20], [30]]})).unwrap(); session.execute("selection.set", json!({"range": "B1:B3"})).unwrap(); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } fn handle(h: &egui_kittest::Harness<'_, SheetApp>) -> Pos2 { diff --git a/crates/ui-egui/tests/it/fill_handle_right_drag.rs b/crates/ui-egui/tests/it/fill_handle_right_drag.rs index a0ebbd40f..d8ffbff9a 100644 --- a/crates/ui-egui/tests/it/fill_handle_right_drag.rs +++ b/crates/ui-egui/tests/it/fill_handle_right_drag.rs @@ -15,15 +15,7 @@ fn harness(setup: impl FnOnce(&mut Session)) -> Harness { let mut session = Session::new(); session.new_workbook(); setup(&mut session); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } /// B1:B2 holds 1, 2 and is selected. diff --git a/crates/ui-egui/tests/it/fill_options_button.rs b/crates/ui-egui/tests/it/fill_options_button.rs index a9e4099d7..0a784d6c6 100644 --- a/crates/ui-egui/tests/it/fill_options_button.rs +++ b/crates/ui-egui/tests/it/fill_options_button.rs @@ -15,15 +15,7 @@ fn harness(setup: impl FnOnce(&mut Session)) -> Harness { let mut session = Session::new(); session.new_workbook(); setup(&mut session); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } /// B1:B2 holds 1, 2 and is selected. diff --git a/crates/ui-egui/tests/it/find_dialog_focus.rs b/crates/ui-egui/tests/it/find_dialog_focus.rs index 2c23e12ea..a774a431b 100644 --- a/crates/ui-egui/tests/it/find_dialog_focus.rs +++ b/crates/ui-egui/tests/it/find_dialog_focus.rs @@ -1,7 +1,6 @@ //! Opening Find and Replace puts the cursor in "Find what", so the user can type at once. use egui::{Event, Key, Modifiers}; -use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use serde_json::json; @@ -11,18 +10,7 @@ type Harness = egui_kittest::Harness<'static, SheetApp>; const CTRL: Modifiers = Modifiers { alt: false, ctrl: true, shift: false, mac_cmd: false, command: true }; fn harness() -> Harness { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(6); - h + crate::support::blank_harness(6) } fn type_after_shortcut(k: Key) -> Option { diff --git a/crates/ui-egui/tests/it/floating_pictures.rs b/crates/ui-egui/tests/it/floating_pictures.rs index b9bd52efc..0ecd9ca07 100644 --- a/crates/ui-egui/tests/it/floating_pictures.rs +++ b/crates/ui-egui/tests/it/floating_pictures.rs @@ -2,8 +2,7 @@ use std::io::Cursor; -use egui::{Shape, TextureId, vec2}; -use gridcraft_engine::Session; +use egui::{Shape, TextureId}; use gridcraft_ui_egui::SheetApp; use serde_json::json; @@ -15,17 +14,7 @@ fn png(color: [u8; 4]) -> Vec { } fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(&ui.ctx().clone()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::blank_harness(4) } fn picture_textures(h: &egui_kittest::Harness<'static, SheetApp>) -> Vec { diff --git a/crates/ui-egui/tests/it/format_painter.rs b/crates/ui-egui/tests/it/format_painter.rs index 62e34c33b..39eeaa4c4 100644 --- a/crates/ui-egui/tests/it/format_painter.rs +++ b/crates/ui-egui/tests/it/format_painter.rs @@ -18,16 +18,7 @@ fn harness() -> Harness { session.execute("home.bold", json!({"range": "A1", "on": true})).unwrap(); session.execute("home.fillColor", json!({"range": "A1", "color": "#FFFF00"})).unwrap(); session.execute("selection.set", json!({"cell": "A1"})).unwrap(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn style(h: &Harness, a1: &str) -> Style { diff --git a/crates/ui-egui/tests/it/formula_bar_expand.rs b/crates/ui-egui/tests/it/formula_bar_expand.rs index 6e82112cd..a71a979cd 100644 --- a/crates/ui-egui/tests/it/formula_bar_expand.rs +++ b/crates/ui-egui/tests/it/formula_bar_expand.rs @@ -18,16 +18,7 @@ fn harness() -> Harness { session.new_workbook(); session.execute("cell.set", json!({"cell": "A1", "input": "text"})).unwrap(); session.execute("selection.set", json!({"range": "A1"})).unwrap(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn ctrl_shift_u(h: &mut Harness, m: Modifiers) { diff --git a/crates/ui-egui/tests/it/freeze_handles.rs b/crates/ui-egui/tests/it/freeze_handles.rs index 71a3b54a4..7bcc81d1a 100644 --- a/crates/ui-egui/tests/it/freeze_handles.rs +++ b/crates/ui-egui/tests/it/freeze_handles.rs @@ -1,6 +1,6 @@ //! Freezing panes by dragging the freeze handles on the header edges (#195). -use egui::{Event, Modifiers, PointerButton, Pos2, pos2, vec2}; +use egui::{Event, Modifiers, PointerButton, Pos2, pos2}; use gridcraft_engine::Session; use gridcraft_engine::core::CellRef; use gridcraft_ui_egui::SheetApp; @@ -11,15 +11,7 @@ type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness() -> Harness { let mut session = Session::new(); session.new_workbook(); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } fn geo(h: &Harness) -> Geo { diff --git a/crates/ui-egui/tests/it/interaction.rs b/crates/ui-egui/tests/it/interaction.rs index 542d66a8a..21e6ca71b 100644 --- a/crates/ui-egui/tests/it/interaction.rs +++ b/crates/ui-egui/tests/it/interaction.rs @@ -9,16 +9,7 @@ use gridcraft_ui_egui::{SheetApp, grid::Geo}; use serde_json::json; fn harness(session: Session) -> egui_kittest::Harness<'static, SheetApp> { - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn blank() -> Session { diff --git a/crates/ui-egui/tests/it/keyboard_shortcuts.rs b/crates/ui-egui/tests/it/keyboard_shortcuts.rs index aa50070bf..fe0cef562 100644 --- a/crates/ui-egui/tests/it/keyboard_shortcuts.rs +++ b/crates/ui-egui/tests/it/keyboard_shortcuts.rs @@ -11,16 +11,7 @@ use serde_json::json; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn book(selected: &str) -> Session { diff --git a/crates/ui-egui/tests/it/keytips_generated.rs b/crates/ui-egui/tests/it/keytips_generated.rs index 438acf71b..60368239a 100644 --- a/crates/ui-egui/tests/it/keytips_generated.rs +++ b/crates/ui-egui/tests/it/keytips_generated.rs @@ -14,15 +14,7 @@ use gridcraft_ui_egui::SheetApp; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_os(OperatingSystem::Nix).with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::common::os_harness(session, OperatingSystem::Nix) } fn blank() -> Session { diff --git a/crates/ui-egui/tests/it/main.rs b/crates/ui-egui/tests/it/main.rs index 48babd2a2..53625015e 100644 --- a/crates/ui-egui/tests/it/main.rs +++ b/crates/ui-egui/tests/it/main.rs @@ -88,6 +88,7 @@ mod show_objects; mod shrink_to_fit; mod sort_dialog_columns; mod status_bar_menu; +mod support; mod symbol_glyphs; mod system_theme; mod tab_split; diff --git a/crates/ui-egui/tests/it/open_encrypted.rs b/crates/ui-egui/tests/it/open_encrypted.rs index 3dbdec30e..e350e4163 100644 --- a/crates/ui-egui/tests/it/open_encrypted.rs +++ b/crates/ui-egui/tests/it/open_encrypted.rs @@ -9,18 +9,7 @@ use serde_json::json; const PW: &str = "synthetic-pw-8842"; fn harness(services: Services) -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::prepare(SheetApp::new(session, services)), - ); - h.run_steps(4); - h + crate::support::services_harness(services, 4) } /// A workbook with 42 in A1, saved as `.xlsx` and encrypted with `PW`. diff --git a/crates/ui-egui/tests/it/outline.rs b/crates/ui-egui/tests/it/outline.rs index db4752d7c..2b075fd26 100644 --- a/crates/ui-egui/tests/it/outline.rs +++ b/crates/ui-egui/tests/it/outline.rs @@ -1,7 +1,7 @@ //! The outline band of grouped rows and columns: − / + and level buttons (#373), and the //! Outline Settings dialog that moves the summary rows above their detail. -use egui::{Event, Modifiers, PointerButton, Pos2, vec2}; +use egui::{Event, Modifiers, PointerButton, Pos2}; use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use gridcraft_ui_egui::outline::{Action, layout}; @@ -12,15 +12,7 @@ type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness() -> Harness { let mut session = Session::new(); session.new_workbook(); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } fn click(h: &mut Harness, pos: Pos2) { diff --git a/crates/ui-egui/tests/it/page_layout_view.rs b/crates/ui-egui/tests/it/page_layout_view.rs index cab751968..d0306d537 100644 --- a/crates/ui-egui/tests/it/page_layout_view.rs +++ b/crates/ui-egui/tests/it/page_layout_view.rs @@ -32,17 +32,11 @@ fn fixture_with(rtl: bool, setup: Option) -> Harness { } session.execute("pageLayout.headerFooter", json!({"header": "&LLeft"})).unwrap(); session.execute("view.pageLayout", json!({})).unwrap(); - let mut h = - crate::common::builder().with_size(vec2(1200.0, 900.0)).with_step_dt(1.0 / 60.0).with_os(egui::os::OperatingSystem::Mac).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::common::harness_with( + crate::common::builder().with_size(vec2(1200.0, 900.0)).with_step_dt(1.0 / 60.0).with_os(egui::os::OperatingSystem::Mac), + crate::common::app(session), + 4, + ) } fn geo(h: &Harness) -> Geo { diff --git a/crates/ui-egui/tests/it/pivot_show_details.rs b/crates/ui-egui/tests/it/pivot_show_details.rs index 81d7574b2..52c76d6dd 100644 --- a/crates/ui-egui/tests/it/pivot_show_details.rs +++ b/crates/ui-egui/tests/it/pivot_show_details.rs @@ -2,7 +2,7 @@ //! Show Details) unless its Enable show details option is off; a label of the report still opens //! the cell for editing. -use egui::{Event, Modifiers, PointerButton, Pos2, vec2}; +use egui::{Event, Modifiers, PointerButton, Pos2}; use gridcraft_engine::Session; use gridcraft_engine::core::CellRef; use gridcraft_ui_egui::{SheetApp, grid::Geo}; @@ -17,15 +17,7 @@ fn harness() -> egui_kittest::Harness<'static, SheetApp> { .execute("insert.pivotTable", json!({"source": "Sheet1!A1:B4", "destination": "Sheet1!D3", "rows": ["Region"], "values": ["Sales"]})) .unwrap(); session.execute("selection.set", json!({"cell": "A1"})).unwrap(); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } fn center(h: &egui_kittest::Harness<'_, SheetApp>, cell: &str) -> Pos2 { diff --git a/crates/ui-egui/tests/it/pivot_show_details_menu.rs b/crates/ui-egui/tests/it/pivot_show_details_menu.rs index dd645c4e2..2747861e6 100644 --- a/crates/ui-egui/tests/it/pivot_show_details_menu.rs +++ b/crates/ui-egui/tests/it/pivot_show_details_menu.rs @@ -1,7 +1,7 @@ //! Right-clicking a PivotTable's value cell offers Show Details in the cell menu (Excel's //! right-click › Show Details); labels of the report and ordinary cells don't offer it. -use egui::{Event, Modifiers, PointerButton, Pos2, vec2}; +use egui::{Event, Modifiers, PointerButton, Pos2}; use egui_kittest::kittest::Queryable as _; use gridcraft_engine::Session; use gridcraft_engine::core::{CellRef, Value}; @@ -17,15 +17,7 @@ fn harness() -> egui_kittest::Harness<'static, SheetApp> { .execute("insert.pivotTable", json!({"source": "Sheet1!A1:B4", "destination": "Sheet1!D3", "rows": ["Region"], "values": ["Sales"]})) .unwrap(); session.execute("selection.set", json!({"cell": "A1"})).unwrap(); - let mut h = crate::common::builder().with_step_dt(1.0 / 60.0).with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::stepped_harness(session) } fn center(h: &egui_kittest::Harness<'_, SheetApp>, cell: &str) -> Pos2 { diff --git a/crates/ui-egui/tests/it/protect_password.rs b/crates/ui-egui/tests/it/protect_password.rs index f77ea1cc1..052fdcbac 100644 --- a/crates/ui-egui/tests/it/protect_password.rs +++ b/crates/ui-egui/tests/it/protect_password.rs @@ -2,25 +2,13 @@ use egui::accesskit::Role; use egui_kittest::kittest::Queryable as _; -use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use serde_json::json; const SECRET: &str = "s3cret"; fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::blank_harness(4) } fn type_password(h: &mut egui_kittest::Harness<'static, SheetApp>) { diff --git a/crates/ui-egui/tests/it/right_to_left.rs b/crates/ui-egui/tests/it/right_to_left.rs index f0703af32..2754a7679 100644 --- a/crates/ui-egui/tests/it/right_to_left.rs +++ b/crates/ui-egui/tests/it/right_to_left.rs @@ -14,16 +14,7 @@ fn harness() -> Harness { session.execute("range.setValues", json!({"range": "A1", "values": [["first", 2], [3, "fourth"]]})).unwrap(); session.execute("view.rightToLeft", json!({"on": true})).unwrap(); session.execute("selection.set", json!({"cell": "B2"})).unwrap(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn geo(h: &Harness) -> Geo { diff --git a/crates/ui-egui/tests/it/sort_dialog_columns.rs b/crates/ui-egui/tests/it/sort_dialog_columns.rs index a6d3b23a8..b6cbb54f6 100644 --- a/crates/ui-egui/tests/it/sort_dialog_columns.rs +++ b/crates/ui-egui/tests/it/sort_dialog_columns.rs @@ -10,16 +10,7 @@ use serde_json::json; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } /// Header row + three rows; the user's cursor sits in column B (Revenue). diff --git a/crates/ui-egui/tests/it/support.rs b/crates/ui-egui/tests/it/support.rs new file mode 100644 index 000000000..0136b3d5e --- /dev/null +++ b/crates/ui-egui/tests/it/support.rs @@ -0,0 +1,41 @@ +//! Constructors for the suite's usual harness shapes. +//! +//! The strict font and lifecycle setup stays in `crate::common`; these wrap it at the sizes and +//! step timings the `it` tests share. Keeping them here (rather than in `common`) leaves the +//! `keytips` test binary's copy of `common` free of helpers only this binary uses. + +use crate::common::{Harness, app, builder, harness_with, prepare}; +use gridcraft_engine::Session; +use gridcraft_ui_egui::{Services, SheetApp}; + +/// A blank workbook session, as most integration tests start. +pub fn blank_session() -> Session { + let mut session = Session::new(); + session.new_workbook(); + session +} + +/// The suite's usual 1200×800 harness around `session`, warmed for `steps` frames. +pub fn harness(session: Session, steps: usize) -> Harness { + harness_with(builder().with_size(egui::vec2(1200.0, 800.0)), app(session), steps) +} + +/// A blank workbook in the suite's usual 1200×800 harness. +pub fn blank_harness(steps: usize) -> Harness { + harness(blank_session(), steps) +} + +/// A 1200×800 harness advancing in 1/60 s frames, for drags and hover sequences. +pub fn stepped_harness(session: Session) -> Harness { + harness_with(builder().with_step_dt(1.0 / 60.0).with_size(egui::vec2(1200.0, 800.0)), app(session), 4) +} + +/// A harness around an app built with the caller's `Services` (e.g. a test inbox). +pub fn services_harness(services: Services, steps: usize) -> Harness { + harness_with(builder().with_size(egui::vec2(1200.0, 800.0)), prepare(SheetApp::new(blank_session(), services)), steps) +} + +/// A harness around an already-prepared `app`, at the suite's usual 1200×800 size. +pub fn app_harness(app: SheetApp, steps: usize) -> Harness { + harness_with(builder().with_size(egui::vec2(1200.0, 800.0)), app, steps) +} diff --git a/crates/ui-egui/tests/it/text_box_editing.rs b/crates/ui-egui/tests/it/text_box_editing.rs index 67b9b0307..799f30cca 100644 --- a/crates/ui-egui/tests/it/text_box_editing.rs +++ b/crates/ui-egui/tests/it/text_box_editing.rs @@ -22,16 +22,11 @@ fn fixture() -> (Harness, u32) { session.execute("selection.set", json!({"cell": "B2"})).unwrap(); let id = session.execute("insert.textBox", json!({"at": "B2", "width": 240, "height": 120, "text": ORIGINAL})).unwrap()["shape"].as_u64().unwrap() as u32; - let mut h = - crate::common::builder().with_size(vec2(1200.0, 800.0)).with_step_dt(1.0 / 60.0).with_os(egui::os::OperatingSystem::Mac).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); + let h = crate::common::harness_with( + crate::common::builder().with_size(vec2(1200.0, 800.0)).with_step_dt(1.0 / 60.0).with_os(egui::os::OperatingSystem::Mac), + crate::common::app(session), + 4, + ); (h, id) } diff --git a/crates/ui-egui/tests/it/touch_pan.rs b/crates/ui-egui/tests/it/touch_pan.rs index b38fec787..1c4960c7b 100644 --- a/crates/ui-egui/tests/it/touch_pan.rs +++ b/crates/ui-egui/tests/it/touch_pan.rs @@ -6,16 +6,7 @@ use gridcraft_engine::core::CellRef; use gridcraft_ui_egui::SheetApp; fn harness(session: Session) -> egui_kittest::Harness<'static, SheetApp> { - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn blank() -> Session { diff --git a/crates/ui-egui/tests/it/trace_navigation.rs b/crates/ui-egui/tests/it/trace_navigation.rs index b0516dbaa..b997b291b 100644 --- a/crates/ui-egui/tests/it/trace_navigation.rs +++ b/crates/ui-egui/tests/it/trace_navigation.rs @@ -9,16 +9,7 @@ use serde_json::json; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::harness(session, 4) } fn active(h: &Harness) -> String { diff --git a/crates/ui-egui/tests/it/translated_form_fields.rs b/crates/ui-egui/tests/it/translated_form_fields.rs index bb64fb233..b6464ab30 100644 --- a/crates/ui-egui/tests/it/translated_form_fields.rs +++ b/crates/ui-egui/tests/it/translated_form_fields.rs @@ -2,24 +2,12 @@ //! and OK/Cancel buttons already were (Page Setup showed "Left margin (in):" in every language). use egui_kittest::kittest::Queryable as _; -use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; use gridcraft_ui_egui::i18n::Language; use serde_json::json; fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - let ctx = ui.ctx().clone(); - app.logic(&ctx); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::support::blank_harness(4) } #[test] diff --git a/crates/ui-egui/tests/it/zoom_dialog.rs b/crates/ui-egui/tests/it/zoom_dialog.rs index a3f7a4623..33ff1bbca 100644 --- a/crates/ui-egui/tests/it/zoom_dialog.rs +++ b/crates/ui-egui/tests/it/zoom_dialog.rs @@ -1,6 +1,5 @@ //! The Zoom dialog stores the Magnification the user picks. -use egui::vec2; use egui_kittest::kittest::Queryable; use gridcraft_engine::Session; use gridcraft_ui_egui::SheetApp; @@ -8,17 +7,7 @@ use gridcraft_ui_egui::control::{Outcome, handle}; use serde_json::{Value as Json, json}; fn harness() -> egui_kittest::Harness<'static, SheetApp> { - let mut session = Session::new(); - session.new_workbook(); - let mut h = crate::common::builder().with_size(vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(&ui.ctx().clone()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(6); - h + crate::support::blank_harness(6) } fn zoom(h: &egui_kittest::Harness<'static, SheetApp>) -> u16 { diff --git a/crates/ui-egui/tests/keytips.rs b/crates/ui-egui/tests/keytips.rs index 7a7fbacf7..b4418018a 100644 --- a/crates/ui-egui/tests/keytips.rs +++ b/crates/ui-egui/tests/keytips.rs @@ -18,15 +18,7 @@ fn harness(session: Session) -> Harness { } fn harness_on(session: Session, os: OperatingSystem) -> Harness { - let mut h = crate::common::builder().with_os(os).with_size(egui::vec2(1200.0, 800.0)).build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::common::os_harness(session, os) } fn blank() -> Session { diff --git a/xtask/src/keytips.rs b/xtask/src/keytips.rs index 7d5b4482f..5b7137455 100644 --- a/xtask/src/keytips.rs +++ b/xtask/src/keytips.rs @@ -365,18 +365,7 @@ use gridcraft_ui_egui::SheetApp; type Harness = egui_kittest::Harness<'static, SheetApp>; fn harness(session: Session) -> Harness { - let mut h = crate::common::builder() - .with_os(OperatingSystem::Nix) - .with_size(egui::vec2(1200.0, 800.0)) - .build_ui_state( - |ui, app: &mut SheetApp| { - app.logic(ui.ctx()); - app.ui(ui); - }, - crate::common::app(session), - ); - h.run_steps(4); - h + crate::common::os_harness(session, OperatingSystem::Nix) } fn blank() -> Session {