use iced::widget::{button, center, text};
use iced::{Element, Point};
use iced_test::simulator;
use snora::{AppLayout, Dialog, Sheet, SheetEdge, Toast, ToastIntent, render};
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)] enum Msg {
BodyPressed,
CloseMenus,
CloseModals,
DialogOk,
SheetAction,
DismissToast(u64),
}
fn btn<'a>(label: &'static str, msg: Msg) -> Element<'a, Msg> {
button(text(label)).on_press(msg).into()
}
#[test]
fn body_button_reachable_without_overlays() {
let layout = AppLayout::new(btn("body", Msg::BodyPressed));
let element = render(layout);
let mut ui = simulator(element);
ui.click("body").expect("body button should be findable");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert_eq!(msgs, vec![Msg::BodyPressed]);
}
#[test]
fn outside_click_on_modal_emits_close_modals() {
let dialog: Dialog<Element<Msg>, Msg> = Dialog::new(btn("OK", Msg::DialogOk));
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.dialog(dialog)
.on_close_modals(Msg::CloseModals);
let element = render(layout);
let mut ui = simulator(element);
ui.point_at(Point::new(4.0, 4.0));
let _ = ui.simulate(iced_test::simulator::click());
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::CloseModals),
"corner click should produce CloseModals; got {msgs:?}",
);
}
#[test]
fn dialog_content_button_reachable() {
let dialog: Dialog<Element<Msg>, Msg> = Dialog::new(center(btn("OK", Msg::DialogOk)).into());
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.dialog(dialog)
.on_close_modals(Msg::CloseModals);
let element = render(layout);
let mut ui = simulator(element);
ui.click("OK").expect("dialog OK button should be findable");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert_eq!(
msgs,
vec![Msg::DialogOk],
"clicking dialog content should produce DialogOk only",
);
}
#[test]
fn no_close_sink_means_no_dismiss_but_content_renders() {
let dialog: Dialog<Element<Msg>, Msg> = Dialog::new(btn("OK", Msg::DialogOk));
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.dialog(dialog);
let element = render(layout);
let mut ui = simulator(element);
ui.point_at(Point::new(4.0, 4.0));
let _ = ui.simulate(iced_test::simulator::click());
let msgs_after_corner: Vec<Msg> = ui.into_messages().collect();
assert!(
!msgs_after_corner.contains(&Msg::CloseModals),
"no close sink → corner click must not produce CloseModals; got {msgs_after_corner:?}",
);
let rebuild: Dialog<Element<Msg>, Msg> = Dialog::new(btn("OK", Msg::DialogOk));
let layout2 = AppLayout::new(btn("body", Msg::BodyPressed)).dialog(rebuild);
let element2 = render(layout2);
let mut ui2 = simulator(element2);
ui2.find("OK").expect("dialog content should still be renderable with no close sink");
}
#[test]
fn toast_dismiss_reachable_above_modal() {
let toast = Toast::new(
7,
ToastIntent::Info,
"Saved",
"All good.",
Msg::DismissToast(7),
);
let dialog: Dialog<Element<Msg>, Msg> = Dialog::new(btn("OK", Msg::DialogOk));
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.dialog(dialog)
.on_close_modals(Msg::CloseModals)
.toasts(vec![toast]);
let element = render(layout);
let mut ui = simulator(element);
ui.click("×").expect("toast close button (×) should be findable above the modal");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::DismissToast(7)),
"toast dismiss should fire even while a modal is present; got {msgs:?}",
);
}
#[test]
fn sheet_content_button_reachable() {
let sheet: Sheet<Element<Msg>, Msg> =
Sheet::new(btn("Sheet action", Msg::SheetAction)).at(SheetEdge::Bottom);
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.sheet(sheet)
.on_close_modals(Msg::CloseModals);
let element = render(layout);
let mut ui = simulator(element);
ui.click("Sheet action").expect("sheet action button should be findable");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert_eq!(
msgs,
vec![Msg::SheetAction],
"clicking sheet content should produce SheetAction only",
);
}
#[test]
fn sheet_end_edge_reachable_under_rtl() {
use snora::LayoutDirection;
let sheet: Sheet<Element<Msg>, Msg> =
Sheet::new(btn("RTL Sheet", Msg::SheetAction)).at(SheetEdge::End);
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.sheet(sheet)
.direction(LayoutDirection::Rtl)
.on_close_modals(Msg::CloseModals);
let element = render(layout);
let mut ui = simulator(element);
ui.find("RTL Sheet")
.expect("sheet content must be findable under RTL direction");
ui.click("RTL Sheet")
.expect("sheet action button should be clickable under RTL");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::SheetAction),
"sheet button must fire SheetAction under RTL layout; got {msgs:?}",
);
}
#[test]
fn toast_dismiss_reachable_under_rtl() {
use snora::{LayoutDirection, ToastPosition};
let toast = Toast::new(
42,
ToastIntent::Success,
"Done",
"Task complete.",
Msg::DismissToast(42),
);
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.toasts(vec![toast])
.toast_position(ToastPosition::TopEnd)
.direction(LayoutDirection::Rtl);
let element = render(layout);
let mut ui = simulator(element);
ui.click("×").expect("toast close button (×) should be findable under RTL");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::DismissToast(42)),
"toast dismiss must fire under RTL direction; got {msgs:?}",
);
}
#[test]
fn outside_click_on_menu_emits_close_menus() {
let menu_el: Element<Msg> = btn("File item", Msg::BodyPressed);
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.header_menu(menu_el)
.on_close_menus(Msg::CloseMenus);
let element = render(layout);
let mut ui = simulator(element);
ui.point_at(Point::new(4.0, 500.0));
let _ = ui.simulate(iced_test::simulator::click());
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::CloseMenus),
"outside click with menu open should produce CloseMenus; got {msgs:?}",
);
}
#[test]
fn dialog_and_sheet_coexist_sheet_content_reachable() {
let dialog: Dialog<Element<Msg>, Msg> = Dialog::new(btn("Dialog btn", Msg::DialogOk));
let sheet: Sheet<Element<Msg>, Msg> =
Sheet::new(btn("Sheet action", Msg::SheetAction)).at(SheetEdge::Bottom);
let layout = AppLayout::new(btn("body", Msg::BodyPressed))
.dialog(dialog)
.sheet(sheet)
.on_close_modals(Msg::CloseModals);
let element = render(layout);
let mut ui = simulator(element);
ui.find("Sheet action")
.expect("sheet content must be findable when both dialog and sheet are present");
ui.click("Sheet action")
.expect("sheet action button should be clickable");
let msgs: Vec<Msg> = ui.into_messages().collect();
assert!(
msgs.contains(&Msg::SheetAction),
"sheet button click must produce SheetAction in coexistence layout; got {msgs:?}",
);
}