diff --git a/Cargo.lock b/Cargo.lock
index a63dbbc..e2de11c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -29,6 +29,15 @@ dependencies = [
  "zerocopy",
 ]
 
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "allocator-api2"
 version = "0.2.16"
@@ -273,12 +282,113 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
 [[package]]
 name = "gimli"
 version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
 [[package]]
 name = "hashbrown"
 version = "0.14.2"
@@ -448,6 +558,12 @@ version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.69"
@@ -486,6 +602,13 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "ratatui-macros"
+version = "0.3.0"
+dependencies = [
+ "ratatui",
+]
+
 [[package]]
 name = "redox_syscall"
 version = "0.4.1"
@@ -495,12 +618,85 @@ dependencies = [
  "bitflags 1.3.2",
 ]
 
+[[package]]
+name = "regex"
+version = "1.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+
+[[package]]
+name = "relative-path"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
+
+[[package]]
+name = "rstest"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d5316d2a1479eeef1ea21e7f9ddc67c191d497abc8fc3ba2467857abbb68330"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "rstest_macros",
+ "rustc_version",
+]
+
+[[package]]
+name = "rstest_macros"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04a9df72cc1f67020b0d63ad9bfe4a323e459ea7eb68e03bd9824db49f9a4c25"
+dependencies = [
+ "cfg-if",
+ "glob",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "relative-path",
+ "rustc_version",
+ "syn",
+ "unicode-ident",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
 [[package]]
 name = "rustversion"
 version = "1.0.14"
@@ -519,6 +715,12 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
 [[package]]
 name = "sharded-slab"
 version = "0.1.7"
@@ -558,6 +760,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
 [[package]]
 name = "smallvec"
 version = "1.11.2"
@@ -680,6 +891,8 @@ dependencies = [
  "indoc",
  "itertools",
  "ratatui",
+ "ratatui-macros",
+ "rstest",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index e9ec08e..0ff5654 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,8 @@ edition = "2021"
 crossterm = "0.27.0"
 itertools = "0.12.1"
 ratatui = "0.26.2"
+ratatui-macros = { version = "0.3.0", path = "../ratatui-macros" }
+rstest = "0.19.0"
 
 [dev-dependencies]
 clap = { version = "4.5.4", features = ["derive"] }
diff --git a/src/text_prompt.rs b/src/text_prompt.rs
index e6d0f69..c499270 100644
--- a/src/text_prompt.rs
+++ b/src/text_prompt.rs
@@ -204,15 +204,12 @@ where
 #[cfg(test)]
 mod tests {
     use crate::Status;
+    use ratatui_macros::line;
+    use rstest::{fixture, rstest};
 
     use super::*;
     use ratatui::{assert_buffer_eq, backend::TestBackend, widgets::Borders};
 
-    // TODO make these configurable
-    const PENDING_STYLE: Style = Style::new().fg(Color::Cyan);
-    const COMPLETE_STYLE: Style = Style::new().fg(Color::Green);
-    const ABORTED_STYLE: Style = Style::new().fg(Color::Red);
-
     #[test]
     fn new() {
         const PROMPT: TextPrompt<'_> = TextPrompt::new(Cow::Borrowed("Enter your name"));
@@ -234,6 +231,7 @@ mod tests {
         let prompt = TextPrompt::from("Enter your name");
         assert_eq!(prompt.message, "Enter your name");
     }
+
     #[test]
     fn render() {
         let prompt = TextPrompt::from("prompt");
@@ -242,11 +240,8 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["? prompt ›     "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line!["?".cyan(), " ", "prompt".bold(), " › ".cyan().dim(), "    ",];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
         assert_eq!(state.cursor(), (11, 0));
     }
 
@@ -258,11 +253,8 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["? 🔍 ›     "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 1, 1), Style::new().bold());
-        expected.set_style(Rect::new(4, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line!["?".cyan(), " ", "🔍".bold(), " › ".cyan().dim(), "    "];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
         assert_eq!(state.cursor(), (7, 0));
     }
 
@@ -274,11 +266,14 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["✔ prompt ›     "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), COMPLETE_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line![
+            "✔".green(),
+            " ",
+            "prompt".bold(),
+            " › ".cyan().dim(),
+            "    "
+        ];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
     }
 
     #[test]
@@ -289,11 +284,8 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["✘ prompt ›     "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), ABORTED_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line!["✘".red(), " ", "prompt".bold(), " › ".cyan().dim(), "    "];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
     }
 
     #[test]
@@ -304,11 +296,14 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["? prompt › value              "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line![
+            "?".cyan(),
+            " ",
+            "prompt".bold(),
+            " › ".cyan().dim(),
+            "value              ".to_string()
+        ];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
     }
 
     #[test]
@@ -325,9 +320,9 @@ mod tests {
             "│? prompt ›   │",
             "└─────────────┘",
         ]);
-        expected.set_style(Rect::new(1, 1, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(3, 1, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(9, 1, 3, 1), Style::new().cyan().dim());
+        expected.set_style(Rect::new(1, 1, 1, 1), Color::Cyan);
+        expected.set_style(Rect::new(3, 1, 6, 1), Modifier::BOLD);
+        expected.set_style(Rect::new(9, 1, 3, 1), (Color::Cyan, Modifier::DIM));
         assert_buffer_eq!(buffer, expected);
     }
 
@@ -339,11 +334,14 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["? prompt › *****              "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line![
+            "?".cyan(),
+            " ",
+            "prompt".bold(),
+            " › ".cyan().dim(),
+            "*****              ".to_string()
+        ];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
     }
 
     #[test]
@@ -354,110 +352,106 @@ mod tests {
 
         prompt.render(buffer.area, &mut buffer, &mut state);
 
-        let mut expected = Buffer::with_lines(vec!["? prompt ›                    "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-        assert_buffer_eq!(buffer, expected);
+        let line = line![
+            "?".cyan(),
+            " ",
+            "prompt".bold(),
+            " › ".cyan().dim(),
+            "                   ".to_string()
+        ];
+        assert_buffer_eq!(buffer, Buffer::with_lines([line]));
     }
 
-    #[test]
-    fn draw_no_wrap() -> Result<(), Box<dyn std::error::Error>> {
-        let prompt = TextPrompt::from("prompt");
-        let mut state = TextState::new().with_value("hello");
-        let backend = TestBackend::new(17, 2);
-        let mut terminal = Terminal::new(backend)?;
+    #[fixture]
+    fn terminal() -> Terminal<TestBackend> {
+        Terminal::new(TestBackend::new(17, 2)).unwrap()
+    }
 
-        let mut expected = Buffer::with_lines(vec!["? prompt › hello ", "                 "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
+    type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
 
+    #[rstest]
+    fn draw_not_focused<'a>(mut terminal: Terminal<impl Backend>) -> Result<()> {
+        let prompt = TextPrompt::from("prompt");
+        let mut state = TextState::new().with_value("hello");
         // The cursor is not changed when the prompt is not focused.
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
+        let _ = terminal.draw(|frame| prompt.draw(frame, frame.size(), &mut state))?;
         assert_eq!(state.cursor(), (11, 0));
         assert_eq!(terminal.backend_mut().get_cursor().unwrap(), (0, 0));
+        Ok(())
+    }
 
+    #[rstest]
+    fn draw_focused<'a>(mut terminal: Terminal<impl Backend>) -> Result<()> {
+        let prompt = TextPrompt::from("prompt");
+        let mut state = TextState::new().with_value("hello");
         // The cursor is changed when the prompt is focused.
         state.focus();
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
+        let _ = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
         assert_eq!(state.cursor(), (11, 0));
         assert_eq!(terminal.backend_mut().get_cursor().unwrap(), (11, 0));
+        Ok(())
+    }
 
+    #[rstest]
+    #[case::position_0(0, (11, 0))] // start of value
+    #[case::position_3(2, (13, 0))] // middle of value
+    #[case::position_4(4, (15, 0))] // last character of value
+    #[case::position_5(5, (16, 0))] // one character beyond the value
+    #[case::position_6(6, (0, 1))] // FIXME: should not go beyond the value
+    #[case::position_7(7, (1, 1))] // FIXME: should not go beyond the value
+    #[case::position_22(22, (16, 1))] // FIXME: should not go beyond the value
+    #[case::position_99(99, (16, 1))] // FIXME: should not go beyond the value
+    fn draw_unwrapped_position<'a>(
+        #[case] position: usize,
+        #[case] expected_cursor: (u16, u16),
+        mut terminal: Terminal<impl Backend>,
+    ) -> Result<()> {
+        let prompt = TextPrompt::from("prompt");
+        let mut state = TextState::new().with_value("hello");
+        // expected: "? prompt › hello "
+        //           "                 "
+        // position:             012345
+        // cursor:    01234567890123456
         // The cursor is changed when the prompt is focused and the position is changed.
-        *state.position_mut() = 3;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (14, 0));
-        assert_eq!(terminal.get_cursor()?, (14, 0));
-
-        // The cursor does not go beyond the end of the value.
-        *state.position_mut() = 100;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        // FIXME (I think these both should be 16, 0 probably)
-        assert_eq!(state.cursor(), (16, 1));
-        assert_eq!(terminal.get_cursor()?, (16, 1));
+        state.focus();
+        *state.position_mut() = position;
+        let _ = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
+        assert_eq!(state.cursor(), expected_cursor);
+        assert_eq!(terminal.get_cursor()?, expected_cursor);
 
         Ok(())
     }
 
-    #[test]
-    #[allow(clippy::cognitive_complexity)]
-    fn draw_wrapped() -> Result<(), Box<dyn std::error::Error>> {
+    #[rstest]
+    #[case::position_0(0, (11, 0))] // start of value
+    #[case::position_1(3, (14, 0))] // middle of value
+    #[case::position_5(5, (16, 0))] // end of line
+    #[case::position_6(6, (0, 1))] // first character of the second line
+    #[case::position_7(7, (1, 1))] // second character of the second line
+    #[case::position_11(10, (4, 1))] // last character of the value
+    #[case::position_12(12, (6, 1))] // one character beyond the value
+    #[case::position_13(13, (7, 1))] // FIXME: should not go beyond the value
+    #[case::position_22(22, (16, 1))] // FIXME: should not go beyond the value
+    #[case::position_99(99, (16, 1))] // FIXME: should not go beyond the value
+    fn draw_wrapped_position<'a>(
+        #[case] position: usize,
+        #[case] expected_cursor: (u16, u16),
+        mut terminal: Terminal<impl Backend>,
+    ) -> Result<()> {
         let prompt = TextPrompt::from("prompt");
         let mut state = TextState::new().with_value("hello world");
-        let backend = TestBackend::new(17, 2);
-        let mut terminal = Terminal::new(backend)?;
-
-        let mut expected = Buffer::with_lines(vec!["? prompt › hello ", "world            "]);
-        expected.set_style(Rect::new(0, 0, 1, 1), PENDING_STYLE);
-        expected.set_style(Rect::new(2, 0, 6, 1), Style::new().bold());
-        expected.set_style(Rect::new(8, 0, 3, 1), Style::new().cyan().dim());
-
-        // The cursor is not changed when the prompt is not focused.
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (11, 0));
-        assert_eq!(terminal.get_cursor()?, (0, 0));
-
-        // The cursor is changed when the prompt is focused.
-        state.focus();
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (11, 0));
-        assert_eq!(terminal.get_cursor()?, (11, 0));
-
+        // line 1:   "? prompt › hello "
+        // position:             012345
+        // cursor:    01234567890123456
+        // line 2:   "world            "
+        // position:  678901
+        // cursor:    01234567890123456
         // The cursor is changed when the prompt is focused and the position is changed.
-        *state.position_mut() = 3;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (14, 0));
-        assert_eq!(terminal.get_cursor()?, (14, 0));
-
-        // The cursor wraps to the first column of the next line
-        *state.position_mut() = 6;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (0, 1));
-        assert_eq!(terminal.get_cursor()?, (0, 1));
-
-        // The cursor continues to cover the second line
-        *state.position_mut() = 7;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        assert_eq!(state.cursor(), (1, 1));
-        assert_eq!(terminal.get_cursor()?, (1, 1));
-
-        // The cursor does not go beyond the end of the value.
-        *state.position_mut() = 100;
-        let frame = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
-        assert_buffer_eq!(*frame.buffer, expected);
-        // FIXME (I think these both should be (5, 1) probably)
-        assert_eq!(state.cursor(), (16, 1));
-        assert_eq!(terminal.get_cursor()?, (16, 1));
+        state.focus();
+        *state.position_mut() = position;
+        let _ = terminal.draw(|frame| prompt.clone().draw(frame, frame.size(), &mut state))?;
+        assert_eq!(state.cursor(), expected_cursor);
+        assert_eq!(terminal.get_cursor()?, expected_cursor);
 
         Ok(())
     }