119 lines
3.8 KiB
Rust
119 lines
3.8 KiB
Rust
use std::{cell::RefCell, rc::Rc};
|
|
|
|
use gpui::{
|
|
Context, IntoElement, MouseButton, ParentElement as _, Render, Styled as _, TestAppContext,
|
|
VisualTestContext, Window, div, point, px,
|
|
};
|
|
use gpui_native_core::select::Select;
|
|
use gpui_native_theme::Theme;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
enum Level {
|
|
Low,
|
|
Mid,
|
|
High,
|
|
}
|
|
|
|
const LEVELS: [(Level, &str); 3] = [
|
|
(Level::Low, "Low"),
|
|
(Level::Mid, "Mid"),
|
|
(Level::High, "High"),
|
|
];
|
|
|
|
type Changes = Rc<RefCell<Vec<Option<Level>>>>;
|
|
|
|
struct Harness {
|
|
value: Option<Level>,
|
|
changes: Changes,
|
|
}
|
|
|
|
impl Render for Harness {
|
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let changes = self.changes.clone();
|
|
let view = cx.entity();
|
|
div().size_full().p_4().child(
|
|
Select::new("level")
|
|
.options(LEVELS)
|
|
.selected(self.value)
|
|
.on_change(move |next, _window, cx| {
|
|
changes.borrow_mut().push(next);
|
|
view.update(cx, |harness, cx| {
|
|
harness.value = next;
|
|
cx.notify();
|
|
});
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn level_window() -> (TestAppContext, VisualTestContext, Changes) {
|
|
let mut cx = TestAppContext::single();
|
|
cx.update(Theme::init);
|
|
let changes = Rc::new(RefCell::new(Vec::new()));
|
|
let harness_changes = changes.clone();
|
|
let window = cx.add_window(move |_, _| Harness {
|
|
value: None,
|
|
changes: harness_changes,
|
|
});
|
|
let mut visual = VisualTestContext::from_window(window.into(), &cx);
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
(cx, visual, changes)
|
|
}
|
|
|
|
fn click(visual: &mut VisualTestContext, position: gpui::Point<gpui::Pixels>) {
|
|
visual.simulate_mouse_down(position, MouseButton::Left, gpui::Modifiers::default());
|
|
visual.simulate_mouse_up(position, MouseButton::Left, gpui::Modifiers::default());
|
|
}
|
|
|
|
/// The three option rows must answer a pointer press wherever they were laid
|
|
/// out — a popup that clips its last item never does. Row positions come from
|
|
/// the rendered bounds, so the stated menu row metric can change freely.
|
|
#[test]
|
|
fn every_option_row_answers_the_pointer() {
|
|
let (_cx, mut visual, changes) = level_window();
|
|
|
|
// Open once to measure where the rows were actually drawn.
|
|
click(&mut visual, point(px(100.), px(31.)));
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
let centers: Vec<gpui::Point<gpui::Pixels>> = (0..3)
|
|
.map(|index| {
|
|
let selector: &'static str = Box::leak(format!("menu-item-{index}").into_boxed_str());
|
|
let row = visual
|
|
.debug_bounds(selector)
|
|
.unwrap_or_else(|| panic!("row {index} should have been laid out"));
|
|
point(
|
|
row.left() + row.size.width / 2.0,
|
|
row.top() + row.size.height / 2.0,
|
|
)
|
|
})
|
|
.collect();
|
|
|
|
// Close again; each iteration below opens the popup fresh.
|
|
click(&mut visual, point(px(100.), px(31.)));
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
|
|
let expected = [(Level::Low, 0), (Level::Mid, 1), (Level::High, 2)];
|
|
for (value, index) in expected {
|
|
// Choosing the previous row closed the popup; reopen it.
|
|
click(&mut visual, point(px(100.), px(31.)));
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
click(&mut visual, centers[index]);
|
|
visual.update(|window, cx| {
|
|
window.draw(cx).clear(cx);
|
|
});
|
|
assert_eq!(
|
|
changes.borrow().last(),
|
|
Some(&Some(value)),
|
|
"pressing {value:?}'s row must choose it"
|
|
);
|
|
}
|
|
}
|