2024-12-03 22:03:06 +01:00
|
|
|
//! Test your `iced` applications in headless mode.
|
2024-12-17 04:13:19 +01:00
|
|
|
//!
|
|
|
|
|
//! # Basic Usage
|
|
|
|
|
//! Let's assume we want to test [the classical counter interface].
|
|
|
|
|
//!
|
|
|
|
|
//! First, we will want to create a [`Simulator`] of our interface:
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust,no_run
|
|
|
|
|
//! # struct Counter { value: i64 }
|
|
|
|
|
//! # impl Counter {
|
|
|
|
|
//! # pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }
|
|
|
|
|
//! # }
|
|
|
|
|
//! use iced_test::simulator;
|
|
|
|
|
//!
|
|
|
|
|
//! let mut counter = Counter { value: 0 };
|
|
|
|
|
//! let mut ui = simulator(counter.view());
|
|
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! Now we can simulate a user interacting with our interface. Let's use [`Simulator::click`] to click
|
|
|
|
|
//! the counter buttons:
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust,no_run
|
|
|
|
|
//! # struct Counter { value: i64 }
|
|
|
|
|
//! # impl Counter {
|
|
|
|
|
//! # pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }
|
|
|
|
|
//! # }
|
|
|
|
|
//! # use iced_test::simulator;
|
|
|
|
|
//! #
|
|
|
|
|
//! # let mut counter = Counter { value: 0 };
|
|
|
|
|
//! # let mut ui = simulator(counter.view());
|
|
|
|
|
//!
|
2025-05-29 16:34:44 +02:00
|
|
|
//! let _ = ui.click("+");
|
|
|
|
|
//! let _ = ui.click("+");
|
|
|
|
|
//! let _ = ui.click("-");
|
2024-12-17 04:13:19 +01:00
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! [`Simulator::click`] takes a [`Selector`]. A [`Selector`] describes a way to query the widgets of an interface. In this case,
|
|
|
|
|
//! [`selector::text`] lets us select a widget by the text it contains.
|
|
|
|
|
//!
|
2024-12-17 04:32:49 +01:00
|
|
|
//! We can now process any messages produced by these interactions and then assert that the final value of our counter is
|
2024-12-17 04:13:19 +01:00
|
|
|
//! indeed `1`!
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust,no_run
|
|
|
|
|
//! # struct Counter { value: i64 }
|
|
|
|
|
//! # impl Counter {
|
|
|
|
|
//! # pub fn update(&mut self, message: ()) {}
|
|
|
|
|
//! # pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }
|
|
|
|
|
//! # }
|
|
|
|
|
//! # use iced_test::simulator;
|
|
|
|
|
//! #
|
|
|
|
|
//! # let mut counter = Counter { value: 0 };
|
|
|
|
|
//! # let mut ui = simulator(counter.view());
|
|
|
|
|
//! #
|
2025-05-29 16:34:44 +02:00
|
|
|
//! # let _ = ui.click("+");
|
|
|
|
|
//! # let _ = ui.click("+");
|
|
|
|
|
//! # let _ = ui.click("-");
|
2024-12-17 04:13:19 +01:00
|
|
|
//! #
|
|
|
|
|
//! for message in ui.into_messages() {
|
|
|
|
|
//! counter.update(message);
|
|
|
|
|
//! }
|
|
|
|
|
//!
|
|
|
|
|
//! assert_eq!(counter.value, 1);
|
|
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! We can even rebuild the interface to make sure the counter _displays_ the proper value with [`Simulator::find`]:
|
|
|
|
|
//!
|
|
|
|
|
//! ```rust,no_run
|
|
|
|
|
//! # struct Counter { value: i64 }
|
|
|
|
|
//! # impl Counter {
|
|
|
|
|
//! # pub fn view(&self) -> iced_runtime::core::Element<(), iced_runtime::core::Theme, iced_renderer::Renderer> { unimplemented!() }
|
|
|
|
|
//! # }
|
|
|
|
|
//! # use iced_test::simulator;
|
|
|
|
|
//! #
|
|
|
|
|
//! # let mut counter = Counter { value: 0 };
|
|
|
|
|
//! let mut ui = simulator(counter.view());
|
|
|
|
|
//!
|
2025-05-29 16:34:44 +02:00
|
|
|
//! assert!(ui.find("1").is_ok(), "Counter should display 1!");
|
2024-12-17 04:13:19 +01:00
|
|
|
//! ```
|
|
|
|
|
//!
|
|
|
|
|
//! And that's it! That's the gist of testing `iced` applications!
|
|
|
|
|
//!
|
|
|
|
|
//! [`Simulator`] contains additional operations you can use to simulate more interactions—like [`tap_key`](Simulator::tap_key) or
|
|
|
|
|
//! [`typewrite`](Simulator::typewrite)—and even perform [_snapshot testing_](Simulator::snapshot)!
|
|
|
|
|
//!
|
|
|
|
|
//! [the classical counter interface]: https://book.iced.rs/architecture.html#dissecting-an-interface
|
2025-05-29 16:34:44 +02:00
|
|
|
#![allow(missing_docs)]
|
2025-05-31 04:34:54 +02:00
|
|
|
use iced_program as program;
|
2024-12-03 22:03:06 +01:00
|
|
|
use iced_renderer as renderer;
|
|
|
|
|
use iced_runtime as runtime;
|
|
|
|
|
use iced_runtime::core;
|
|
|
|
|
|
2025-05-31 04:34:54 +02:00
|
|
|
pub mod emulator;
|
2025-08-15 21:22:41 +02:00
|
|
|
pub mod ice;
|
2025-05-29 16:34:44 +02:00
|
|
|
pub mod instruction;
|
|
|
|
|
pub mod selector;
|
|
|
|
|
pub mod simulator;
|
2024-12-14 03:49:24 +01:00
|
|
|
|
2025-05-29 16:34:44 +02:00
|
|
|
mod error;
|
2024-12-06 04:06:41 +01:00
|
|
|
|
2025-05-31 05:50:25 +02:00
|
|
|
pub use emulator::Emulator;
|
2025-05-29 16:34:44 +02:00
|
|
|
pub use error::Error;
|
2025-08-15 21:22:41 +02:00
|
|
|
pub use ice::Ice;
|
2025-05-29 16:34:44 +02:00
|
|
|
pub use instruction::Instruction;
|
|
|
|
|
pub use selector::Selector;
|
|
|
|
|
pub use simulator::{Simulator, simulator};
|