e2e

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package e2e drives the compiled binary inside a real terminal so that rendering, key handling and resize behaviour can be asserted on the frames a user would actually see.

It uses tmux as a scriptable terminal. Two tmux facts shape this package and were verified empirically rather than assumed:

  • resize-window changes the size of a detached session's pseudo-terminal and the process receives SIGWINCH. resize-pane does not: on a window with a single pane it silently does nothing, so a resize test built on it would pass while never resizing anything.
  • capture-pane without a scrollback range captures the visible screen, which for a full-screen program is the alternate screen buffer. Scrollback captures do not contain alternate-screen output at all.

Every Terminal runs on its own tmux server socket, so a test can never disturb a tmux session the user is working in.

Index

Constants

This section is empty.

Variables

View Source
var ErrTimeout = errors.New("timed out waiting for the terminal")

ErrTimeout is returned when a wait gives up.

Functions

func Available

func Available() error

Available reports whether tmux is usable, so tests can skip cleanly rather than fail on a machine without it.

Types

type Options

type Options struct {
	// Width and Height are the initial terminal size in character cells.
	Width, Height int
	// Dir is the working directory for the command.
	Dir string
	// Env holds extra environment entries in KEY=VALUE form. TERM and the
	// colour-related variables are set for you unless you override them.
	Env []string
	// Color leaves colour enabled. By default colour is switched off so that
	// captured frames are stable text.
	Color bool
}

Options configures a Terminal.

type Terminal

type Terminal struct {
	// contains filtered or unexported fields
}

Terminal is a tmux-hosted terminal running one command.

func Start

func Start(t *testing.T, command string, opts Options) *Terminal

Start launches command in a new terminal of the requested size. The command is run through the shell, so it may contain arguments. The Terminal is closed automatically when the test finishes.

func (*Terminal) Alive

func (tm *Terminal) Alive() bool

Alive reports whether the program is still running.

func (*Terminal) AssertFits

func (tm *Terminal) AssertFits()

AssertFits checks the invariant every frame must satisfy: no line wider than the terminal and no more lines than it has rows. A frame that breaks this corrupts the display and is the most common resize bug.

func (*Terminal) Capture

func (tm *Terminal) Capture() string

Capture returns the visible screen as plain text with trailing blanks trimmed from each line.

func (*Terminal) CaptureANSI

func (tm *Terminal) CaptureANSI() string

CaptureANSI returns the visible screen including escape sequences, for assertions where styling is the thing under test.

func (*Terminal) Close

func (tm *Terminal) Close()

Close kills the tmux server backing this terminal.

func (*Terminal) ExitStatus

func (tm *Terminal) ExitStatus() (int, bool)

ExitStatus returns the program's exit status, and whether it has exited.

func (*Terminal) Lines

func (tm *Terminal) Lines() []string

Lines returns the visible screen split into lines.

func (*Terminal) MustWaitFor

func (tm *Terminal) MustWaitFor(substr string, timeout time.Duration) string

MustWaitFor is WaitFor with the error turned into a test failure.

func (*Terminal) Resize

func (tm *Terminal) Resize(width, height int)

Resize changes the terminal size, which delivers SIGWINCH to the program.

func (*Terminal) ResizeAndWait

func (tm *Terminal) ResizeAndWait(width, height int, timeout time.Duration) string

ResizeAndWait changes the size and waits for the program to redraw, which is the only safe way to assert on a frame after a resize.

func (*Terminal) SendKeys

func (tm *Terminal) SendKeys(keys ...string)

SendKeys sends key names to the program. Names are tmux key names, so "Enter", "Escape", "C-c", "Up" and plain characters all work.

func (*Terminal) SendText

func (tm *Terminal) SendText(text string)

SendText sends literal text, which is safer than SendKeys for characters tmux would interpret as key names.

func (*Terminal) Size

func (tm *Terminal) Size() (width, height int)

Size returns the size tmux reports for the pane, which is the size the program actually sees. It is not necessarily the size passed to Start or Resize, so assertions about wrapping should use this.

func (*Terminal) WaitChanged

func (tm *Terminal) WaitChanged(previous string, timeout time.Duration) string

WaitChanged blocks until the screen differs from previous and has then stopped changing, and returns the new screen.

This is the wait to use after anything that should redraw. WaitSettled alone is not enough: it returns as soon as the screen has held still for a moment, and immediately after a resize the screen is still the old one and perfectly still, so a caller can be handed the frame from before the change and assert against it. That is not a hypothetical — it is how a genuine recovery from the too-small state looked like a failure to recover.

func (*Terminal) WaitFor

func (tm *Terminal) WaitFor(substr string, timeout time.Duration) (string, error)

WaitFor blocks until the screen contains substr. It returns the screen that matched.

func (*Terminal) WaitSettled

func (tm *Terminal) WaitSettled(timeout time.Duration) string

WaitSettled blocks until the screen has stopped changing, and returns it. Polling for a stable frame is deterministic where sleeping for a guessed duration is not: a slow machine makes a sleep too short, never too long.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL