pub struct HeadlessHarness { /* private fields */ }Expand description
A headless harness for UI testing and benchmarking.
HeadlessHarness manages a view tree and provides methods to simulate user interactions without creating an actual window.
Internally, it uses a headless WindowHandle to ensure behavior
matches real window behavior, including the full process_update() cycle
for style recalculation and layout.
Implementations§
Source§impl HeadlessHarness
impl HeadlessHarness
Sourcepub fn new(root: TestRoot, view: impl IntoView) -> HeadlessHarness
pub fn new(root: TestRoot, view: impl IntoView) -> HeadlessHarness
Create a new headless harness with the given root view.
The view will be set up with default size (800x600) and scale (1.0).
§Example
use floem::headless::{TestRoot, HeadlessHarness};
use floem::views::Empty;
let root = TestRoot::new();
let view = Empty::new().style(|s| s.size(100.0, 100.0));
let harness = HeadlessHarness::new(root, view);Sourcepub fn new_with_size(
root: TestRoot,
view: impl IntoView,
width: f64,
height: f64,
) -> HeadlessHarness
pub fn new_with_size( root: TestRoot, view: impl IntoView, width: f64, height: f64, ) -> HeadlessHarness
Create a new headless harness with the given root view and window size.
Use this when you need to create views before creating the harness.
§Example
use floem::headless::{TestRoot, HeadlessHarness};
use floem::views::Empty;
let root = TestRoot::new();
let view = Empty::new().style(|s| s.size(100.0, 100.0));
let harness = HeadlessHarness::new_with_size(root, view, 100.0, 100.0);Sourcepub fn set_size(&mut self, width: f64, height: f64) -> &mut HeadlessHarness
pub fn set_size(&mut self, width: f64, height: f64) -> &mut HeadlessHarness
Set the window size and rebuild layout.
Sourcepub fn set_scale(&mut self, scale: f64) -> &mut HeadlessHarness
pub fn set_scale(&mut self, scale: f64) -> &mut HeadlessHarness
Set the window scale factor.
Sourcepub fn rebuild(&mut self)
pub fn rebuild(&mut self)
Run all passes: style → layout → compute_layout.
This must be called after any changes to view styles or structure for events to be dispatched correctly.
Note: When using the headless WindowHandle, this is typically called
automatically via process_update_no_paint() after event dispatch.
Sourcepub fn process_update_messages(&mut self)
pub fn process_update_messages(&mut self)
process update messages
this can be used so that style requests can be integrated into the window state without restyling
Sourcepub fn process_update_no_paint(&mut self)
pub fn process_update_no_paint(&mut self)
Run pending reactive effects and process all updates.
Returns true if a repaint would be scheduled (style or layout changed).
This is the return value from the underlying WindowHandle::process_update_no_paint().
Use this method when you need to verify that style/layout changes trigger repaints:
signal.set(new_value);
let needs_repaint = harness.process_update_no_paint();
assert!(needs_repaint, "Style change should trigger repaint");Sourcepub fn window_id(&self) -> WindowId
pub fn window_id(&self) -> WindowId
Returns the winit::window::WindowId of the underlying headless window.
Sourcepub fn dispatch_event(&mut self, event: Event) -> EventResult
pub fn dispatch_event(&mut self, event: Event) -> EventResult
Dispatch an event to the view tree.
This uses the full WindowHandle event dispatch and processing,
including the process_update() cycle that handles:
- Update messages
- Style recalculation
- Layout passes
Sourcepub fn pointer_down(&mut self, x: f64, y: f64) -> EventResult
pub fn pointer_down(&mut self, x: f64, y: f64) -> EventResult
Simulate a pointer down event at the given position.
Sourcepub fn pointer_up(&mut self, x: f64, y: f64) -> EventResult
pub fn pointer_up(&mut self, x: f64, y: f64) -> EventResult
Simulate a pointer up event at the given position.
Sourcepub fn pointer_move(&mut self, x: f64, y: f64) -> EventResult
pub fn pointer_move(&mut self, x: f64, y: f64) -> EventResult
Simulate a pointer move event to the given position.
Sourcepub fn pointer_leave(&mut self) -> EventResult
pub fn pointer_leave(&mut self) -> EventResult
Simulate a pointer leave window event to the given position.
Sourcepub fn click(&mut self, x: f64, y: f64) -> EventResult
pub fn click(&mut self, x: f64, y: f64) -> EventResult
Simulate a click (pointer down + pointer up) at the given position.
Sourcepub fn double_click(&mut self, x: f64, y: f64) -> EventResult
pub fn double_click(&mut self, x: f64, y: f64) -> EventResult
Simulate a double click at the given position.
Sourcepub fn secondary_click(&mut self, x: f64, y: f64) -> EventResult
pub fn secondary_click(&mut self, x: f64, y: f64) -> EventResult
Simulate a secondary (right) click at the given position.
Sourcepub fn touch_down(&mut self, x: f64, y: f64) -> EventResult
pub fn touch_down(&mut self, x: f64, y: f64) -> EventResult
Simulate a touch down event at the given position.
Touch pointers automatically get implicit capture per W3C Pointer Events spec.
Sourcepub fn touch_up(&mut self, x: f64, y: f64) -> EventResult
pub fn touch_up(&mut self, x: f64, y: f64) -> EventResult
Simulate a touch up event at the given position.
Sourcepub fn touch_move(&mut self, x: f64, y: f64) -> EventResult
pub fn touch_move(&mut self, x: f64, y: f64) -> EventResult
Simulate a touch move event to the given position.
Sourcepub fn tap(&mut self, x: f64, y: f64) -> EventResult
pub fn tap(&mut self, x: f64, y: f64) -> EventResult
Simulate a tap (touch down + touch up) at the given position.
Sourcepub fn scroll(
&mut self,
x: f64,
y: f64,
delta_x: f64,
delta_y: f64,
) -> EventResult
pub fn scroll( &mut self, x: f64, y: f64, delta_x: f64, delta_y: f64, ) -> EventResult
Simulate a scroll wheel event at the given position.
delta_x and delta_y are the scroll amounts in pixels.
These are raw scroll deltas - the scroll view negates them internally.
Typically: negative delta_y = scroll down (see lower content).
Sourcepub fn scroll_down(&mut self, x: f64, y: f64, amount: f64) -> EventResult
pub fn scroll_down(&mut self, x: f64, y: f64, amount: f64) -> EventResult
Simulate scrolling down (to see lower content).
amount is how many pixels to scroll down (positive value).
Sourcepub fn scroll_up(&mut self, x: f64, y: f64, amount: f64) -> EventResult
pub fn scroll_up(&mut self, x: f64, y: f64, amount: f64) -> EventResult
Simulate scrolling up (to see higher content).
amount is how many pixels to scroll up (positive value).
Sourcepub fn scroll_right(&mut self, x: f64, y: f64, amount: f64) -> EventResult
pub fn scroll_right(&mut self, x: f64, y: f64, amount: f64) -> EventResult
Simulate scrolling right (to see content further right).
amount is how many pixels to scroll right (positive value).
Sourcepub fn scroll_left(&mut self, x: f64, y: f64, amount: f64) -> EventResult
pub fn scroll_left(&mut self, x: f64, y: f64, amount: f64) -> EventResult
Simulate scrolling left (to see content further left).
amount is how many pixels to scroll left (positive value).
Sourcepub fn scroll_lines(
&mut self,
x: f64,
y: f64,
lines_x: f32,
lines_y: f32,
) -> EventResult
pub fn scroll_lines( &mut self, x: f64, y: f64, lines_x: f32, lines_y: f32, ) -> EventResult
Simulate a line-based scroll wheel event at the given position.
lines_x and lines_y are the number of lines to scroll.
This is converted to pixel delta using a default line height of 20 pixels.
Sourcepub fn element_id_at(&self, x: f64, y: f64) -> Option<ElementId>
pub fn element_id_at(&self, x: f64, y: f64) -> Option<ElementId>
Find the visual id at the given position (hit test).
Sourcepub fn is_active(&self, id: impl Into<ElementId>) -> bool
pub fn is_active(&self, id: impl Into<ElementId>) -> bool
Check if a view is currently in the “active” state active: pointer down and not up with the pointer in the element either by 1: remaining in or 2: returning into the element or keyboard trigger is down).
Sourcepub fn is_hovered(&self, id: impl Into<ElementId>) -> bool
pub fn is_hovered(&self, id: impl Into<ElementId>) -> bool
Check if a view is currently hovered.
Sourcepub fn is_focused(&self, id: impl Into<ElementId>) -> bool
pub fn is_focused(&self, id: impl Into<ElementId>) -> bool
Check if a view is currently focused.
Sourcepub fn has_capture(&self, id: impl Into<ElementId>) -> bool
pub fn has_capture(&self, id: impl Into<ElementId>) -> bool
Check if a view has pointer capture.
Sourcepub fn get_interaction_state(
&mut self,
id: impl Into<ElementId>,
) -> InteractionState
pub fn get_interaction_state( &mut self, id: impl Into<ElementId>, ) -> InteractionState
Get the current interaction state for a view.
This returns the same state used during style computation to determine which style selectors (hover, active, focused, etc.) apply to the view.
Sourcepub fn has_style_for_selector(
&mut self,
id: ViewId,
selector: StyleSelector,
) -> bool
pub fn has_style_for_selector( &mut self, id: ViewId, selector: StyleSelector, ) -> bool
Check if a view has styles defined for the given selector.
For example, has_style_for_selector(id, StyleSelector::Active) returns true
if the view has an :active style defined.
Sourcepub fn get_computed_style(&self, id: ViewId) -> Style
pub fn get_computed_style(&self, id: ViewId) -> Style
Get the computed style for a view.
This returns a clone of the fully computed style after all style passes have run. Use this to verify that style changes (e.g., from :active or :hover selectors) are being applied correctly.
§Example
use floem::style::Background;
harness.pointer_down(50.0, 50.0);
let style = harness.get_computed_style(id);
let bg = style.get(Background);
assert!(bg.is_some(), "Background should be set when :active");Sourcepub fn recompute_styles(&mut self)
pub fn recompute_styles(&mut self)
Trigger a style recalculation pass.
This runs the full process_update cycle which includes style recalculation. With the headless WindowHandle, this is typically called automatically after event dispatch, but can be called manually if needed.
Sourcepub fn process_pointer_up_styles(&mut self)
pub fn process_pointer_up_styles(&mut self)
Request style recalculation for views with Active selector, then recompute.
This simulates the full pointer-up flow:
- Run style recalculation via process_update
Sourcepub fn paint_requested(&self) -> bool
pub fn paint_requested(&self) -> bool
Check if a repaint was requested.
This is useful for verifying that style changes trigger repaints.
Sourcepub fn clear_paint_request(&mut self)
pub fn clear_paint_request(&mut self)
Clear the paint request flag.
Call this before an operation to then check if it triggered a repaint.
Sourcepub fn has_pending_style_change(&self, id: ViewId) -> bool
pub fn has_pending_style_change(&self, id: ViewId) -> bool
Check if a view has pending style changes.
Sourcepub fn has_scheduled_updates(&self) -> bool
pub fn has_scheduled_updates(&self) -> bool
Check if there are scheduled updates for the next frame.
This is useful for testing transitions, which schedule style updates to animate across frames.
Sourcepub fn is_style_dirty(&self, id: ViewId) -> bool
pub fn is_style_dirty(&self, id: ViewId) -> bool
Check if a view is in the style_dirty set.
Views in this set will be processed during the next style pass.
Sourcepub fn get_layout_rect(&self, id: ViewId) -> Rect
pub fn get_layout_rect(&self, id: ViewId) -> Rect
Get the layout rectangle for a view.
This is the rectangle in window coordinates where the view is positioned.
pub fn get_view(&self, id: ViewId) -> Rc<RefCell<Box<dyn View>>>
Sourcepub fn get_content_rect(&self, id: ViewId) -> Rect
pub fn get_content_rect(&self, id: ViewId) -> Rect
Get the content rectangle for a view (excluding padding/borders).
Sourcepub fn paint_and_get_order(&mut self) -> Vec<ViewId>
pub fn paint_and_get_order(&mut self) -> Vec<ViewId>
Paint the view tree and record the order in which views are painted.
This enables paint order tracking, paints the entire view tree (including overlays), and returns the list of ViewIds in the order they were painted.
§Example
let paint_order = harness.paint_and_get_order();
// Views are painted from back to front (lowest z-index first)
// Regular views paint first, then overlaysSourcepub fn enable_paint_tracking(&mut self)
pub fn enable_paint_tracking(&mut self)
Enable paint order tracking for subsequent paint operations.
Call this before operations that trigger painting, then use
get_paint_order() to retrieve the recorded order.
Sourcepub fn disable_paint_tracking(&mut self)
pub fn disable_paint_tracking(&mut self)
Disable paint order tracking.
Sourcepub fn clear_paint_order(&mut self)
pub fn clear_paint_order(&mut self)
Clear the recorded paint order without disabling tracking.
Sourcepub fn get_paint_order(&self) -> Vec<ViewId>
pub fn get_paint_order(&self) -> Vec<ViewId>
Get the recorded paint order from the most recent paint operation.
Returns the list of ViewIds in the order they were painted (from back to front).
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for HeadlessHarness
impl !RefUnwindSafe for HeadlessHarness
impl !Send for HeadlessHarness
impl !Sync for HeadlessHarness
impl Unpin for HeadlessHarness
impl UnsafeUnpin for HeadlessHarness
impl !UnwindSafe for HeadlessHarness
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more