$npx -y skills add nowledge-co/con-terminal --skill con-cli-e2eValidate 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/.
| 1 | # con-cli E2E & con-test |
| 2 | |
| 3 | 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/`. |
| 4 | |
| 5 | Primary reference: |
| 6 | |
| 7 | - Read [`docs/impl/con-cli-e2e.md`](../../docs/impl/con-cli-e2e.md) for the full workflow and current live limitations. |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## con-cli manual E2E |
| 12 | |
| 13 | Default workflow: |
| 14 | |
| 15 | 1. Build the relevant crates. |
| 16 | 2. Launch `cargo run -p con`. |
| 17 | 3. Wait for `/tmp/con.sock`. |
| 18 | 4. Use `con-cli --json identify`, `tabs list`, and `panes list` before acting. |
| 19 | 5. Only use `panes exec` on panes that expose `exec_visible_shell`. |
| 20 | 6. Use `tree` / `surfaces list` only for pane-local surface validation. |
| 21 | 7. After `surfaces create` or `surfaces split`, use `surfaces wait-ready --surface-id <id> --timeout 10` before sending input that assumes an initialized shell. |
| 22 | 8. Use `agent ask` to verify the real in-tab built-in agent session. |
| 23 | |
| 24 | Rules: |
| 25 | |
| 26 | - Prefer `--json` for every command in automated evaluation. |
| 27 | - Prefer `pane_id` over `pane_index` for follow-up actions. |
| 28 | - Prefer `surface_id` for follow-up actions only when testing the explicit `surfaces.*` API. |
| 29 | - Keep existing pane and agent benchmarks on `panes.*`; surfaces are additive and must not change the built-in agent's pane model. |
| 30 | - After visible execution, confirm the pane still reports `shell_prompt` and keeps `exec_visible_shell`. |
| 31 | - If `agent ask` fails, check provider config/env before blaming the socket layer. |
| 32 | |
| 33 | Known current limit: |
| 34 | |
| 35 | - `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. |
| 36 | |
| 37 | --- |
| 38 | |
| 39 | ## con-test integration tests |
| 40 | |
| 41 | `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. |
| 42 | |
| 43 | ### Running tests |
| 44 | |
| 45 | ```bash |
| 46 | # Build first |
| 47 | cargo build |
| 48 | |
| 49 | # Run all tests |
| 50 | ./target/debug/con-test crates/con-test/testdata/ |
| 51 | |
| 52 | # Run a single file |
| 53 | ./target/debug/con-test crates/con-test/testdata/panes/split.test |
| 54 | ``` |
| 55 | |
| 56 | ### Test file format |
| 57 | |
| 58 | Test files live in `crates/con-test/testdata/<group>/<name>.test`. Each step is a `con-cli` command followed by an assertion block: |
| 59 | |
| 60 | ``` |
| 61 | # comment |
| 62 | con-cli --json <command> # step description |
| 63 | ---- <assertion> |
| 64 | <expected> |
| 65 | ``` |
| 66 | |
| 67 | Assertion types: |
| 68 | |
| 69 | | Assertion | Meaning | |
| 70 | |---|---| |
| 71 | | `---- ok` | Command exits 0 (any output accepted) | |
| 72 | | `---- contains` | stdout contains the literal string on the next line | |
| 73 | | `---- json-subset` | actual JSON is a superset of the expected JSON (subset match, deep) | |
| 74 | |
| 75 | 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. |
| 76 | |
| 77 | ### Writing new tests |
| 78 | |
| 79 | - **Unit-test functions** in Rust (`#[cfg(test)]`) for logic. Use `con-test` only for integration and interactive behavior that requires a live session. |
| 80 | - **No low-value tests** — don't write tests just to hit coverage. Every test should catch a real bug or document a real contract. |
| 81 | - Group tests by domain: `panes/`, `tabs/`, `agent/`, `system/`. |
| 82 | - After `panes create`, always add a `panes wait` step before asserting `is_alive` — the new pane's surface may not be ready immediately. |
| 83 | - For agent panel tests, use `agent open-panel-for-request` to drive the motion state, then `agent panel-state` to assert the result. |
| 84 | |
| 85 | ### Example test |
| 86 | |
| 87 | ``` |
| 88 | # panes/split.test |
| 89 | con-cli --json panes list --tab 1 # start with 1 pane |
| 90 | ---- json-subset |
| 91 | {"panes":[{"index":1}]} |
| 92 | |
| 93 | con-cli --json panes create --tab 1 --location right # split right |
| 94 | ---- ok |
| 95 | |
| 96 | con-cli --json panes wait --tab 1 --pane-index 2 --timeout 5 # wait for new pane |
| 97 | ---- ok |
| 98 | |
| 99 | con-cli --json panes list --tab 1 # both panes alive |
| 100 | ---- json-subset |
| 101 | {"panes":[{"is_alive":true},{"is_alive":true}]} |
| 102 | ``` |
| 103 | |
| 104 | ### Fixing failures |
| 105 | |
| 106 | When a test fails with `expected JSON is not a subset of actual JSON`, the actual output is printed in full. Check: |
| 107 | |
| 108 | 1. Is the command missing (unrecognized subcommand)? → Add the subcommand to `con-cli` and the `ControlCommand` handler. |
| 109 | 2. Is a field wrong/missing? → Fix the handler's response shape. |
| 110 | 3. Is the assertion racing (e.g. `is_alive: false` right after create)? → Add a `panes wait` or `surfaces wait-ready` step before the assertion. |