Files
gpui-native-kit/crates/core/tests/scroll_area.rs
T
2026-10-30 13:50:00 +07:00

151 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use gpui::{
Context, IntoElement, Modifiers, ParentElement as _, Render, ScrollDelta, ScrollEvent,
ScrollHandle, SharedString, Styled as _, TestAppContext, VisualTestContext, Window, div, point,
px,
};
use gpui_native_core::scroll_area::ScrollArea;
use gpui_native_theme::Theme;
struct Harness {
scroll: ScrollHandle,
rows: usize,
}
impl Render for Harness {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div().size_full().child(
ScrollArea::new("test-scroll")
.handle(self.scroll.clone())
.h(px(200.))
.w(px(300.))
.child(div().flex().flex_col().children((0..self.rows).map(|row| {
div()
.h(px(20.))
.child(SharedString::from(format!("row {row}")))
}))),
)
}
}
/// A 300×200 scroll area over `rows` 20px rows, with the handle the test
/// can inspect directly.
fn scroll_area_window(rows: usize) -> (TestAppContext, VisualTestContext, ScrollHandle) {
let mut cx = TestAppContext::single();
cx.update(Theme::init);
let handle = ScrollHandle::new();
let handle_for_view = handle.clone();
let window = cx.add_window(move |_, _| Harness {
scroll: handle_for_view,
rows,
});
let mut visual = VisualTestContext::from_window(window.into(), &cx);
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
(cx, visual, handle)
}
#[test]
fn wheel_scrolling_moves_the_offset_and_stays_inside_the_content() {
let (_cx, mut visual, handle) = scroll_area_window(30);
// 30 rows × 20px = 600px of content in a 200px viewport.
visual.simulate_event(ScrollEvent {
position: point(px(100.), px(100.)),
delta: ScrollDelta::Pixels(point(px(0.), px(-60.))),
modifiers: Modifiers::default(),
..Default::default()
});
let offset = handle.offset().y;
assert_eq!(offset, px(-60.));
// Wheeling far past the end clamps to the content.
for _ in 0..10 {
visual.simulate_event(ScrollEvent {
position: point(px(100.), px(100.)),
delta: ScrollDelta::Pixels(point(px(0.), px(-60.))),
modifiers: Modifiers::default(),
..Default::default()
});
}
// max_offset = 600 - 200 = 400.
assert_eq!(handle.offset().y, px(-400.));
}
#[test]
fn the_content_starts_unscrolled_and_horizontal_axes_scroll_x() {
let (_cx, mut visual, handle) = scroll_area_window(30);
assert_eq!(handle.offset(), gpui::point(px(0.), px(0.)));
// A vertical-only area ignores horizontal wheel deltas.
visual.simulate_event(ScrollEvent {
position: point(px(100.), px(100.)),
delta: ScrollDelta::Pixels(point(px(-60.), px(0.))),
modifiers: Modifiers::default(),
..Default::default()
});
assert_eq!(handle.offset().x, px(0.));
}
#[test]
fn the_thumb_paints_when_the_content_overflows() {
let (_cx, _visual, handle) = scroll_area_window(30);
// 30 rows × 20px in a 200px viewport: the thumb has something to report.
assert!(handle.max_offset().y > px(0.));
}
/// The gallery's exact shell: a window-filling root, a window-filling scroll
/// area over padded flex-column content that towers past the viewport.
struct GalleryShell {
scroll: ScrollHandle,
}
impl Render for GalleryShell {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div().size_full().child(
ScrollArea::new("gallery-scroll")
.handle(self.scroll.clone())
.size_full()
.child(
div()
.p_6()
.flex()
.flex_col()
.gap_5()
.children((0..12).map(|section| {
div()
.h(px(220.))
.child(SharedString::from(format!("section {section}")))
})),
),
)
}
}
#[test]
fn a_gallery_style_window_fill_scroll_area_scrolls_tall_flex_content() {
let mut cx = TestAppContext::single();
cx.update(Theme::init);
let handle = ScrollHandle::new();
let handle_for_view = handle.clone();
let window = cx.add_window(move |_, _| GalleryShell {
scroll: handle_for_view,
});
let mut visual = VisualTestContext::from_window(window.into(), &cx);
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
// 12 sections × 220px + padding towers past the window; a wheel event
// over the middle of the viewport must scroll the root area.
visual.simulate_event(ScrollEvent {
position: point(px(300.), px(300.)),
delta: ScrollDelta::Pixels(point(px(0.), px(-60.))),
modifiers: Modifiers::default(),
..Default::default()
});
assert_eq!(handle.offset().y, px(-60.));
assert!(handle.max_offset().y > px(1000.));
}