Struct masonry::testing::TestHarness
source · pub struct TestHarness { /* private fields */ }
Expand description
A safe headless environment to test widgets in.
TestHarness
is a type that simulates an AppRoot
with a single window.
§Workflow
One of the main goals of masonry is to provide primitives that allow application developers to test their app in a convenient and intuitive way. The basic testing workflow is as follows:
- Create a harness with some widget.
- Send events to the widget as if you were a user interacting with a window. (Lifecycle and layout passes are handled automatically.)
- Check that the state of the widget graph matches what you expect.
You can do that last part in a few different ways. You can get a WidgetRef
to
a specific widget through methods like try_get_widget
. WidgetRef
implements
Debug
, so you can check the state of an entire tree with something like the insta
crate.
You can also render the widget tree directly with the render
method. Masonry also
provides the [assert_render_snapshot
] macro, which performs snapshot testing on the
rendered widget tree automatically.
§Fidelity
TestHarness
tries to act like the normal masonry environment. For instance, it will dispatch every Command
sent during event handling, handle lifecycle methods, etc.
The passage of time is simulated with the move_timers_forward
methods. (TODO -
Doesn’t move animations forward.)
(TODO - ExtEvents aren’t handled.)
(TODO - Painting invalidation might not be accurate.)
One minor difference is that layout is always calculated after every event, whereas in normal execution it is only calculated before paint. This might be create subtle differences in cases where timers are programmed to fire at the same time: in normal execution, they’ll execute back-to-back; in the harness, they’ll be separated with layout calls.
Also, paint only happens when the user explicitly calls rendering methods, whereas in a normal applications you could reasonably expect multiple paint calls between eg any two clicks.
§Example
use insta::assert_debug_snapshot;
use masonry::widget::Button;
use masonry::Action;
use masonry::assert_render_snapshot;
use masonry::testing::widget_ids;
use masonry::testing::TestHarness;
use masonry::testing::TestWidgetExt;
use masonry::theme::PRIMARY_LIGHT;
#[test]
fn simple_button() {
let [button_id] = widget_ids();
let widget = Button::new("Hello").with_id(button_id);
let mut harness = TestHarness::create(widget);
assert_debug_snapshot!(harness.root_widget());
assert_render_snapshot!(harness, "hello");
assert_eq!(harness.pop_action(), None);
harness.mouse_click_on(button_id);
assert_eq!(
harness.pop_action(),
Some((Action::ButtonPressed, button_id))
);
}
Implementations§
source§impl TestHarness
impl TestHarness
sourcepub fn create(root_widget: impl Widget) -> Self
pub fn create(root_widget: impl Widget) -> Self
Builds harness with given root widget.
Window size will be HARNESS_DEFAULT_SIZE
.
Background color will be [HARNESS_DEFAULT_BACKGROUND_COLOR
].
sourcepub fn create_with_size(root_widget: impl Widget, window_size: Size) -> Self
pub fn create_with_size(root_widget: impl Widget, window_size: Size) -> Self
Builds harness with given root widget and window size.
sourcepub fn create_with(
root_widget: impl Widget,
window_size: Size,
background_color: Color
) -> Self
pub fn create_with( root_widget: impl Widget, window_size: Size, background_color: Color ) -> Self
Builds harness with given root widget, canvas size and background color.
sourcepub fn process_window_event(&mut self, event: WindowEvent) -> Handled
pub fn process_window_event(&mut self, event: WindowEvent) -> Handled
Send an event to the widget.
If this event triggers lifecycle events, they will also be dispatched, as will any resulting commands. Commands created as a result of this event will also be dispatched.
sourcepub fn process_pointer_event(&mut self, event: PointerEvent) -> Handled
pub fn process_pointer_event(&mut self, event: PointerEvent) -> Handled
Send an event to the widget.
If this event triggers lifecycle events, they will also be dispatched, as will any resulting commands. Commands created as a result of this event will also be dispatched.
sourcepub fn process_text_event(&mut self, event: TextEvent) -> Handled
pub fn process_text_event(&mut self, event: TextEvent) -> Handled
Send an event to the widget.
If this event triggers lifecycle events, they will also be dispatched, as will any resulting commands. Commands created as a result of this event will also be dispatched.
sourcepub fn render(&mut self) -> RgbaImage
pub fn render(&mut self) -> RgbaImage
Create a bitmap (an array of pixels), paint the window and return the bitmap as an 8-bits-per-channel RGB image.
sourcepub fn mouse_move(&mut self, pos: impl Into<Point>)
pub fn mouse_move(&mut self, pos: impl Into<Point>)
Move an internal mouse state, and send a MouseMove event to the window.
Send a MouseDown event to the window.
Send a MouseUp event to the window.
sourcepub fn mouse_wheel(&mut self, wheel_delta: Vec2)
pub fn mouse_wheel(&mut self, wheel_delta: Vec2)
Send a Wheel event to the window
sourcepub fn mouse_click_on(&mut self, id: WidgetId)
pub fn mouse_click_on(&mut self, id: WidgetId)
Send events that lead to a given widget being clicked.
Combines mouse_move
, mouse_button_press
, and mouse_button_release
.
sourcepub fn mouse_move_to(&mut self, id: WidgetId)
pub fn mouse_move_to(&mut self, id: WidgetId)
Use mouse_move
to set the internal mouse pos to the center of the given widget.
pub fn keyboard_type_chars(&mut self, text: &str)
sourcepub fn root_widget(&self) -> WidgetRef<'_, dyn Widget>
pub fn root_widget(&self) -> WidgetRef<'_, dyn Widget>
Return the root widget.
sourcepub fn get_widget(&self, id: WidgetId) -> WidgetRef<'_, dyn Widget>
pub fn get_widget(&self, id: WidgetId) -> WidgetRef<'_, dyn Widget>
sourcepub fn try_get_widget(&self, id: WidgetId) -> Option<WidgetRef<'_, dyn Widget>>
pub fn try_get_widget(&self, id: WidgetId) -> Option<WidgetRef<'_, dyn Widget>>
Try to return the widget with the given id.
sourcepub fn focused_widget(&self) -> Option<WidgetRef<'_, dyn Widget>>
pub fn focused_widget(&self) -> Option<WidgetRef<'_, dyn Widget>>
Return the widget that receives keyboard events.
sourcepub fn inspect_widgets(
&mut self,
f: impl Fn(WidgetRef<'_, dyn Widget>) + 'static
)
pub fn inspect_widgets( &mut self, f: impl Fn(WidgetRef<'_, dyn Widget>) + 'static )
Call the provided visitor on every widget in the widget tree.
sourcepub fn edit_root_widget<R>(
&mut self,
f: impl FnOnce(WidgetMut<'_, Box<dyn Widget>>) -> R
) -> R
pub fn edit_root_widget<R>( &mut self, f: impl FnOnce(WidgetMut<'_, Box<dyn Widget>>) -> R ) -> R
Get a WidgetMut
to the root widget.
Because of how WidgetMut
works, it can only be passed to a user-provided callback.
sourcepub fn pop_action(&mut self) -> Option<(Action, WidgetId)>
pub fn pop_action(&mut self) -> Option<(Action, WidgetId)>
Pop next action from the queue
Note: Actions are still a WIP feature.
sourcepub fn check_render_snapshot(
&mut self,
manifest_dir: &str,
test_file_path: &str,
test_module_path: &str,
test_name: &str
)
pub fn check_render_snapshot( &mut self, manifest_dir: &str, test_file_path: &str, test_module_path: &str, test_name: &str )
Method used by [assert_render_snapshot
]. Use the macro instead.
Renders the current Widget tree to a pixmap, and compares the pixmap against the
snapshot stored in ./screenshots/module_path__test_name.png
.
- manifest_dir: directory where
Cargo.toml
can be found. - test_file_path: file path the current test is in.
- test_module_path: import path of the module the current test is in.
- test_name: arbitrary name; second argument of assert_render_snapshot.