From 61bcf0f506677def7ebc460aaf8780ade6b96226 Mon Sep 17 00:00:00 2001 From: Chad Elliott Date: Fri, 30 Oct 2026 01:01:56 -0500 Subject: [PATCH] test(ui-egui): drop_import's launch list waits for its library checks before a click (#3368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The launch list's rows say "Checking…" until a worker answers; the answer drops that line, the centred window shrinks and its buttons move. draw_launch_list only waited for the list to be drawn, so on a loaded runner the answer could land between a click's press and release and ui.clickWidget refused it ("moved before its release"), as on a windows-latest run of a_queued_photo_drop_survives_the_choosers_new_library_prompt_and_cancel. The helper now waits until every row is answered and the window holds still, as the launch_library tests already do. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/tests/drop_import.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/tests/drop_import.rs b/crates/ui-egui/src/tests/drop_import.rs index 3d8031a69..80c0b5462 100644 --- a/crates/ui-egui/src/tests/drop_import.rs +++ b/crates/ui-egui/src/tests/drop_import.rs @@ -131,7 +131,10 @@ fn app_with_library(dir: &Scratch) -> Headless { } /// Draw the launch list (`over_open_library`: Alt-at-launch over the library that opened, else the -/// list with no library behind it). +/// list with no library behind it), then wait until it holds still. Each recent library's row says +/// "Checking…" until a worker answers; the answer drops that line, so the centred window shrinks and +/// its buttons move. A click aimed before then can find its button gone from under the pointer by +/// the release, and `ui.clickWidget` refuses it. fn draw_launch_list(h: &mut Headless, over_open_library: bool) { let mut problem = crate::panels::library_problem::LibraryProblem::choose_later(&h.app.ui.settings); if over_open_library && let Some(c) = problem.chooser.as_mut() { @@ -139,6 +142,26 @@ fn draw_launch_list(h: &mut Headless, over_open_library: bool) { } h.app.library_problem = Some(problem); assert!(h.step_until(T, |h| h.app.widgets.iter().any(|(w, _)| w == "button:libraryOpen")), "the launch list is drawn"); + let answered = + |h: &Headless| h.app.library_problem.as_ref().and_then(|p| p.chooser.as_ref()).is_some_and(|c| c.libraries.iter().all(|l| !l.checking)); + assert!(h.step_until(T, answered), "every recent library is checked"); + wait_until_still(h, "button:libraryOpen"); +} + +/// Run frames until widget `id` keeps its rect from one frame to the next (an anchored window +/// takes a frame to move to its new size). +fn wait_until_still(h: &mut Headless, id: &str) { + let rect = |h: &Headless| h.app.widgets.iter().find(|(w, _)| w == id).map(|(_, r)| *r); + let mut last = rect(h); + for _ in 0..60 { + h.step(); + let now = rect(h); + if now.is_some() && now == last { + return; + } + last = now; + } + panic!("{id} never held still"); } /// The launch list as Alt-at-launch shows it over the library that opened.