#[macro_export]
macro_rules! test_helpers {
($message_type:ty) => {
type ViewFn = Box<dyn Fn() -> iced::Element<'static, $message_type>>;
#[derive(Clone)]
struct App {
view_fn: std::rc::Rc<ViewFn>,
}
impl App {
fn new<F>(view_fn: F) -> (Self, iced::Task<$message_type>)
where
F: Fn() -> iced::Element<'static, $message_type> + 'static,
{
(
App {
view_fn: std::rc::Rc::new(Box::new(view_fn)),
},
iced::Task::none(),
)
}
#[allow(unused_variables, dead_code)]
fn update(&mut self, message: $message_type) {
}
fn view(&self) -> iced::Element<'static, $message_type> {
(self.view_fn)()
}
}
#[allow(dead_code)]
fn simulator(app: &App) -> iced_test::Simulator<'static, $message_type> {
iced_test::Simulator::with_settings(iced::Settings::default(), app.view())
}
#[allow(dead_code)]
fn run_test<F>(view_fn: F)
where
F: Fn() -> iced::Element<'static, $message_type> + 'static,
{
let (app, _) = App::new(view_fn);
let _ui = iced_test::Simulator::with_settings(iced::Settings::default(), app.view());
}
#[allow(dead_code)]
fn run_test_and_find<F>(view_fn: F, text: &str)
where
F: Fn() -> iced::Element<'static, $message_type> + 'static,
{
let (app, _) = App::new(view_fn);
let mut ui = iced_test::Simulator::with_settings(iced::Settings::default(), app.view());
assert!(
ui.find(text).is_ok(),
"Failed to find text '{}' in widget",
text
);
}
#[allow(dead_code)]
fn simulate_mouse_click(
ui: &mut iced_test::Simulator<'_, $message_type>,
position: iced_core::Point,
button: iced_core::mouse::Button,
) {
use iced::Event;
use iced_core::mouse;
ui.simulate([
Event::Mouse(mouse::Event::CursorMoved { position }),
Event::Mouse(mouse::Event::ButtonPressed(button)),
]);
}
#[allow(dead_code)]
fn simulate_mouse_click_at(
ui: &mut iced_test::Simulator<'_, $message_type>,
x: f32,
y: f32,
button: iced_core::mouse::Button,
) {
simulate_mouse_click(ui, iced_core::Point::new(x, y), button);
}
#[allow(dead_code)]
fn simulate_left_click_at(
ui: &mut iced_test::Simulator<'_, $message_type>,
x: f32,
y: f32,
) {
simulate_mouse_click_at(ui, x, y, iced_core::mouse::Button::Left);
}
#[allow(dead_code)]
fn simulate_right_click_at(
ui: &mut iced_test::Simulator<'_, $message_type>,
x: f32,
y: f32,
) {
simulate_mouse_click_at(ui, x, y, iced_core::mouse::Button::Right);
}
#[allow(dead_code)]
fn simulate_touch(
ui: &mut iced_test::Simulator<'_, $message_type>,
position: iced_core::Point,
) {
use iced::Event;
use iced_core::touch;
ui.simulate([Event::Touch(touch::Event::FingerPressed {
id: touch::Finger(0),
position,
})]);
}
#[allow(dead_code)]
fn simulate_touch_at(ui: &mut iced_test::Simulator<'_, $message_type>, x: f32, y: f32) {
simulate_touch(ui, iced_core::Point::new(x, y));
}
#[allow(dead_code)]
fn outside_position() -> iced_core::Point {
iced_core::Point::new(1000.0, 1000.0)
}
#[allow(dead_code)]
fn assert_message_received<F>(
ui: iced_test::Simulator<'_, $message_type>,
app: &mut App,
mut predicate: F,
error_msg: &str,
) where
F: FnMut(&$message_type) -> bool,
{
let mut received = false;
for message in ui.into_messages() {
if predicate(&message) {
received = true;
}
app.update(message);
}
assert!(received, "{}", error_msg);
}
#[allow(dead_code)]
fn check_message_received<F>(
ui: iced_test::Simulator<'_, $message_type>,
app: &mut App,
mut predicate: F,
) -> bool
where
F: FnMut(&$message_type) -> bool,
{
let mut received = false;
for message in ui.into_messages() {
if predicate(&message) {
received = true;
}
app.update(message);
}
received
}
#[allow(dead_code)]
fn process_messages(ui: iced_test::Simulator<'_, $message_type>, app: &mut App) {
for message in ui.into_messages() {
app.update(message);
}
}
#[allow(dead_code, unreachable_code)]
fn collect_messages<F>(
ui: iced_test::Simulator<'_, $message_type>,
app: &mut App,
mut predicate: F,
) -> Vec<$message_type>
where
F: FnMut(&$message_type) -> bool,
$message_type: Clone,
{
let mut collected = Vec::new();
for message in ui.into_messages() {
if predicate(&message) {
collected.push(message.clone());
}
app.update(message);
}
collected
}
#[allow(dead_code)]
fn assert_snapshot_matches(
ui: &mut iced_test::Simulator<'_, $message_type>,
baseline_name: &str,
) -> Result<(), iced_test::Error> {
#[cfg(any(target_os = "windows", target_os = "macos"))]
{
let is_ci = std::env::var("CI").is_ok() || std::env::var("GITHUB_ACTIONS").is_ok();
if is_ci {
println!(
"Skipping snapshot comparison on {} in CI environment",
if cfg!(target_os = "windows") {
"Windows"
} else {
"macOS"
}
);
return Ok(());
}
}
let snapshot = ui.snapshot(&iced::Theme::Light)?;
let baseline_path = std::path::Path::new(baseline_name);
assert!(
snapshot.matches_hash(baseline_name)?,
"Snapshot hash mismatch for: {}",
baseline_name
);
assert!(
snapshot.matches_image(baseline_path)?,
"Snapshot image mismatch for: {}",
baseline_name
);
Ok(())
}
#[allow(dead_code)]
fn assert_snapshot_hash_matches(
ui: &mut iced_test::Simulator<'_, $message_type>,
baseline_name: &str,
) -> Result<(), iced_test::Error> {
let snapshot = ui.snapshot(&iced::Theme::Light)?;
assert!(
snapshot.matches_hash(baseline_name)?,
"Snapshot hash mismatch for: {}",
baseline_name
);
Ok(())
}
};
}