I am trying to write functional tests for a Click-based CLI using pytest and click.testing. My program relies on click.prompt, which is a blocking command that waits for user input. When running the program from a bash script, the program correctly exits once stdin reaches EOF, but when testing it using CliRunner, the test hangs indefinitely as the runner does not handle EOF in the same way. Here’s a simplified example that demonstrates the issue. The program is supposed to prompt for a number a certain number of times, defined by the --size option. However, due to an intentional BUG, the program prompts for more inputs than provided, which causes the test to never finish: import click import click.testing @click.command() @click.option("-s", "--size", type=int, default=3) def main(size): BUG = 5 for i in range(size + BUG): value = click.prompt("", type=int) click.echo(f"{value}") def test_cli(): runner = click.testing.CliRunner() result = runner.invoke(main, ["-s", "5"], input="1\n2\n3\n4\n5\n") assert result.stdout == "1\n2\n3\n4\n5\n" assert result.exit_code == 0 if __name__ == "__main__": main() test_cli() When running the program directly from the shell, it behaves as expected. If fewer inputs are provided than the number of prompts, the program exits with an abort once EOF is reached: $ echo -e "1\n" | python foo.py Enter a number: 1 Enter a number: Enter a number: Aborted! However when using CliRunner for testing, the test hangs indefinitely once it reaches the missing inputs. Unlike the behavior in bash, CliRunner does not handle EOF and keeps waiting for additional input. This becomes a significant issue in continuous integration (CI) environments, where tests are expected to terminate correctly. Here what I tried so far: Simulating EOF with \xff: I tried appending \xff to the input to simulate the end of input, but the issue remains. Using BytesIO: I attempted using a BytesIO object for the input stream, but the test still hangs. Applying a Timeout: I added @pytest.mark.timeout(1) before the test_cli function to enforce a timeout. While this prevents the test from hanging indefinitely, it does not solve the underlying issue with click.prompt not handling EOF. How can I resolve this issue where click.prompt in the test does not properly handle EOF when using click.testing.CliRunner? Is there a reliable way to simulate EOF in tests so that the test terminates when the input is exhausted, as it does when running from a bash script? Continue reading...