Lock the input invariants with web_surface store regressions
Five PerTabSurface tests pin the input contract so future refactors can't silently regress it: - typed_text_enters_pending_input_after_clicked_viewport: typing reaches the sidecar once a click establishes keyboard focus. - scroll_delta_enters_pending_input_after_wheel: scroll deltas combine across multiple wheel events. - viewport_size_changes_after_stable_second_measurement: viewport resize is debounced behind a "same size twice" guard. - scroll_after_click_keeps_keyboard_focus_and_typed_text: the bug fixed last commit cycle — scroll drops the buffered click point but must keep keyboard_focus and buffered keystrokes. - typing_without_a_prior_click_is_rejected: typing without focus returns false, so a future refactor can't accept stray keystrokes. No instrumentation eprintln/log added in production paths (per CLAUDE.md NO LOGGING). cargo test ely_app --bin ely_app: 102 passed.
This commit is contained in:
@@ -49,6 +49,70 @@ fn viewport_size_changes_after_stable_second_measurement() -> Result<(), Box<dyn
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Regression — a wheel scroll between focusing a field and typing
|
||||
/// must not erase keyboard focus or buffered keystrokes.
|
||||
///
|
||||
/// The `record_scroll_delta` path drops `click_point` on purpose
|
||||
/// (its viewport coordinates are stale once the page scrolls) but
|
||||
/// must keep `keyboard_focus` and `typed_text`, so a focused input
|
||||
/// keeps receiving the user's keystrokes after they wheel-scroll.
|
||||
/// Locks the fix from commit fcac326-era input-loss work.
|
||||
#[test]
|
||||
fn scroll_after_click_keeps_keyboard_focus_and_typed_text() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/form")?;
|
||||
let url = tab.url().as_str();
|
||||
|
||||
assert!(store.record_viewport_size(tab.id(), web_bounds()));
|
||||
assert!(store.record_click_point(tab.id(), url, point(px(160.0), px(120.0))));
|
||||
assert!(store.record_typed_text(tab.id(), url, "h"));
|
||||
|
||||
assert!(store.record_scroll_delta(tab.id(), url, point(px(0.0), px(140.0))));
|
||||
|
||||
assert!(
|
||||
store.record_typed_text(tab.id(), url, "i"),
|
||||
"scroll must not erase keyboard focus — typing after a scroll should still buffer",
|
||||
);
|
||||
|
||||
let input = store.take_pending_input(tab.id(), url);
|
||||
|
||||
assert_eq!(
|
||||
input.scroll_delta.map(|delta| (delta.x(), delta.y())),
|
||||
Some((0, 140)),
|
||||
"scroll delta should reach the sidecar",
|
||||
);
|
||||
assert_eq!(input.scroll_offset.y(), 140);
|
||||
assert!(
|
||||
input.click_point.is_none(),
|
||||
"post-scroll click coordinates would land on the wrong DOM node — they must be dropped",
|
||||
);
|
||||
assert_eq!(
|
||||
input.typed_text.as_deref(),
|
||||
Some("hi"),
|
||||
"buffered keystrokes from before AND after the scroll must reach the sidecar",
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Locks the precondition that `record_typed_text` requires a prior
|
||||
/// click to have established keyboard focus. Without this guard, a
|
||||
/// future refactor could silently start buffering stray keystrokes
|
||||
/// against an unfocused tab — and the user would see characters land
|
||||
/// on whichever DOM node Servo last focused, with no visible cause.
|
||||
#[test]
|
||||
fn typing_without_a_prior_click_is_rejected() -> Result<(), Box<dyn Error>> {
|
||||
let mut store = WebSurfaceStore::new();
|
||||
let tab = web_tab("https://example.com/form")?;
|
||||
let url = tab.url().as_str();
|
||||
|
||||
assert!(store.record_viewport_size(tab.id(), web_bounds()));
|
||||
assert!(
|
||||
!store.record_typed_text(tab.id(), url, "x"),
|
||||
"typing must fail until a click establishes keyboard focus on this tab and url",
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn web_bounds() -> Bounds<gpui::Pixels> {
|
||||
Bounds::new(point(px(0.0), px(0.0)), size(px(640.0), px(480.0)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user