example_tests.rs

  1//! Tests for the `ExampleEditor` entity.
  2//!
  3//! These use GPUI's test infrastructure which requires the `test-support` feature:
  4//!
  5//! ```sh
  6//! cargo test --example text_views -p gpui --features test-support
  7//! ```
  8
  9#[cfg(test)]
 10mod tests {
 11    use std::time::Duration;
 12
 13    use gpui::{Context, Entity, KeyBinding, TestAppContext, Window, prelude::*};
 14
 15    use crate::example_editor::ExampleEditor;
 16    use crate::example_input::ExampleInput;
 17    use crate::example_text_area::ExampleTextArea;
 18    use crate::{Backspace, Delete, End, Enter, Home, Left, Right};
 19
 20    struct InputWrapper {
 21        editor: Entity<ExampleEditor>,
 22    }
 23
 24    impl Render for InputWrapper {
 25        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
 26            ExampleInput::new(self.editor.clone())
 27        }
 28    }
 29
 30    struct TextAreaWrapper {
 31        editor: Entity<ExampleEditor>,
 32    }
 33
 34    impl Render for TextAreaWrapper {
 35        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
 36            ExampleTextArea::new(self.editor.clone(), 5)
 37        }
 38    }
 39
 40    fn bind_keys(cx: &mut TestAppContext) {
 41        cx.update(|cx| {
 42            cx.bind_keys([
 43                KeyBinding::new("backspace", Backspace, None),
 44                KeyBinding::new("delete", Delete, None),
 45                KeyBinding::new("left", Left, None),
 46                KeyBinding::new("right", Right, None),
 47                KeyBinding::new("home", Home, None),
 48                KeyBinding::new("end", End, None),
 49                KeyBinding::new("enter", Enter, None),
 50            ]);
 51        });
 52    }
 53
 54    fn init_input(
 55        cx: &mut TestAppContext,
 56    ) -> (Entity<ExampleEditor>, &mut gpui::VisualTestContext) {
 57        bind_keys(cx);
 58
 59        let (wrapper, cx) = cx.add_window_view(|_window, cx| {
 60            let editor = cx.new(|cx| ExampleEditor::new(cx));
 61            InputWrapper { editor }
 62        });
 63
 64        let editor = cx.read_entity(&wrapper, |wrapper, _cx| wrapper.editor.clone());
 65
 66        cx.update(|window, cx| {
 67            let focus_handle = editor.read(cx).focus_handle.clone();
 68            window.focus(&focus_handle, cx);
 69        });
 70
 71        (editor, cx)
 72    }
 73
 74    fn init_textarea(
 75        cx: &mut TestAppContext,
 76    ) -> (Entity<ExampleEditor>, &mut gpui::VisualTestContext) {
 77        bind_keys(cx);
 78
 79        let (wrapper, cx) = cx.add_window_view(|_window, cx| {
 80            let editor = cx.new(|cx| ExampleEditor::new(cx));
 81            TextAreaWrapper { editor }
 82        });
 83
 84        let editor = cx.read_entity(&wrapper, |wrapper, _cx| wrapper.editor.clone());
 85
 86        cx.update(|window, cx| {
 87            let focus_handle = editor.read(cx).focus_handle.clone();
 88            window.focus(&focus_handle, cx);
 89        });
 90
 91        (editor, cx)
 92    }
 93
 94    #[gpui::test]
 95    fn test_typing_and_cursor(cx: &mut TestAppContext) {
 96        let (editor, cx) = init_input(cx);
 97
 98        cx.simulate_input("hello");
 99
100        cx.read_entity(&editor, |editor, _cx| {
101            assert_eq!(editor.content, "hello");
102            assert_eq!(editor.cursor, 5);
103        });
104
105        cx.simulate_keystrokes("left left");
106
107        cx.read_entity(&editor, |editor, _cx| {
108            assert_eq!(editor.cursor, 3);
109        });
110
111        cx.simulate_input(" world");
112
113        cx.read_entity(&editor, |editor, _cx| {
114            assert_eq!(editor.content, "hel worldlo");
115            assert_eq!(editor.cursor, 9);
116        });
117    }
118
119    #[gpui::test]
120    fn test_backspace_and_delete(cx: &mut TestAppContext) {
121        let (editor, cx) = init_input(cx);
122
123        cx.simulate_input("abcde");
124
125        cx.simulate_keystrokes("backspace");
126        cx.read_entity(&editor, |editor, _cx| {
127            assert_eq!(editor.content, "abcd");
128            assert_eq!(editor.cursor, 4);
129        });
130
131        cx.simulate_keystrokes("home delete");
132        cx.read_entity(&editor, |editor, _cx| {
133            assert_eq!(editor.content, "bcd");
134            assert_eq!(editor.cursor, 0);
135        });
136
137        // Boundary no-ops
138        cx.simulate_keystrokes("backspace");
139        cx.read_entity(&editor, |editor, _cx| {
140            assert_eq!(editor.content, "bcd");
141        });
142
143        cx.simulate_keystrokes("end delete");
144        cx.read_entity(&editor, |editor, _cx| {
145            assert_eq!(editor.content, "bcd");
146        });
147    }
148
149    #[gpui::test]
150    fn test_cursor_blink(cx: &mut TestAppContext) {
151        let (editor, cx) = init_input(cx);
152
153        cx.read_entity(&editor, |editor, _cx| {
154            assert!(editor.cursor_visible);
155        });
156
157        cx.background_executor
158            .advance_clock(Duration::from_millis(500));
159        cx.run_until_parked();
160
161        cx.read_entity(&editor, |editor, _cx| {
162            assert!(!editor.cursor_visible);
163        });
164
165        // Typing resets the blink.
166        cx.simulate_input("a");
167
168        cx.read_entity(&editor, |editor, _cx| {
169            assert!(editor.cursor_visible);
170        });
171    }
172
173    #[gpui::test]
174    fn test_enter_does_not_insert_in_input(cx: &mut TestAppContext) {
175        let (editor, cx) = init_input(cx);
176
177        cx.simulate_input("hello");
178        cx.simulate_keystrokes("enter");
179
180        cx.read_entity(&editor, |editor, _cx| {
181            assert_eq!(
182                editor.content, "hello",
183                "Enter should not insert text in Input"
184            );
185            assert_eq!(editor.cursor, 5);
186        });
187    }
188
189    #[gpui::test]
190    fn test_enter_inserts_newline_in_textarea(cx: &mut TestAppContext) {
191        let (editor, cx) = init_textarea(cx);
192
193        cx.simulate_input("ab");
194        cx.simulate_keystrokes("enter");
195        cx.simulate_input("cd");
196
197        cx.read_entity(&editor, |editor, _cx| {
198            assert_eq!(editor.content, "ab\ncd");
199            assert_eq!(editor.cursor, 5);
200        });
201    }
202
203    #[gpui::test]
204    fn test_enter_at_start_of_textarea(cx: &mut TestAppContext) {
205        let (editor, cx) = init_textarea(cx);
206
207        cx.simulate_keystrokes("enter");
208        cx.simulate_input("hello");
209
210        cx.read_entity(&editor, |editor, _cx| {
211            assert_eq!(editor.content, "\nhello");
212            assert_eq!(editor.cursor, 6);
213        });
214    }
215}