use gpui::{
Focusable, Modifiers, MouseButton, Point, TestAppContext, VisualTestContext, point, px, size,
};
use ui::{
menu::Item,
menubar::{self, Menu, Menubar},
};
const RECENT: usize = 1;
const WIDTH: gpui::Pixels = px(900.0);
const HEIGHT: gpui::Pixels = px(600.0);
const SWEEP: f32 = 2.0;
fn menus() -> Vec<Menu> {
vec![Menu::new(
"File",
vec![
Item::action("New Window").with_keystroke("⌘N"),
Item::submenu(
"Open Recent",
vec![
Item::action("bezel.md"),
Item::Separator,
Item::action("Clear Menu"),
],
),
Item::Separator,
Item::action("Close").disabled(),
],
)]
}
fn open(cx: &mut TestAppContext) -> (gpui::Entity<Menubar>, VisualTestContext) {
cx.update(|cx| {
theme::Theme::install(theme::Appearance::Dark, cx);
menubar::init(cx);
});
let window = cx.add_window(|_, cx| Menubar::new(menus(), cx));
let bar = window.root(cx).unwrap();
let mut visual = VisualTestContext::from_window(window.into(), cx);
visual.simulate_resize(size(WIDTH, HEIGHT));
visual.update(|window, cx| {
let handle = bar.read(cx).focus_handle(cx);
window.focus(&handle, cx);
});
visual.simulate_keystrokes("enter");
visual.run_until_parked();
(bar, visual)
}
fn cursor(bar: &gpui::Entity<Menubar>, cx: &mut VisualTestContext) -> (Vec<usize>, Option<usize>) {
cx.update(|_, cx| {
let cursor = bar.read(cx).cursor();
(cursor.open().to_vec(), cursor.row())
})
}
fn move_to(cx: &mut VisualTestContext, at: Point<gpui::Pixels>) {
cx.simulate_mouse_move(at, MouseButton::Left, Modifiers::default());
}
fn submenu_row_y(bar: &gpui::Entity<Menubar>, cx: &mut VisualTestContext) -> gpui::Pixels {
assert_eq!(
cursor(bar, cx),
(vec![], None),
"the menu opens with nothing lit"
);
for step in 0..(f32::from(HEIGHT) / SWEEP) as usize {
let y = px(step as f32 * SWEEP);
move_to(cx, point(px(24.0), y));
if cursor(bar, cx).0 == [RECENT] {
return y;
}
}
panic!("never found the submenu row by sweeping the card");
}
fn probe_right(
bar: &gpui::Entity<Menubar>,
cx: &mut VisualTestContext,
y: gpui::Pixels,
) -> Option<(Point<gpui::Pixels>, Option<usize>)> {
(0..(f32::from(WIDTH) / SWEEP) as usize).find_map(|step| {
let at = point(px(step as f32 * SWEEP), y);
move_to(cx, at);
let (open, row) = cursor(bar, cx);
(open == [RECENT] && row.is_some()).then_some((at, row))
})
}
#[gpui::test]
fn the_panel_paints_where_the_pointer_can_reach_it(cx: &mut TestAppContext) {
let (bar, mut cx) = open(cx);
let y = submenu_row_y(&bar, &mut cx);
assert_eq!(
probe_right(&bar, &mut cx, y).map(|(_, row)| row),
Some(Some(0)),
"the panel never answered the pointer to the right of the row it hangs on"
);
}
#[gpui::test]
fn a_row_in_the_panel_answers_a_click(cx: &mut TestAppContext) {
let (bar, mut cx) = open(cx);
let y = submenu_row_y(&bar, &mut cx);
let (at, _) = probe_right(&bar, &mut cx, y).expect("no row in the panel");
cx.simulate_click(at, Modifiers::default());
cx.run_until_parked();
assert!(
cx.update(|_, cx| bar.read(cx).open_menu().is_none()),
"choosing a row in a submenu closes the bar"
);
}
#[gpui::test]
fn the_arrows_walk_into_the_panel_and_back_out(cx: &mut TestAppContext) {
let (bar, mut cx) = open(cx);
cx.simulate_keystrokes("down down right");
assert_eq!(cursor(&bar, &mut cx), (vec![RECENT], Some(0)));
cx.simulate_keystrokes("left");
assert_eq!(cursor(&bar, &mut cx), (vec![], Some(RECENT)));
cx.simulate_keystrokes("enter");
assert_eq!(cursor(&bar, &mut cx), (vec![RECENT], Some(0)));
assert!(cx.update(|_, cx| bar.read(cx).open_menu().is_some()));
cx.simulate_keystrokes("escape");
assert_eq!(cursor(&bar, &mut cx), (vec![], Some(RECENT)));
cx.simulate_keystrokes("escape");
assert!(cx.update(|_, cx| bar.read(cx).open_menu().is_none()));
}