Open mikaelmello opened 2 years ago
Layer 1: receive a sequence of commands as input. This layer could not even know about the existence of keystrokes.
Layer 2: receive a sequence of ui::key::Key
s. Then they will be handled by the normal key handler implemented by each prompt.
Layer 3: Full E2E testing with a tty. This will allow us to test our integrations with each terminal backend. enigo might be a good way to go about it
Hey @mikaelmello 👋
I am relatively new to Rust and starting playing with this library for a cool way for my cli tools to take input from users rather than always as args.
I really like this library. The type to filter functionality in the select and multiselect was a cool surprise for me. Nice! 👍
I’m trying to convince my boss to use Rust and things like this at work, but they want to see good tests for “enterprise level code”.
I took a stab at it on my own, but I’m not exactly sure how to go from the ‘Key’ to making it think that key was pressed. See this related issue .
I think sending the raw Key events is fine for me- at least it will allow me to navigate through the prompts and get stuff done.
I think at least adding an example of doing this in the README could be an easy win.
I do also like the idea of having some higher level commands though… for example a function that takes a vec of choices and under the hood maps to all the arrow / filtering / space key presses that go into selecting a bunch of things on a multiselect…
I have some bandwidth to think about this if you need any help as well.
Thanks!
hey @JimLynchCodes , 100%. Unfortunately this hasn't been implemented as of now, a few months back I did try tackling this but it was more complex than I expected, so it kind of got brushed aside, I intend to revisit it over the next couple of weeks
No worries @mikaelmello. It's not super urgent for me. Here are some things I've been trying, nothing exactly working yet but it might be interesting to you... actually ChatGPT gave me some of this code, but it doesn't compile. 😆 😅
I think a chainable "stdin" function like this where I can just pass in a string would be a nice API, at least for "Confirm".
let output = Command::cargo_bin("mybin")
.unwrap()
.current_dir(temp_dir.path())
.stdin("yes\n") // Mock the user input
.stdin(Stdio::piped("foo"))
.assert()
.success();
assert_eq!(output, "You said yes!");
Unfortunately though, this "stdin" function doesn't take a string or string slice... here is my compiler error:
----- ^^^^^^^ the trait `From<&str>` is not implemented for `Stdio`
| |
| required by a bound introduced by this call
I also tried using this strange and imo very ugly syntax, but I am still getting a compile error, "no method names as_mut
found for struct Assert
in the current scope" 🤔
use std::io::{Read, Write};
use std::process::{Command, Stdio};
...
let mut child_process = Command::new("mybin")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
// Send input to the child process
let input_data = "hello world\n";
child_process
.stdin
.as_mut()
.unwrap()
.write_all(input_data.as_bytes())
.unwrap();
// Read output from the child process
let mut output_data = String::new();
child_process
.stdout
.as_mut()
.unwrap()
.read_to_string(&mut output_data)
.unwrap();
// Wait for the child process to exit
let exit_status = child_process.wait().unwrap();
If anyone finds it helpful, I had some basic success with using https://github.com/rust-cli/rexpect to test inquire
CLIs.
That is indeed really helpful, I found the project where you're doing that (cargo-wizard right? really awesome btw)!
Will take some inspiration from it when I find the time: https://github.com/Kobzol/cargo-wizard/blob/main/tests/integration/utils/terminal.rs
@JimLynchCodes assert_cmd
provides a write_stdin
that you can use to write stdin:
#[test]
fn om_init() -> anyhow::Result<()> {
let temp_dir = assert_fs::TempDir::new().unwrap();
om()?
.arg("init")
.arg(temp_dir.path())
.write_stdin("\n\n")
.assert()
.success();
temp_dir.close().unwrap();
Ok(())
}
However, this crashes at runtime (during Select
prompt) throwing
IO error: Failed to initialize input reader
Error: The input device is not a TTY
(https://github.com/assert-rs/assert_cmd/issues/138)
This will allow both we and our users to make the prompts fully testable.
It will heavily rely on #70