cli-e2e-testing
Skill9 starsChanged 6 months agoMITView on GitHub
Use when creating, modifying, debugging, or reviewing end-to-end tests for any CLI tool that must run in a real terminal, accept keyboard input, and expose observable terminal output. Prefer Hex1b terminal automation for PTY/headless terminal flows.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- dotnet/aspiretheir own version, first seen Oct 8, 2026
- microsoft/aspiretheir own version, first seen May 27, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- dotnet/aspire★ 6.4ksame name
- microsoft/aspire★ 6.4ksame name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository29 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- cli-e2e-testingSkill
- crap-scoreSkill
- detect-static-dependenciesSkill
- dotnet-livecharts2Skill
- dotnet-modern-csharp-editorconfigSkill
- dotnet-test-frameworksSkill
- filter-syntaxSkill
- generate-testability-wrappersSkill
- migrate-static-to-wrapperSkill
- mtp-hot-reloadSkill
- platform-detectionSkill
- run-testsSkill
- test-anti-patternsSkill
- writing-mstest-testsSkill
- crap-scoreSkill
- detect-static-dependenciesSkill
- dotnet-livecharts2Skill
- dotnet-modern-csharp-editorconfigSkill
- dotnet-test-frameworksSkill
- filter-syntaxSkill
- generate-testability-wrappersSkill
- migrate-static-to-wrapperSkill
- mtp-hot-reloadSkill
- platform-detectionSkill
- run-testsSkill
- test-anti-patternsSkill
- writing-mstest-testsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
27 rules. About 0 are common, 18 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈18
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 19
Use this skill when a CLI test must exercise the real executable through a terminal-like environment instead of calling internal APIs or …
- Very specific: line 31
Avoid Hex1b for simple non-interactive commands where ProcessStartInfo with redirected output is enough.
- Distinctive: line 35
Create an isolated temporary workspace.
- Distinctive: line 36
Create deterministic test fixtures and fake external tools/services as needed.
- Very specific: line 37
Start a Hex1bTerminal with:
- Very specific: line 45
Stop the shell/process in finally.
- Distinctive: line 46
Keep the recording as a test artifact for visual review.
- Distinctive: line 108
Use a unique filename that includes the test name and a GUID or timestamp.
- Very specific: line 109
Write the recording path to test output, for example through ITestOutputHelper.
- Distinctive: line 110
Do not commit recordings; keep them as local or CI artifacts.
- Very specific: line 111
Keep CaptureInput disabled unless a test explicitly needs to review typed input.
- Very specific: line 112
Use IdleTimeLimit to compress long pauses in playback.
- Distinctive: line 113
Ensure the terminal is disposed before asserting the recording is complete.
- Distinctive: line 136
Prefer deterministic waits over sleeps:
- Distinctive: line 146
Use a unique command-completion sentinel when driving a shell:
- Very specific: line 152
Wait for __DONE:0__ for success.
- Distinctive: line 156
Wait for the prompt/list before sending input:
- Distinctive: line 174
After keyboard input that changes the UI, wait for a visible result before continuing.
- Distinctive: line 178
Keep e2e tests deterministic:
- Distinctive: line 182
Avoid network calls unless the test category explicitly says it is live.
- Distinctive: line 183
Use per-test temp directories for HOME, config, cache, and package locations when the CLI reads global state.
- Distinctive: line 184
Prefer real local files and real process execution over mocks for the CLI itself.
- Very specific: line 194
Use GetScreenText() for visible terminal contents.
- Distinctive: line 200
When diagnosing a failing test:
- Distinctive: line 202
Check the failed wait description.
- Distinctive: line 205
Verify the wait text is literal and not accidentally matching echoed command text.
- Very specific: line 206
Verify the CLI process inherited the intended PATH, HOME/config variables, and working directory.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLI End-to-End Testing
Use this skill when a CLI test must exercise the real executable through a terminal-like environment instead of calling internal APIs or redirecting standard input/output.
Fit
Hex1b is a good fit when tests need any of these:
- A real PTY-backed child process such as
bash,zsh,pwsh, or the CLI itself. - Terminal screen inspection after ANSI output, cursor movement, tables, progress bars, or interactive prompts.
- Keyboard input such as arrows, Enter, Escape, Ctrl+C, text typing, or selection-list navigation.
- Headless CI execution without opening a real terminal window.
- Debuggable failures with a terminal snapshot, step history, and replayable terminal recording.
Avoid Hex1b for simple non-interactive commands where ProcessStartInfo with redirected output is enough.
Test Architecture
- Create an isolated temporary workspace.
- Create deterministic test fixtures and fake external tools/services as needed.
- Start a
Hex1bTerminalwith:WithHeadless()- fixed dimensions large enough for the expected output
WithPtyProcess(...)for the shell or CLI process under testWithAsciinemaRecording(...)writing to a per-test.castfile
- Wrap it in
Hex1bTerminalAutomator. - Type commands, send keys, and wait for specific output.
- Inspect terminal snapshots and side effects.
- Stop the shell/process in
finally. - Keep the recording as a test artifact for visual review.
Basic Pattern
using Hex1b;
using Hex1b.Automation;
using Hex1b.Input;
await using var terminal = Hex1bTerminal.CreateBuilder()
.WithHeadless()
.WithDimensions(160, 80)
.WithPtyProcess(options =>
{
options.FileName = "/bin/bash";
options.Arguments = ["--noprofile", "--norc", "-i"];
options.WorkingDirectory = workspace;
options.Environment = new Dictionary<string, string>
{
["TERM"] = "xterm-256color",
["PATH"] = testBin + Path.PathSeparator + (Environment.GetEnvironmentVariable("PATH") ?? "")
};
})
.WithAsciinemaRecording(
recordingPath,
new AsciinemaRecorderOptions
{
Title = "my-cli end-to-end test",
Command = "my-cli",
IdleTimeLimit = 1
})
.Build();
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(90));
var runTask = terminal.RunAsync(cts.Token);
var auto = new Hex1bTerminalAutomator(terminal, defaultTimeout: TimeSpan.FromSeconds(30));
try
{
await auto.TypeAsync("my-cli --dry-run; printf '\\n__DONE:%s__\\n' \"$?\"");
await auto.EnterAsync();
await auto.WaitUntilTextAsync("__DONE:0__", timeout: TimeSpan.FromSeconds(60));
using var snapshot = auto.CreateSnapshot();
string screen = snapshot.GetScreenText();
Assert.Contains("Expected output", screen, StringComparison.Ordinal);
}
finally
{
await auto.TypeAsync("exit");
await auto.EnterAsync();
await runTask.WaitAsync(TimeSpan.FromSeconds(5));
}Recordings
Make Hex1b asciinema recordings a standard artifact for terminal e2e tests. This gives reviewers a visual playback of what happened without changing the CLI tool under test.
Recording guidelines:
- Store recordings outside any disposable temp workspace, typically under the test project's
TestResults/recordingsdirectory. - Use a unique filename that includes the test name and a GUID or timestamp.
- Write the recording path to test output, for example through
ITestOutputHelper. - Do not commit recordings; keep them as local or CI artifacts.
- Keep
CaptureInputdisabled unless a test explicitly needs to review typed input. It is disabled by default. - Use
IdleTimeLimitto compress long pauses in playback. - Ensure the terminal is disposed before asserting the recording is complete.
Example recording path helper:
static string CreateRecordingPath(string testName)
{
string recordingDirectory = Path.Combine(ProjectDirectory, "TestResults", "recordings");
_ = Directory.CreateDirectory(recordingDirectory);
return Path.Combine(recordingDirectory, $"{testName}-{Guid.NewGuid():N}.cast");
}Visual verification:
asciinema play tests/MyCli.LiveTests/TestResults/recordings/MyTest-abc123.castFor CI, upload TestResults/recordings/*.cast as test artifacts so failures can be replayed locally.
Waiting
Prefer deterministic waits over sleeps:
await auto.WaitUntilTextAsync("Select an option");
await auto.WaitUntilAsync(
snapshot => snapshot.ContainsText("Ready") && !snapshot.ContainsText("Loading"),
timeout: TimeSpan.FromSeconds(30),
description: "CLI to finish loading");Use a unique command-completion sentinel when driving a shell:
my-cli args; printf '\n__DONE:%s__\n' "$?"Wait for __DONE:0__ for success. If testing failures, wait for the expected non-zero sentinel.
Keyboard Input
Wait for the prompt/list before sending input:
await auto.WaitUntilTextAsync("select which to apply:");
await auto.LeftAsync();
await auto.WaitUntilTextAsync("[ ] first-item");
await auto.EnterAsync();Useful automator methods:
TypeAsync("text")EnterAsync()UpAsync(),DownAsync(),LeftAsync(),RightAsync()SpaceAsync()EscapeAsync()Ctrl().KeyAsync(Hex1bKey.C)
After keyboard input that changes the UI, wait for a visible result before continuing.
External Dependencies
Keep e2e tests deterministic:
- Stub external CLIs by putting scripts in a temporary
bindirectory and prepending it toPATH. - Log stub invocations to a temp file when assertions need to prove what was called.
- Avoid network calls unless the test category explicitly says it is live.
- Use per-test temp directories for HOME, config, cache, and package locations when the CLI reads global state.
- Prefer real local files and real process execution over mocks for the CLI itself.
Assertions
Assert both terminal output and side effects:
- Output: summary lines, prompts, selected item state, error messages, completion sentinel.
- Side effects: files created/updated, command log contents, exit code sentinel.
- Negative checks: no install/update command was invoked, no directive block was written, no unexpected prompt appeared.
Use GetScreenText() for visible terminal contents. If important output can scroll out of view, use larger fixed dimensions, add a sentinel near the end, or assert side effects and inspect the Hex1b recording.
Failure Diagnostics
Hex1b automation failures include step history and terminal snapshots. Make wait descriptions specific enough to identify the failed phase.
When diagnosing a failing test:
- Check the failed wait description.
- Inspect the terminal snapshot from the exception.
- Play the
.castrecording to see the terminal flow exactly as the test saw it. - Verify the wait text is literal and not accidentally matching echoed command text.
- Verify the CLI process inherited the intended
PATH, HOME/config variables, and working directory. - Confirm the test waited for the UI to rerender after each key input.
Common Pitfalls
- Matching command text echoed by the shell instead of output produced after execution.
- Pressing Enter immediately after a key input without waiting for the terminal UI to update.
- Relying on arbitrary delays instead of
WaitUntilTextAsyncorWaitUntilAsync. - Letting tests use the developer machine's real CLI extensions, global config, or network credentials.
- Using a terminal height too small for the output under test.
- Writing recordings into a temp workspace that the test deletes before the developer can replay them.
- Asserting a file was not created when the CLI intentionally creates scaffolding even with no selected actions; assert the meaningful content instead.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

