How Freebuff Uses tmux Helper Scripts for End-to-End Testing

Freebuff drives its end-to-end test suite by launching the CLI inside a detached tmux session, using a combination of shell scripts in scripts/tmux/ and TypeScript wrappers in freebuff/e2e/utils/tmux-helpers.ts to programmatically control the interactive TUI.

Freebuff's testing framework relies on tmux helper scripts to create isolated terminal environments for reliable end-to-end validation. These utilities enable the test suite to launch the CLI application, inject commands, capture output, and clean up resources automatically. The architecture separates low-level tmux operations implemented in shell scripts from high-level orchestration logic written in TypeScript.

The Testing Architecture

The solution is split between Bash scripts handling raw tmux operations and TypeScript utilities providing a typed interface for test authors. The shell scripts reside in scripts/tmux/ while the programmatic API lives in freebuff/e2e/utils/tmux-helpers.ts. This separation allows the test suite to leverage tmux's terminal multiplexing capabilities while maintaining type safety and clean abstraction boundaries in the test code.

Starting a tmux Session with tmuxStart

The tmuxStart function builds the argument list and delegates to scripts/tmux/tmux-start.sh to initialize the testing environment.

Session Initialization and Metadata

According to the source code in /scripts/tmux/tmux-start.sh (lines 35-40), the script generates a unique session name or accepts a supplied identifier. It records session metadata under debug/tmux-sessions/<session>/ (lines 38-46), creating a dedicated directory for logs and debugging artifacts. The script finally prints the session name in plain text or JSON format (lines 76-84) for the TypeScript wrapper to consume.

Command Selection and Launch

The helper automatically determines which binary to execute. As implemented in lines 94-118 of tmux-start.sh, it prioritizes custom commands, falls back to compiled binaries, or defaults to bun dev if no specific target is provided. The session launches with configurable dimensions specified via the -w (width) and -h (height) parameters (lines 120-126), ensuring consistent terminal sizing across test runs.

Interacting with the Session

Once running, the test suite communicates with the tmux pane through three primary TypeScript functions defined in /freebuff/e2e/utils/tmux-helpers.ts (lines 33-71).

Sending Input and Keystrokes

The tmuxSend and tmuxSendKey functions invoke scripts/tmux/tmux-send.sh to feed text or special key events into the active pane. This allows tests to simulate user typing and keyboard shortcuts programmatically without blocking the main test process.

Capturing Terminal Output

For assertions and debugging, tmuxCapture executes scripts/tmux/tmux-capture.sh to retrieve the current visible content of the tmux pane. The capture script can also save timestamped GIFs of the terminal state, providing visual regression testing capabilities.

Session Lifecycle Management

Proper cleanup is critical for CI/CD environments to prevent resource leaks.

Safe Session Termination

The tmuxStop function (lines 73-82 in tmux-helpers.ts) executes scripts/tmux/tmux-stop.sh to kill the session. The underlying shell script is designed to be idempotent, silently ignoring "session not found" errors when called multiple times.

High-Level Orchestration with FreebuffSession

The FreebuffSession class in /freebuff/e2e/utils/freebuff-session.ts encapsulates the complete lifecycle (lines 28-71 and 112-123). It creates temporary project directories, starts the CLI via tmuxStart, and exposes methods like send(), sendKey(), capture(), and waitForReady(). The class ensures automatic cleanup by calling tmuxStop in its teardown methods.

Practical Usage Example

The following TypeScript pattern demonstrates how the Freebuff test suite utilizes these helpers to validate CLI behavior:

import { FreebuffSession } from './utils/freebuff-session'

// 1️⃣ Start a CLI instance in a tmux session
const session = await FreebuffSession.start('/path/to/cli/binary')

// 2️⃣ Wait until the UI is ready (enough non-empty lines)
await session.waitForReady()

// 3️⃣ Send a command (e.g., open a new file)
await session.send('new myfile.txt')

// 4️⃣ Capture the terminal output for verification
const output = await session.capture()
if (!output.includes('myfile.txt')) {
  throw new Error('File creation not reflected in UI')
}

// 5️⃣ Clean up the tmux session and temp directory
await session.stop()

Summary

  • tmuxStart in scripts/tmux/tmux-start.sh creates uniquely named sessions with configurable dimensions and stores metadata in debug/tmux-sessions/.
  • Interaction helpers (tmuxSend, tmuxSendKey, tmuxCapture) in freebuff/e2e/utils/tmux-helpers.ts wrap shell scripts to simulate user input and capture output.
  • tmuxStop provides idempotent cleanup, safely ignoring errors if sessions are already terminated.
  • FreebuffSession offers a high-level TypeScript API managing the full lifecycle from temporary directory creation to automatic resource cleanup.

Frequently Asked Questions

What tmux commands does Freebuff use for testing?

Freebuff uses a dedicated suite of shell scripts including tmux-start.sh to create detached sessions, tmux-send.sh to pipe input, tmux-capture.sh to read pane contents, and tmux-stop.sh for cleanup. These scripts handle the raw tmux CLI invocations while TypeScript wrappers in tmux-helpers.ts provide the test-friendly interface.

How does Freebuff handle session cleanup after tests?

The tmuxStop function executes scripts/tmux/tmux-stop.sh, which is designed to be idempotent and ignores "session not found" errors. The FreebuffSession class automatically triggers this cleanup during teardown, ensuring temporary directories and tmux sessions are removed even if tests fail.

Can I use Freebuff's tmux helpers for other CLI applications?

Yes, the architecture is generic enough to test any terminal-based application. The FreebuffSession.start() method accepts a path to any compiled binary or command, and the interaction methods (send, sendKey, capture) work with any process running inside the tmux pane.

Where does Freebuff store tmux session logs and snapshots?

Session metadata, logs, and timestamped captures are stored under debug/tmux-sessions/<session-name>/ as defined in /scripts/tmux/tmux-start.sh (lines 38-46). This directory structure provides isolated debugging artifacts for each test session, including optional GIF recordings of terminal activity.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →