Add command palette tests and simulate_keystrokes

This commit is contained in:
Conrad Irwin
2023-11-14 23:22:51 -07:00
parent e37d7f5b0e
commit 91b54b352b
6 changed files with 180 additions and 119 deletions
+11
View File
@@ -54,6 +54,9 @@ pub trait Action: std::fmt::Debug + 'static {
where
Self: Sized;
fn build(value: Option<serde_json::Value>) -> Result<Box<dyn Action>>
where
Self: Sized;
fn is_registered() -> bool
where
Self: Sized;
@@ -88,6 +91,14 @@ where
Ok(Box::new(action))
}
fn is_registered() -> bool {
ACTION_REGISTRY
.read()
.names_by_type_id
.get(&TypeId::of::<A>())
.is_some()
}
fn partial_eq(&self, action: &dyn Action) -> bool {
action
.as_any()
+54 -6
View File
@@ -1,8 +1,8 @@
use crate::{
div, Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
BackgroundExecutor, Context, Div, EventEmitter, ForegroundExecutor, InputEvent, KeyDownEvent,
Keystroke, Model, ModelContext, Render, Result, Task, TestDispatcher, TestPlatform, View,
ViewContext, VisualContext, WindowContext, WindowHandle, WindowOptions,
Keystroke, Model, ModelContext, Render, Result, Task, TestDispatcher, TestPlatform, TestWindow,
View, ViewContext, VisualContext, WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{Stream, StreamExt};
@@ -220,7 +220,21 @@ impl TestAppContext {
{
window
.update(self, |_, cx| cx.dispatch_action(action.boxed_clone()))
.unwrap()
.unwrap();
self.background_executor.run_until_parked()
}
pub fn simulate_keystrokes(&mut self, window: AnyWindowHandle, keystrokes: &str) {
for keystroke in keystrokes
.split(" ")
.map(Keystroke::parse)
.map(Result::unwrap)
{
self.dispatch_keystroke(window, keystroke.into(), false);
}
self.background_executor.run_until_parked()
}
pub fn dispatch_keystroke(
@@ -229,15 +243,41 @@ impl TestAppContext {
keystroke: Keystroke,
is_held: bool,
) {
let keystroke2 = keystroke.clone();
let handled = window
.update(self, |_, cx| {
cx.dispatch_event(InputEvent::KeyDown(KeyDownEvent { keystroke, is_held }))
})
.is_ok_and(|handled| handled);
if !handled {
// todo!() simluate input here
if handled {
return;
}
let input_handler = self.update_test_window(window, |window| window.input_handler.clone());
let Some(input_handler) = input_handler else {
panic!(
"dispatch_keystroke {:?} failed to dispatch action or input",
&keystroke2
);
};
let text = keystroke2.ime_key.unwrap_or(keystroke2.key);
input_handler.lock().replace_text_in_range(None, &text);
}
pub fn update_test_window<R>(
&mut self,
window: AnyWindowHandle,
f: impl FnOnce(&mut TestWindow) -> R,
) -> R {
window
.update(self, |_, cx| {
f(cx.window
.platform_window
.as_any_mut()
.downcast_mut::<TestWindow>()
.unwrap())
})
.unwrap()
}
pub fn notifications<T: 'static>(&mut self, entity: &Model<T>) -> impl Stream<Item = ()> {
@@ -401,12 +441,20 @@ impl<'a> VisualTestContext<'a> {
Self { cx, window }
}
pub fn run_until_parked(&self) {
self.cx.background_executor.run_until_parked();
}
pub fn dispatch_action<A>(&mut self, action: A)
where
A: Action,
{
self.cx.dispatch_action(self.window, action)
}
pub fn simulate_keystrokes(&mut self, keystrokes: &str) {
self.cx.simulate_keystrokes(self.window, keystrokes)
}
}
impl<'a> Context for VisualTestContext<'a> {
+14
View File
@@ -229,6 +229,20 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
mut self,
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
) -> Self {
// NOTE: this debug assert has the side-effect of working around
// a bug where a crate consisting only of action definitions does
// not register the actions in debug builds:
//
// https://github.com/rust-lang/rust/issues/47384
// https://github.com/mmastrac/rust-ctor/issues/280
//
// if we are relying on this side-effect still, removing the debug_assert!
// likely breaks the command_palette tests.
debug_assert!(
A::is_registered(),
"{:?} is not registered as an action",
A::qualified_name()
);
self.interactivity().action_listeners.push((
TypeId::of::<A>(),
Box::new(move |view, action, phase, cx| {
+3 -3
View File
@@ -22,7 +22,7 @@ pub struct TestWindow {
bounds: WindowBounds,
current_scene: Mutex<Option<Scene>>,
display: Rc<dyn PlatformDisplay>,
input_handler: Option<Box<dyn PlatformInputHandler>>,
pub(crate) input_handler: Option<Arc<Mutex<Box<dyn PlatformInputHandler>>>>,
handlers: Mutex<Handlers>,
platform: Weak<TestPlatform>,
sprite_atlas: Arc<dyn PlatformAtlas>,
@@ -80,11 +80,11 @@ impl PlatformWindow for TestWindow {
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
todo!()
self
}
fn set_input_handler(&mut self, input_handler: Box<dyn crate::PlatformInputHandler>) {
self.input_handler = Some(input_handler);
self.input_handler = Some(Arc::new(Mutex::new(input_handler)));
}
fn prompt(
+1 -1
View File
@@ -189,7 +189,7 @@ impl Drop for FocusHandle {
pub struct Window {
pub(crate) handle: AnyWindowHandle,
pub(crate) removed: bool,
platform_window: Box<dyn PlatformWindow>,
pub(crate) platform_window: Box<dyn PlatformWindow>,
display_id: DisplayId,
sprite_atlas: Arc<dyn PlatformAtlas>,
rem_size: Pixels,