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

source

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].

source

pub fn create_with_size(root_widget: impl Widget, window_size: Size) -> Self

Builds harness with given root widget and window size.

source

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.

source

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.

source

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.

source

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.

source

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.

source

pub fn mouse_move(&mut self, pos: impl Into<Point>)

Move an internal mouse state, and send a MouseMove event to the window.

source

pub fn mouse_button_press(&mut self, button: MouseButton)

Send a MouseDown event to the window.

source

pub fn mouse_button_release(&mut self, button: MouseButton)

Send a MouseUp event to the window.

source

pub fn mouse_wheel(&mut self, wheel_delta: Vec2)

Send a Wheel event to the window

source

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.

source

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.

source

pub fn keyboard_type_chars(&mut self, text: &str)

source

pub fn root_widget(&self) -> WidgetRef<'_, dyn Widget>

Return the root widget.

source

pub fn get_widget(&self, id: WidgetId) -> WidgetRef<'_, dyn Widget>

Return the widget with the given id.

§Panics

Panics if no Widget with this id can be found.

source

pub fn try_get_widget(&self, id: WidgetId) -> Option<WidgetRef<'_, dyn Widget>>

Try to return the widget with the given id.

source

pub fn focused_widget(&self) -> Option<WidgetRef<'_, dyn Widget>>

Return the widget that receives keyboard events.

source

pub fn inspect_widgets( &mut self, f: impl Fn(WidgetRef<'_, dyn Widget>) + 'static )

Call the provided visitor on every widget in the widget tree.

source

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.

source

pub fn pop_action(&mut self) -> Option<(Action, WidgetId)>

Pop next action from the queue

Note: Actions are still a WIP feature.

source

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.
source

pub fn write_debug_logs(&mut self, path: &str)

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> AsAny for T
where T: Any,

source§

fn as_dyn_any(&self) -> &(dyn Any + 'static)

Return self.
source§

fn as_mut_dyn_any(&mut self) -> &mut (dyn Any + 'static)

Return self.
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> ErasedDestructor for T
where T: 'static,

source§

impl<T> MaybeSendSync for T