use std::cell::RefCell; use std::rc::Rc; use gpui::{ Context, IntoElement, Modifiers, MouseButton, ParentElement as _, Render, Styled as _, TestAppContext, VisualTestContext, Window, div, point, px, }; use gpui_native_core::button::{Button, ButtonVariant}; use gpui_native_core::dialog::Dialog; use gpui_native_theme::Theme; struct Harness { open: bool, alert: bool, changes: Rc>>, } impl Render for Harness { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let changes = self.changes.clone(); let view = cx.entity(); let on_change_view = view.clone(); let close_changes = self.changes.clone(); let close_view = view.clone(); div().size_full().child( Dialog::new("test-dialog") .open(self.open) .alert(self.alert) .title("Delete file?") .on_change(move |next, _, cx| { eprintln!("HARNESS on_change: {next}"); changes.borrow_mut().push(next); on_change_view.update(cx, |harness, cx| { harness.open = next; cx.notify(); }); }) .content(|_, _| { div() .w(px(300.)) .h(px(80.)) .child("This cannot be undone.") .into_any_element() }) .actions(move |_, _| { vec![ Button::new("dialog-cancel") .label("Cancel") .variant(ButtonVariant::Secondary) .on_click({ let close_changes = close_changes.clone(); let close_view = close_view.clone(); move |_, _, cx| { close_changes.borrow_mut().push(false); close_view.update(cx, |harness, cx| { harness.open = false; cx.notify(); }); } }) .into_any_element(), Button::new("dialog-delete") .label("Delete") .variant(ButtonVariant::Destructive) .on_click({ let close_changes = close_changes.clone(); let close_view = close_view.clone(); move |_, _, cx| { close_changes.borrow_mut().push(false); close_view.update(cx, |harness, cx| { harness.open = false; cx.notify(); }); } }) .into_any_element(), ] }), ) } } /// An open 332px-wide dialog centered in the window: the panel spans /// roughly `(794..1126, 448..640)`, so `(100, 100)` is on the scrim and /// the window center is on the panel. fn dialog_window( open: bool, alert: bool, ) -> (TestAppContext, VisualTestContext, Rc>>) { 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 { open, alert, 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 draw(visual: &mut VisualTestContext) { visual.update(|window, cx| { eprintln!("DRAW"); window.draw(cx).clear(cx); }); } fn click(visual: &mut VisualTestContext, position: gpui::Point) { visual.simulate_mouse_down(position, MouseButton::Left, Modifiers::default()); visual.simulate_mouse_up(position, MouseButton::Left, Modifiers::default()); } #[test] fn escape_closes_a_modal_dialog_and_stays_closed() { let (_cx, mut visual, changes) = dialog_window(true, false); visual.simulate_keystrokes("escape"); assert_eq!(*changes.borrow(), vec![false]); draw(&mut visual); // Closed: escape on the inert remainder reports nothing further. visual.simulate_keystrokes("escape"); assert_eq!(*changes.borrow(), vec![false]); } #[test] fn escape_is_inert_on_an_alert() { let (_cx, mut visual, changes) = dialog_window(true, true); visual.simulate_keystrokes("escape"); assert!(changes.borrow().is_empty()); } #[test] fn scrim_click_closes_a_modal_but_not_an_alert() { let (_cx, mut visual, changes) = dialog_window(true, false); click(&mut visual, point(px(100.), px(100.))); assert_eq!(*changes.borrow(), vec![false]); draw(&mut visual); click(&mut visual, point(px(100.), px(100.))); assert_eq!(*changes.borrow(), vec![false]); // The same click on an alert's scrim answers nothing. let (_cx, mut visual, changes) = dialog_window(true, true); click(&mut visual, point(px(100.), px(100.))); assert!(changes.borrow().is_empty()); } #[test] fn clicking_the_panel_does_not_dismiss() { // The window center is where the centered panel sits. let (_cx, mut visual, changes) = dialog_window(true, false); click(&mut visual, point(px(960.), px(540.))); assert!(changes.borrow().is_empty()); } #[test] fn a_closed_dialog_is_inert() { let (_cx, mut visual, changes) = dialog_window(false, false); visual.simulate_keystrokes("escape"); click(&mut visual, point(px(100.), px(100.))); assert!(changes.borrow().is_empty()); }