| name | con-cli-e2e |
| description | Validate Con's local socket control plane against a real running app session, and write/run con-test integration tests. Use when testing con-cli, the Unix socket API, pane control, tmux control, in-session agent calls, or when writing E2E test cases in crates/con-test/testdata/. |
con-cli E2E & con-test
Use this skill when the task is to verify that Con's CLI/control plane works against a live app window, or when writing/fixing integration tests in crates/con-test/testdata/.
Primary reference:
con-cli manual E2E
Default workflow:
- Build the relevant crates.
- Launch
cargo run -p con.
- Wait for
/tmp/con.sock.
- Use
con-cli --json identify, tabs list, and panes list before acting.
- Only use
panes exec on panes that expose exec_visible_shell.
- Use
tree / surfaces list only for pane-local surface validation.
- After
surfaces create or surfaces split, use surfaces wait-ready --surface-id <id> --timeout 10 before sending input that assumes an initialized shell.
- Use
agent ask to verify the real in-tab built-in agent session.
Rules:
- Prefer
--json for every command in automated evaluation.
- Prefer
pane_id over pane_index for follow-up actions.
- Prefer
surface_id for follow-up actions only when testing the explicit surfaces.* API.
- Keep existing pane and agent benchmarks on
panes.*; surfaces are additive and must not change the built-in agent's pane model.
- After visible execution, confirm the pane still reports
shell_prompt and keeps exec_visible_shell.
- If
agent ask fails, check provider config/env before blaming the socket layer.
Known current limit:
panes create now reports surface_ready, is_alive, and has_shell_integration, but startup-command panes can still be in a non-shell foreground state immediately after creation. Treat them as provisional until panes list confirms the capabilities you need for the next step.
con-test integration tests
con-test is the E2E test runner for integration and interactive behavior. It launches a real con session, runs .test files against it via con-cli, and checks output.
Running tests
cargo build
./target/debug/con-test crates/con-test/testdata/
./target/debug/con-test crates/con-test/testdata/panes/split.test
Test file format
Test files live in crates/con-test/testdata/<group>/<name>.test. Each step is a con-cli command followed by an assertion block:
# comment
con-cli --json <command> # step description
---- <assertion>
<expected>
Assertion types:
| Assertion | Meaning |
|---|
---- ok | Command exits 0 (any output accepted) |
---- contains | stdout contains the literal string on the next line |
---- json-subset | actual JSON is a superset of the expected JSON (subset match, deep) |
The json-subset assertion only checks the keys you specify — extra fields in the actual output are ignored. Use it to assert specific fields without coupling to the full response shape.
Writing new tests
- Unit-test functions in Rust (
#[cfg(test)]) for logic. Use con-test only for integration and interactive behavior that requires a live session.
- No low-value tests — don't write tests just to hit coverage. Every test should catch a real bug or document a real contract.
- Group tests by domain:
panes/, tabs/, agent/, system/.
- After
panes create, always add a panes wait step before asserting is_alive — the new pane's surface may not be ready immediately.
- For agent panel tests, use
agent open-panel-for-request to drive the motion state, then agent panel-state to assert the result.
Example test
# panes/split.test
con-cli --json panes list --tab 1 # start with 1 pane
---- json-subset
{"panes":[{"index":1}]}
con-cli --json panes create --tab 1 --location right # split right
---- ok
con-cli --json panes wait --tab 1 --pane-index 2 --timeout 5 # wait for new pane
---- ok
con-cli --json panes list --tab 1 # both panes alive
---- json-subset
{"panes":[{"is_alive":true},{"is_alive":true}]}
Fixing failures
When a test fails with expected JSON is not a subset of actual JSON, the actual output is printed in full. Check:
- Is the command missing (unrecognized subcommand)? → Add the subcommand to
con-cli and the ControlCommand handler.
- Is a field wrong/missing? → Fix the handler's response shape.
- Is the assertion racing (e.g.
is_alive: false right after create)? → Add a panes wait or surfaces wait-ready step before the assertion.