Implement Simulator::simulate and polish naming

This commit is contained in:
Héctor Ramón Jiménez 2024-12-17 01:37:00 +01:00
parent bfa722c662
commit 869b44db4e
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
2 changed files with 61 additions and 47 deletions

View file

@ -611,8 +611,8 @@ mod tests {
let mut ui = simulator(&todos); let mut ui = simulator(&todos);
let _input = ui.click("new-task")?; let _input = ui.click("new-task")?;
ui.typewrite("Create the universe"); let _ = ui.typewrite("Create the universe");
ui.press_key(keyboard::key::Named::Enter); let _ = ui.tap_key(keyboard::key::Named::Enter);
for message in ui.into_messages() { for message in ui.into_messages() {
let _command = todos.update(message); let _command = todos.update(message);

View file

@ -9,13 +9,16 @@ use iced_runtime as runtime;
use iced_runtime::core; use iced_runtime::core;
use crate::core::clipboard; use crate::core::clipboard;
use crate::core::event;
use crate::core::keyboard; use crate::core::keyboard;
use crate::core::mouse; use crate::core::mouse;
use crate::core::theme; use crate::core::theme;
use crate::core::time; use crate::core::time;
use crate::core::widget; use crate::core::widget;
use crate::core::window; use crate::core::window;
use crate::core::{Element, Event, Font, Rectangle, Settings, Size, SmolStr}; use crate::core::{
Element, Event, Font, Point, Rectangle, Settings, Size, SmolStr,
};
use crate::runtime::user_interface; use crate::runtime::user_interface;
use crate::runtime::UserInterface; use crate::runtime::UserInterface;
@ -53,6 +56,7 @@ pub struct Simulator<
raw: UserInterface<'a, Message, Theme, Renderer>, raw: UserInterface<'a, Message, Theme, Renderer>,
renderer: Renderer, renderer: Renderer,
window_size: Size, window_size: Size,
cursor: mouse::Cursor,
messages: Vec<Message>, messages: Vec<Message>,
} }
@ -75,14 +79,14 @@ where
settings: Settings, settings: Settings,
element: impl Into<Element<'a, Message, Theme, Renderer>>, element: impl Into<Element<'a, Message, Theme, Renderer>>,
) -> Self { ) -> Self {
Self::with_settings_and_size( Self::with_window_size(
settings, settings,
window::Settings::default().size, window::Settings::default().size,
element, element,
) )
} }
pub fn with_settings_and_size( pub fn with_window_size(
settings: Settings, settings: Settings,
window_size: impl Into<Size>, window_size: impl Into<Size>,
element: impl Into<Element<'a, Message, Theme, Renderer>>, element: impl Into<Element<'a, Message, Theme, Renderer>>,
@ -112,6 +116,7 @@ where
raw, raw,
renderer, renderer,
window_size, window_size,
cursor: mouse::Cursor::Unavailable,
messages: Vec::new(), messages: Vec::new(),
} }
} }
@ -214,7 +219,6 @@ where
} }
let mut find = FindById { id, target: None }; let mut find = FindById { id, target: None };
self.raw.operate(&self.renderer, &mut find); self.raw.operate(&self.renderer, &mut find);
find.target.ok_or(Error::NotFound(selector)) find.target.ok_or(Error::NotFound(selector))
@ -258,7 +262,6 @@ where
} }
let mut find = FindByText { text, target: None }; let mut find = FindByText { text, target: None };
self.raw.operate(&self.renderer, &mut find); self.raw.operate(&self.renderer, &mut find);
find.target.ok_or(Error::NotFound(selector)) find.target.ok_or(Error::NotFound(selector))
@ -266,56 +269,52 @@ where
} }
} }
pub fn point_at(&mut self, position: impl Into<Point>) {
self.cursor = mouse::Cursor::Available(position.into());
}
pub fn click( pub fn click(
&mut self, &mut self,
selector: impl Into<Selector>, selector: impl Into<Selector>,
) -> Result<Target, Error> { ) -> Result<Target, Error> {
let target = self.find(selector)?; let target = self.find(selector)?;
self.point_at(target.bounds.center());
let _ = self.raw.update( let _ = self.simulate(click());
&[
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)),
],
mouse::Cursor::Available(target.bounds.center()),
&mut self.renderer,
&mut clipboard::Null,
&mut self.messages,
);
Ok(target) Ok(target)
} }
pub fn typewrite(&mut self, text: impl AsRef<str>) { pub fn tap_key(&mut self, key: impl Into<keyboard::Key>) -> event::Status {
let events: Vec<_> = text self.simulate(tap_key(key, None))
.as_ref() .first()
.chars() .copied()
.map(|c| SmolStr::new_inline(&c.to_string())) .unwrap_or(event::Status::Ignored)
.flat_map(|c| {
key_press_and_release(
keyboard::Key::Character(c.clone()),
Some(c),
)
})
.collect();
let _ = self.raw.update(
&events,
mouse::Cursor::Unavailable,
&mut self.renderer,
&mut clipboard::Null,
&mut self.messages,
);
} }
pub fn press_key(&mut self, key: impl Into<keyboard::Key>) { pub fn typewrite(&mut self, text: &str) -> event::Status {
let _ = self.raw.update( let statuses = self.simulate(typewrite(text));
&key_press_and_release(key, None),
mouse::Cursor::Unavailable, statuses
.into_iter()
.fold(event::Status::Ignored, event::Status::merge)
}
pub fn simulate(
&mut self,
events: impl IntoIterator<Item = Event>,
) -> Vec<event::Status> {
let events: Vec<Event> = events.into_iter().collect();
let (_state, statuses) = self.raw.update(
&events,
self.cursor,
&mut self.renderer, &mut self.renderer,
&mut clipboard::Null, &mut clipboard::Null,
&mut self.messages, &mut self.messages,
); );
statuses
} }
pub fn snapshot(&mut self) -> Result<Snapshot, Error> { pub fn snapshot(&mut self) -> Result<Snapshot, Error> {
@ -326,7 +325,7 @@ where
&[Event::Window(window::Event::RedrawRequested( &[Event::Window(window::Event::RedrawRequested(
time::Instant::now(), time::Instant::now(),
))], ))],
mouse::Cursor::Unavailable, self.cursor,
&mut self.renderer, &mut self.renderer,
&mut clipboard::Null, &mut clipboard::Null,
&mut self.messages, &mut self.messages,
@ -338,7 +337,7 @@ where
&core::renderer::Style { &core::renderer::Style {
text_color: base.text_color, text_color: base.text_color,
}, },
mouse::Cursor::Unavailable, self.cursor,
); );
let scale_factor = 2.0; let scale_factor = 2.0;
@ -363,8 +362,8 @@ where
}) })
} }
pub fn into_messages(self) -> impl IntoIterator<Item = Message> { pub fn into_messages(self) -> impl Iterator<Item = Message> {
self.messages self.messages.into_iter()
} }
} }
@ -433,10 +432,18 @@ impl Snapshot {
} }
} }
fn key_press_and_release( pub fn click() -> impl Iterator<Item = Event> {
[
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)),
]
.into_iter()
}
pub fn tap_key(
key: impl Into<keyboard::Key>, key: impl Into<keyboard::Key>,
text: Option<SmolStr>, text: Option<SmolStr>,
) -> [Event; 2] { ) -> impl Iterator<Item = Event> {
let key = key.into(); let key = key.into();
[ [
@ -460,6 +467,13 @@ fn key_press_and_release(
modifiers: keyboard::Modifiers::default(), modifiers: keyboard::Modifiers::default(),
}), }),
] ]
.into_iter()
}
pub fn typewrite(text: &str) -> impl Iterator<Item = Event> + '_ {
text.chars()
.map(|c| SmolStr::new_inline(&c.to_string()))
.flat_map(|c| tap_key(keyboard::Key::Character(c.clone()), Some(c)))
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]