Documentation
ΒΆ
Overview ΒΆ
Package steep provides test helpers for tea.Program and models (root and component).
Use NewHarness to run a root tea.Model in a test:
h := steep.NewHarness(t, model, steep.WithWindowSize(80, 24))
h.Type("hello").WaitSettle().Assert("hello")
h.QuitProgram()
h.WaitFinished()
Use NewComponentHarness for components that expose View() string and an Update method through the asynchronous tea.Program runtime.
Use NewExecHarness for a command, which need not use Bubble Tea, on a pseudo-terminal:
h := steep.NewExecHarness(t, exec.Command("./myapp"))
h.Wait("ready").Key("q")
if status := h.ExitStatus(); status != 0 {
t.Errorf("exit status = %d", status)
}
Hooks ΒΆ
Harness actions invoke Hook callbacks from WithHooks before and after the action body. Hook errors fail the test immediately. Once an action is done, it is marked in the timeline as "category:n", with its event and count, such as "input:2" or "wait:1", and each failure the harness reports is marked as "failure:1" and so on (see Harness.Mark). Those categories are reserved; use the same form for a test's own marks, such as "login:done" or "step:3", so tools reading a recording can group marks by category (see reel.SplitLabel). WithAutoMarks turns the harness's marks off.
Recording and export ΒΆ
A harness runs its program in a reel.Session, whose reel.Timeline records everything the program wrote and the test did. Recordings are made from the timeline, so a test never slows down to be recorded; WithSlow is only for programs that need real time between actions, and reel.Delay, passed to Harness.Type and the like, for recordings that should show text being typed.
The timeline also holds reel.Annotation events, described by reel's annotation.schema.json, of what the test did and found: its configuration ("steep.start"), the program's start and end ("steep.ready", "steep.exit"), inputs ("steep.input"), terminal changes and program actions ("steep.terminal", "steep.program"), waits ("steep.wait.start", "steep.wait.end"), assertions and snapshot comparisons ("steep.assert", "steep.snapshot"), failures ("steep.failure"), and the result ("steep.result"). Text fields over 4 KiB are cut and marked truncated. Messages the model receives ("steep.message") are only recorded with WithRecordMessages, which leaves out the environment (tea.EnvMsg). WithSource adds the file, line, and function of the test's line that led to each annotation and mark, and the test's package and module to "steep.start".
By default nothing is written: the timeline stays in memory, for Harness.Timeline. WithExportOnFailure exports when the test failed, and WithExportAlways whether it passed or failed. Either exports once, at Harness.Close, which runs as a test cleanup, so a test that fails, calls FailNow, or panics still exports. A test killed by "go test -timeout" writes nothing.
WithRecording sets what an export writes as a reel.Profile. Without outputs it writes "{name}_{status}.gif" and "{name}_{status}.cast" under WithArtifacts, or testing.TB.ArtifactDir, which is only kept with "go test -artifacts"; without it, an export logs that its files are removed. Absolute paths are written as they are. Each export logs the paths it wrote. WithStills adds a PNG or text snapshot at the marks of the hook events it names.
steep adds two effects to those in the effects package: Logo, an animated intro, and Outro, a PASS or FAIL card. Effects run by priority (see reel.Prioritizer), so effects.Pause pauses on the screen the test failed on before the card shows:
steep.WithRecording(reel.Profile{
Effects: []reel.Effect{
steep.Logo(2 * time.Second),
effects.Pause(),
effects.Keys(time.Second),
steep.Outro(2 * time.Second),
},
}),
steep.WithExportOnFailure(),
The ".cast" output is the timeline itself, from which reel.ReadTimeline and reel.Export can write the other outputs again. A profile with effects.Redact or effects.RedactInputs must therefore set outputs without ".cast" (see reel.ErrRawOutput).
Environment ΒΆ
These variables override the options set in code unless WithIgnoreEnv is set, so any test can be recorded or tuned without changing it. Unparsable values are ignored, except in STEEP_EXPORT.
- STEEP_TIMEOUT, STEEP_CHECK, STEEP_SETTLE, STEEP_SLOW: durations for WithTimeout, WithCheck, WithSettle, and WithSlow.
- STEEP_TYPING_DELAY: a duration to pause after each key press of Harness.Type and Harness.Key (reel.WithTypingDelay), unless a call passes reel.Delay.
- STEEP_LOG: on (or true, 1) adds the hook of WithLog.
- STEEP_RECORD_MESSAGES: on or off (or true, 1, false, 0) for WithRecordMessages.
- STEEP_SOURCE: on or off (or true, 1, false, 0) for WithSource.
- STEEP_SNAPSHOT_DIR: the default snapshot directory (snapshot.WithDir); a directory passed to a snapshot call still wins.
- STEEP_EXPORT_MODE: on (or always, true, 1) for WithExportAlways, failure (or on-failure) for WithExportOnFailure, off (or false, 0) for neither.
- STEEP_EXPORT_DIR: the directory of WithArtifacts.
- STEEP_EXPORT: replaces the outputs and stills with a comma-separated list of outputs (see reel.ParseFiles), each a path with optional query parameters, such as "{name}_{status}.gif?max-bytes=5MB" or "{name}_{mark}.snap?match=input:*". A path that holds {mark} with no marks or match parameter is a still at each hook mark of the events WithStills uses by default. An output that does not parse fails the test.
- STEEP_EXPORT_FPS, STEEP_EXPORT_SPEED: replace reel.Profile.FPS and reel.Profile.Speed.
- STEEP_RENDERER_SCALE, STEEP_RENDERER_FONT_FAMILY: appended to reel.Profile.Render.
For example:
STEEP_EXPORT_MODE=on STEEP_EXPORT='{name}.mp4,{name}_{mark}.png?match=wait:*' go test -artifacts ./...
Index ΒΆ
- Constants
- func Assert[T string | []string](tb testing.TB, view Viewable, content T, opts ...Option) bool
- func AssertDimensions(tb testing.TB, view Viewable, width, height int, opts ...Option) bool
- func AssertFor(tb testing.TB, view Viewable, cond reel.Condition, opts ...Option) bool
- func AssertHasMessage[T uv.Event](tb testing.TB, log MessageCollector, opts ...Option) bool
- func AssertHeight(tb testing.TB, view Viewable, n int, opts ...Option) bool
- func AssertNot[T string | []string](tb testing.TB, view Viewable, content T, opts ...Option) bool
- func AssertWidth(tb testing.TB, view Viewable, n int, opts ...Option) bool
- func Dimensions(tb testing.TB, out string, opts ...Option) (w, h int)
- func FilterMessagesFunc[T uv.Event](tb testing.TB, messages iter.Seq[uv.Event], fn func(T) bool) iter.Seq[T]
- func FilterMessagesType[T uv.Event](tb testing.TB, messages iter.Seq[uv.Event]) iter.Seq[T]
- func IgnoreMessagesReflect(tb testing.TB, messages iter.Seq[uv.Event], ignore ...reflect.Type) iter.Seq[uv.Event]
- func Logo(d time.Duration) reel.Effect
- func Outro(d time.Duration, lines ...effects.Line) reel.Effect
- func Require[T string | []string](tb testing.TB, view Viewable, content T, opts ...Option)
- func RequireDimensions(tb testing.TB, view Viewable, width, height int, opts ...Option)
- func RequireFor(tb testing.TB, view Viewable, cond reel.Condition, opts ...Option)
- func RequireHasMessage[T uv.Event](tb testing.TB, log MessageCollector, opts ...Option)
- func RequireHeight(tb testing.TB, view Viewable, n int, opts ...Option)
- func RequireNot[T string | []string](tb testing.TB, view Viewable, content T, opts ...Option)
- func RequireWidth(tb testing.TB, view Viewable, n int, opts ...Option)
- func WaitLiveMessage[T uv.Event](tb testing.TB, log MessageCollector, opts ...Option) T
- func WaitLiveMessageWhere(tb testing.TB, log MessageCollector, fn func(uv.Event) (ok bool), ...) uv.Event
- func WaitMessage[T uv.Event](tb testing.TB, log MessageCollector, opts ...Option) T
- func WaitMessageWhere(tb testing.TB, log MessageCollector, fn func(uv.Event) (ok bool), ...) uv.Event
- func WaitSettleMessages(tb testing.TB, log MessageCollector, opts ...Option)
- type AssertKind
- type AssertMeta
- type CaptureKind
- type CaptureMeta
- type ColorProfile
- type Harness
- func (h *Harness) Assert[T string | []string](content T, opts ...Option) *Harness
- func (h *Harness) AssertDimensions(width, height int, opts ...Option) *Harness
- func (h *Harness) AssertFor(cond reel.Condition, opts ...Option) *Harness
- func (h *Harness) AssertHasMessage[T uv.Event](opts ...Option) bool
- func (h *Harness) AssertHeight(height int, opts ...Option) *Harness
- func (h *Harness) AssertJSON(opts ...snapshot.Option) *Harness
- func (h *Harness) AssertNot[T string | []string](content T, opts ...Option) *Harness
- func (h *Harness) AssertSnapshot(opts ...snapshot.Option) *Harness
- func (h *Harness) AssertWidth(width int, opts ...Option) *Harness
- func (h *Harness) Bell() vt.Bell
- func (h *Harness) BgColor() color.Color
- func (h *Harness) Blur() *Harness
- func (h *Harness) Bounds() image.Rectangle
- func (h *Harness) ClearScrollback() *Harness
- func (h *Harness) Clipboard() vt.ClipboardWrite
- func (h *Harness) Close()
- func (h *Harness) CursorBlink() bool
- func (h *Harness) CursorColor() color.Color
- func (h *Harness) CursorPosition() image.Point
- func (h *Harness) CursorStyle() vt.CursorShape
- func (h *Harness) CursorVisible() bool
- func (h *Harness) Dimensions() (width, height int)
- func (h *Harness) ExitStatus(opts ...Option) int
- func (h *Harness) FgColor() color.Color
- func (h *Harness) FilterMessagesFunc[T uv.Event](fn func(T) bool) iter.Seq[T]
- func (h *Harness) FilterMessagesType[T uv.Event]() iter.Seq[T]
- func (h *Harness) FinalModel(opts ...Option) tea.Model
- func (h *Harness) FinalModelAs[M any](opts ...Option) M
- func (h *Harness) Focus() *Harness
- func (h *Harness) Height() int
- func (h *Harness) Image() image.Image
- func (h *Harness) ImageInto(dst *image.NRGBA)
- func (h *Harness) IsAltScreen() bool
- func (h *Harness) IsFocused() bool
- func (h *Harness) Key(key string, opts ...reel.InputOption) *Harness
- func (h *Harness) KeyBackspace(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyCtrlC(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyCtrlD(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyDelete(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyDown(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyEsc(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyLeft(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyRight(opts ...reel.InputOption) *Harness
- func (h *Harness) KeyUp(opts ...reel.InputOption) *Harness
- func (h *Harness) LeftClick(x, y int, opts ...reel.InputOption) *Harness
- func (h *Harness) LeftDrag(x1, y1, x2, y2 int, opts ...reel.InputOption) *Harness
- func (h *Harness) LiveMessages(ctx context.Context) iter.Seq[uv.Event]
- func (h *Harness) Locate(cond reel.Condition, opts ...Option) Location
- func (h *Harness) Mark(label string) *Harness
- func (h *Harness) MessageHistory() iter.Seq[uv.Event]
- func (h *Harness) Messages(ctx context.Context) iter.Seq[uv.Event]
- func (h *Harness) MiddleClick(x, y int, opts ...reel.InputOption) *Harness
- func (h *Harness) ModeSetting(mode ansi.Mode) ansi.ModeSetting
- func (h *Harness) Mouse(action vt.MouseAction, button vt.MouseButton, x, y int) *Harness
- func (h *Harness) MouseClick(button vt.MouseButton, x, y int, opts ...reel.InputOption) *Harness
- func (h *Harness) MouseDrag(button vt.MouseButton, x1, y1, x2, y2 int, opts ...reel.InputOption) *Harness
- func (h *Harness) Mutate[M any](fn func(M) M, opts ...Option) *Harness
- func (h *Harness) Notifications() []vt.Notification
- func (h *Harness) Paste(text string) *Harness
- func (h *Harness) ProgramStatuses() []vt.ProgramStatus
- func (h *Harness) Progress() vt.Progress
- func (h *Harness) Prompt() vt.Prompt
- func (h *Harness) QuitProgram() *Harness
- func (h *Harness) Require[T string | []string](content T, opts ...Option) *Harness
- func (h *Harness) RequireDimensions(width, height int, opts ...Option) *Harness
- func (h *Harness) RequireFor(cond reel.Condition, opts ...Option) *Harness
- func (h *Harness) RequireHasMessage[T uv.Event](opts ...Option) *Harness
- func (h *Harness) RequireHeight(height int, opts ...Option) *Harness
- func (h *Harness) RequireJSON(opts ...snapshot.Option) *Harness
- func (h *Harness) RequireNot[T string | []string](content T, opts ...Option) *Harness
- func (h *Harness) RequireSnapshot(opts ...snapshot.Option) *Harness
- func (h *Harness) RequireWidth(width int, opts ...Option) *Harness
- func (h *Harness) Resize(width, height int) *Harness
- func (h *Harness) ResizeRequest() (cols, rows int, ok bool)
- func (h *Harness) RightClick(x, y int, opts ...reel.InputOption) *Harness
- func (h *Harness) ScrollDown(n int) *Harness
- func (h *Harness) ScrollToBottom() *Harness
- func (h *Harness) ScrollToTop() *Harness
- func (h *Harness) ScrollUp(n int) *Harness
- func (h *Harness) Scrollback() [][]vt.Cell
- func (h *Harness) ScrollbackCount() int
- func (h *Harness) ScrollbackOffset() int
- func (h *Harness) SendProgram(msg uv.Event) *Harness
- func (h *Harness) Session() *reel.Session
- func (h *Harness) SetBgColor(c color.Color) *Harness
- func (h *Harness) SetClipboard(text string) *Harness
- func (h *Harness) SetCursorColor(c color.Color) *Harness
- func (h *Harness) SetDefaultBgColor(c color.Color) *Harness
- func (h *Harness) SetDefaultCursorColor(c color.Color) *Harness
- func (h *Harness) SetDefaultFgColor(c color.Color) *Harness
- func (h *Harness) SetFgColor(c color.Color) *Harness
- func (h *Harness) SetScrollbackSize(maxLines int) *Harness
- func (h *Harness) Sleep(d time.Duration, opts ...Option) *Harness
- func (h *Harness) Timeline() *reel.Timeline
- func (h *Harness) Title() string
- func (h *Harness) Type(s string, opts ...reel.InputOption) *Harness
- func (h *Harness) View() string
- func (h *Harness) Wait[T string | []byte | []string](contents T, opts ...Option) *Harness
- func (h *Harness) WaitFinished(opts ...Option)
- func (h *Harness) WaitFor(cond reel.Condition, opts ...Option) *Harness
- func (h *Harness) WaitLiveMessage[T uv.Event](opts ...Option) T
- func (h *Harness) WaitLiveMessageWhere[T uv.Event](fn func(T) bool, opts ...Option) T
- func (h *Harness) WaitMessage[T uv.Event](opts ...Option) T
- func (h *Harness) WaitMessageWhere[T uv.Event](fn func(T) bool, opts ...Option) T
- func (h *Harness) WaitNot[T string | []byte | []string](contents T, opts ...Option) *Harness
- func (h *Harness) WaitSettle(opts ...Option) *Harness
- func (h *Harness) WaitSettleMessages(opts ...Option) *Harness
- func (h *Harness) Width() int
- func (h *Harness) WorkingDirectory() string
- type Hook
- type HookEvent
- type HookStage
- type InputKind
- type InputMeta
- type Location
- func (l Location) LeftClick(opts ...reel.InputOption) *Harness
- func (l Location) MiddleClick(opts ...reel.InputOption) *Harness
- func (l Location) MouseClick(button vt.MouseButton, opts ...reel.InputOption) *Harness
- func (l Location) Offset(x, y int) Location
- func (l Location) RightClick(opts ...reel.InputOption) *Harness
- type MessageCollector
- type Option
- func WithANSI(enable bool) Option
- func WithArtifacts(dir string) Option
- func WithAutoMarks(enable bool, categories ...string) Option
- func WithCheck(interval time.Duration) Option
- func WithColor(p ColorProfile) Option
- func WithContext(ctx context.Context) Option
- func WithEnvVars(vars ...string) Option
- func WithExportAlways() Option
- func WithExportOnFailure() Option
- func WithHooks(hooks ...Hook) Option
- func WithIgnoreEnv(ignore bool) Option
- func WithLog(tb testing.TB) Option
- func WithProgramOptions(opts ...tea.ProgramOption) Option
- func WithRecordMessages(enable bool) Option
- func WithRecording(p reel.Profile) Option
- func WithScrollOnInput(enable bool) Option
- func WithSettle(timeout time.Duration) Option
- func WithSettleIgnoreMsgs(types ...any) Option
- func WithSlow(d time.Duration) Option
- func WithSource(enable bool) Option
- func WithStills(kinds StillKind, events ...HookEvent) Option
- func WithTimeout(timeout time.Duration) Option
- func WithWindowSize(width, height int) Option
- type Result
- type StillKind
- type Viewable
- type WaitKind
- type WaitMeta
Constants ΒΆ
const ( // DefaultTermWidth is the default terminal width (see [WithWindowSize]). DefaultTermWidth = 80 // DefaultTermHeight is the default terminal height (see [WithWindowSize]). DefaultTermHeight = 24 // DefaultTimeout is the default timeout used by [Harness] blocking waits. DefaultTimeout = 2 * time.Second // DefaultCheckInterval is the default [WithCheck] interval. DefaultCheckInterval = 10 * time.Millisecond // DefaultSettleTimeout is the default settle timeout used by [Harness] settle // waits. Settle timeouts are capped at 80% of the [WithTimeout] timeout. DefaultSettleTimeout = 100 * time.Millisecond )
const MarkFailure = "failure"
MarkFailure is the category of the marks of the failures the harness reports, "failure:1" and so on (see Harness.Mark).
Variables ΒΆ
This section is empty.
Functions ΒΆ
func Assert ΒΆ
Assert reports an error unless content appears in output. content is a string or every string in a []string. It returns whether it did.
func AssertDimensions ΒΆ
AssertDimensions reports an error unless output has specified dimensions. It returns whether the output matched.
func AssertFor ΒΆ
AssertFor reports an error unless cond holds for the output, such as reel.Matches for a regular expression. It returns whether it held. The output has no cursor, so reel.OnCursorLine never holds; use Harness.AssertFor for that.
func AssertHasMessage ΒΆ
AssertHasMessage asserts that at least one message with the same concrete type as T has been observed.
func AssertHeight ΒΆ
AssertHeight reports an error unless output has n rows. Unlike charm.land/lipgloss/v2.Height, empty output has a height of 0. It returns whether the output matched.
func AssertNot ΒΆ
AssertNot reports an error if content appears in output. content is a string or any string in a []string. It returns whether none appeared.
func AssertWidth ΒΆ
AssertWidth reports an error unless output has n columns. It returns whether the output matched.
func Dimensions ΒΆ
Dimensions returns the width and height of the output.
func FilterMessagesFunc ΒΆ
func FilterMessagesFunc[T uv.Event](tb testing.TB, messages iter.Seq[uv.Event], fn func(T) bool) iter.Seq[T]
FilterMessagesFunc filters an iterator of messages to only include messages of type T for which fn returns true.
func FilterMessagesType ΒΆ
FilterMessagesType filters an iterator of messages to only include messages with the same concrete type as T.
func IgnoreMessagesReflect ΒΆ
func IgnoreMessagesReflect(tb testing.TB, messages iter.Seq[uv.Event], ignore ...reflect.Type) iter.Seq[uv.Event]
IgnoreMessagesReflect filters an iterator of messages to exclude messages with the same concrete type as any of the provided reflect.Types.
func Logo ΒΆ
Logo returns an effect that shows steep's animated logo before the first frame of a recording, with steam rising for d while the recording's title (the test name, for a Harness) fades in. Terminals too small for the logo get a plain "steep" card instead. A d of zero or less shows nothing. Playback speed does not scale it.
Its frames are reel.Frame.Isolated and have no cells, so later effects such as effects.Keys leave them alone. They count toward GIF frame and byte limits.
func Outro ΒΆ
Outro returns an effect that shows a card for d after the last frame of a recording (see effects.OutroFunc). With lines, the card shows them. Without, it shows the *Result in reel.Context.Meta, which a Harness export sets: PASS or FAIL, the test name, and the first line of as many failures as fit. Without lines or a *Result, or with a d of zero or less, it shows nothing. Playback speed does not scale d.
For a failed test, the last frame before the card plays for at least 3s (effects.HoldLast), so the failing screen can be read. An effects.Pause badges that frame.
func Require ΒΆ
Require fails the test immediately unless content appears in output. content is a string or every string in a []string.
func RequireDimensions ΒΆ
RequireDimensions fails the test immediately unless output has specified dimensions.
func RequireFor ΒΆ
RequireFor is AssertFor, failing the test immediately unless cond holds.
func RequireHasMessage ΒΆ
RequireHasMessage requires that at least one message with the same concrete type as T has been observed.
func RequireHeight ΒΆ
RequireHeight fails the test immediately unless output has n rows.
func RequireNot ΒΆ
RequireNot fails the test immediately if content appears in output. content is a string or any string in a []string.
func RequireWidth ΒΆ
RequireWidth fails the test immediately unless output has n columns.
func WaitLiveMessage ΒΆ
WaitLiveMessage waits until a message with the same concrete type as T is received after the call, then returns it.
func WaitLiveMessageWhere ΒΆ
func WaitLiveMessageWhere(tb testing.TB, log MessageCollector, fn func(uv.Event) (ok bool), opts ...Option) uv.Event
WaitLiveMessageWhere waits until fn returns true for a message received after the call, then returns it.
func WaitMessage ΒΆ
WaitMessage waits until at least one message with the same concrete type as T has been observed, then returns the first match.
func WaitMessageWhere ΒΆ
func WaitMessageWhere(tb testing.TB, log MessageCollector, fn func(uv.Event) (ok bool), opts ...Option) uv.Event
WaitMessageWhere waits until fn returns true for any received message, past or future, then returns it.
func WaitSettleMessages ΒΆ
func WaitSettleMessages(tb testing.TB, log MessageCollector, opts ...Option)
WaitSettleMessages waits until no messages have been observed for the settle timeout (WithSettle). Types from WithSettleIgnoreMsgs do not count.
See also Harness.WaitSettle.
Types ΒΆ
type AssertKind ΒΆ
type AssertKind string
AssertKind is what an assertion asserts.
const ( // AssertKindContains asserts that text is on the screen // ([Harness.Assert] and [Harness.Require]). AssertKindContains AssertKind = "contains" // AssertKindNotContains asserts that text is not on the screen // ([Harness.AssertNot] and [Harness.RequireNot]). AssertKindNotContains AssertKind = "not_contains" // AssertKindCondition asserts a [reel.Condition] on the screen // ([Harness.AssertFor] and [Harness.RequireFor]). AssertKindCondition AssertKind = "condition" // AssertKindWidth asserts the width of the screen's text // ([Harness.AssertWidth] and [Harness.RequireWidth]). AssertKindWidth AssertKind = "width" // AssertKindHeight asserts the height of the screen's text // ([Harness.AssertHeight] and [Harness.RequireHeight]). AssertKindHeight AssertKind = "height" // AssertKindDimensions asserts the width and height of the screen's // text ([Harness.AssertDimensions] and [Harness.RequireDimensions]). AssertKindDimensions AssertKind = "dimensions" // AssertKindHasMessage asserts that the model received a message of a // type ([Harness.AssertHasMessage] and [Harness.RequireHasMessage]). AssertKindHasMessage AssertKind = "has_message" )
type AssertMeta ΒΆ
type AssertMeta struct {
Kind AssertKind `json:"assert"`
// Required is true for a Require method, whose failure stops the test.
Required bool `json:"required"`
}
AssertMeta is the metadata of HookAssert events.
func (AssertMeta) LogValue ΒΆ
func (m AssertMeta) LogValue() slog.Value
type CaptureKind ΒΆ
type CaptureKind string
CaptureKind is what a capture captures.
const ( // CaptureKindText compares the screen's text with a ".snap" file // ([Harness.AssertSnapshot] and [Harness.RequireSnapshot]). CaptureKindText CaptureKind = "text" // CaptureKindJSON compares the screen's cells and the terminal's state // with a ".json" file ([Harness.AssertJSON] and [Harness.RequireJSON]). CaptureKindJSON CaptureKind = "json" // CaptureKindImage renders the screen as an image ([Harness.Image] and // [Harness.ImageInto]). It records no annotation. CaptureKindImage CaptureKind = "image" )
type CaptureMeta ΒΆ
type CaptureMeta struct {
Kind CaptureKind `json:"format"`
// Required is true for a Require method, whose mismatch stops the test.
Required bool `json:"required"`
}
CaptureMeta is the metadata of HookCapture events.
func (CaptureMeta) LogValue ΒΆ
func (m CaptureMeta) LogValue() slog.Value
type ColorProfile ΒΆ
type ColorProfile int
ColorProfile is the color support the harness terminal advertises to the program (see WithColor).
const ( // ColorASCII advertises no color support (NO_COLOR=1). Text attributes // such as bold still render. ColorASCII ColorProfile = iota + 1 // ColorANSI advertises the 16 ANSI colors (TERM=xterm). ColorANSI // ColorANSI256 advertises 256 colors (TERM=xterm-256color). This is what // the harness terminal reports without [WithColor]. ColorANSI256 // ColorTrueColor advertises 24-bit color (TERM=xterm-256color, // COLORTERM=truecolor). ColorTrueColor )
func (ColorProfile) String ΒΆ
func (p ColorProfile) String() string
String returns the profile's name.
type Harness ΒΆ
type Harness struct {
// contains filtered or unexported fields
}
Harness is a test harness for a tea.Program.
Its checks follow one naming convention:
- Assert* report a failed check with testing.TB.Errorf and let the test continue.
- Require* stop the test with testing.TB.FailNow when the check fails.
- Wait* block until the condition holds, and stop the test with testing.TB.Fatalf if WithTimeout passes or the context is canceled first.
Most methods return the harness for chaining. Waits on the screen are built on reel.Session.Wait. The package-level Assert*, Require*, and message Wait* functions of the same names check any Viewable or MessageCollector and return a result instead: whether an Assert* passed, or the message that satisfied a Wait*.
A harness from NewExecHarness runs a command rather than a tea.Program: methods that need the program or its model fail the test.
func NewComponentHarness ΒΆ
NewComponentHarness is NewHarness for a component model, which must have a View() string method and an Update method returning either a tea.Cmd or the updated model and a tea.Cmd. Init is optional.
func NewExecHarness ΒΆ
NewExecHarness starts cmd on a pseudo-terminal (see reel.Exec) and returns a harness to drive and assert on it, for programs that cannot run in the test's process, such as a built binary or one that does not use Bubble Tea. It registers Harness.Close as a test cleanup, which kills cmd if it is still running. It fails the test if cmd cannot be started.
Unlike NewHarness, it does not wait for cmd to do anything, as a command has no first message to wait for. Wait for what it draws, such as with Harness.Wait.
The environment is cmd.Env, or the host's when nil, changed by WithEnvVars and WithColor. WithProgramOptions, WithRecordMessages, and WithSettleIgnoreMsgs have no effect. Methods that need the program or its model fail the test: Harness.SendProgram, Harness.QuitProgram, Harness.Mutate, Harness.FinalModel, and those that read messages, such as Harness.WaitMessage.
func NewHarness ΒΆ
NewHarness runs the root tea.Model in a tea.Program and returns a harness to drive and assert on it. It waits up to the WithTimeout timeout for the model's first message, and registers Harness.Close as a test cleanup.
func (*Harness) Assert ΒΆ
Assert reports an error unless content appears in view output. content is a string or every string in a []string.
func (*Harness) AssertDimensions ΒΆ
AssertDimensions reports an error unless view output has width columns and height rows.
See also Harness.Dimensions.
func (*Harness) AssertFor ΒΆ
AssertFor reports an error unless cond holds for the screen, such as reel.Matches for a regular expression or reel.OnCursorLine for a condition on the cursor's line.
func (*Harness) AssertHasMessage ΒΆ
AssertHasMessage reports an error unless history contains a message of type T.
func (*Harness) AssertHeight ΒΆ
AssertHeight reports an error unless view output has height rows. It allows the test to continue.
func (*Harness) AssertJSON ΒΆ
AssertJSON compares the screen's cells and the terminal's state, as JSON, against a snapshot file.
func (*Harness) AssertNot ΒΆ
AssertNot reports an error if content appears in view output. content is a string or any string in a []string.
func (*Harness) AssertSnapshot ΒΆ
AssertSnapshot compares Harness.View against a snapshot file. It allows the test to continue.
func (*Harness) AssertWidth ΒΆ
AssertWidth reports an error unless view output has width columns. It allows the test to continue.
func (*Harness) Bell ΒΆ
Bell returns the latest bell (ansi.BEL). Its Count is zero before the first.
func (*Harness) ClearScrollback ΒΆ
ClearScrollback clears the terminal's scrollback (see reel.Session.ClearScrollback).
func (*Harness) Clipboard ΒΆ
func (h *Harness) Clipboard() vt.ClipboardWrite
Clipboard returns the program's latest clipboard write.
func (*Harness) Close ΒΆ
func (h *Harness) Close()
Close stops the program, exports the recording if the export policy says to, and releases the terminal. NewHarness registers it as a test cleanup, so calling it is optional. Calls after the first do nothing.
func (*Harness) CursorBlink ΒΆ
CursorBlink reports whether the cursor style is blinking.
func (*Harness) CursorColor ΒΆ
CursorColor returns the terminal emulator's cursor color.
func (*Harness) CursorPosition ΒΆ
CursorPosition returns the terminal emulator cursor position, or (-1, -1) while the viewport is scrolled off it (see Harness.ScrollUp).
func (*Harness) CursorStyle ΒΆ
func (h *Harness) CursorStyle() vt.CursorShape
CursorStyle returns the current VT cursor shape.
func (*Harness) CursorVisible ΒΆ
CursorVisible reports whether the cursor is shown (DECTCEM).
func (*Harness) Dimensions ΒΆ
Dimensions returns the terminal's width and height in cells.
func (*Harness) ExitStatus ΒΆ
ExitStatus waits for the command of NewExecHarness to finish, as Harness.WaitFinished does, and returns its exit status. On Unix, a command killed by a signal has status 128+signal, as shells report it.
func (*Harness) FilterMessagesFunc ΒΆ
FilterMessagesFunc yields history messages of type T for which fn returns true.
func (*Harness) FilterMessagesType ΒΆ
FilterMessagesType yields history messages whose concrete type is T.
func (*Harness) FinalModel ΒΆ
FinalModel waits for the tea.Program to finish and returns the root model.
func (*Harness) FinalModelAs ΒΆ
FinalModelAs is Harness.FinalModel, with the model as M. It fails the test when the model is not M.
func (*Harness) Image ΒΆ
Image renders the screen as an image, with the Render options of the recording profile (see WithRecording and reel.Imager.Image).
The image is reused by the next call, so do not mutate or retain it; copy it, or use Harness.ImageInto.
func (*Harness) ImageInto ΒΆ
ImageInto renders the screen into dst, at dst.Rect.Min (see reel.Imager.ImageInto). dst must be at least as large as the image Harness.Image returns. Unlike that image, dst is the caller's, safe to keep after the call.
func (*Harness) IsAltScreen ΒΆ
IsAltScreen returns true if the terminal is in alt screen mode.
func (*Harness) Key ΒΆ
func (h *Harness) Key(key string, opts ...reel.InputOption) *Harness
Key sends a single key press to the terminal, such as "ctrl+a", "enter", "shift+tab", or "space" (see reel.Session.Key). An unknown name fails the test. Like Harness.Type, it can be reordered against Harness.SendProgram. Pass reel.Delay to pause after the key press, or reel.Repeat to press it more than once.
func (*Harness) KeyBackspace ΒΆ
func (h *Harness) KeyBackspace(opts ...reel.InputOption) *Harness
KeyBackspace sends a backspace key press to the terminal emulator.
func (*Harness) KeyCtrlC ΒΆ
func (h *Harness) KeyCtrlC(opts ...reel.InputOption) *Harness
KeyCtrlC sends ctrl+c to the terminal emulator.
func (*Harness) KeyCtrlD ΒΆ
func (h *Harness) KeyCtrlD(opts ...reel.InputOption) *Harness
KeyCtrlD sends ctrl+d to the terminal emulator.
func (*Harness) KeyDelete ΒΆ
func (h *Harness) KeyDelete(opts ...reel.InputOption) *Harness
KeyDelete sends a delete (forward-delete) key press to the terminal emulator.
func (*Harness) KeyDown ΒΆ
func (h *Harness) KeyDown(opts ...reel.InputOption) *Harness
KeyDown sends a down-arrow key press to the terminal emulator.
func (*Harness) KeyEsc ΒΆ
func (h *Harness) KeyEsc(opts ...reel.InputOption) *Harness
KeyEsc sends an escape key press to the terminal emulator.
func (*Harness) KeyLeft ΒΆ
func (h *Harness) KeyLeft(opts ...reel.InputOption) *Harness
KeyLeft sends a left-arrow key press to the terminal emulator.
func (*Harness) KeyRight ΒΆ
func (h *Harness) KeyRight(opts ...reel.InputOption) *Harness
KeyRight sends a right-arrow key press to the terminal emulator.
func (*Harness) KeyUp ΒΆ
func (h *Harness) KeyUp(opts ...reel.InputOption) *Harness
KeyUp sends an up-arrow key press to the terminal emulator.
func (*Harness) LeftClick ΒΆ
func (h *Harness) LeftClick(x, y int, opts ...reel.InputOption) *Harness
LeftClick is Harness.MouseClick with the left mouse button.
func (*Harness) LeftDrag ΒΆ
func (h *Harness) LeftDrag(x1, y1, x2, y2 int, opts ...reel.InputOption) *Harness
LeftDrag is Harness.MouseDrag with the left mouse button.
func (*Harness) LiveMessages ΒΆ
LiveMessages returns an iterator over messages the model receives after the call returns, until ctx is done. Like Harness.Messages, it buffers only 32 messages, and a loop that falls further behind misses the newer ones.
func (*Harness) Locate ΒΆ
Locate waits until cond holds for the screen, as Harness.WaitFor does, and returns the cell where cond's first match starts, so a test can click what the program drew without knowing where it drew it:
h.Locate(reel.Contains("[ Save ]")).LeftClick()
h.Locate(reel.Contains("Name:")).Offset(6, 0).LeftClick()
The location is not updated if the program redraws afterward. A condition that holds without locating anything, such as reel.NotContains or reel.ScreenFunc, fails the test.
func (*Harness) Mark ΒΆ
Mark places a reel.Mark labeled label in the session's timeline, which reel.Timeline.Between can cut a recording at. The label must not be empty. Use the "category:value" form, such as "login:done" or "step:3", so marks can be grouped by the text before the first ":" (see reel.SplitLabel). The categories of the harness's own marks, the hook events' names and MarkFailure, are reserved: a label in one of them is a test error, and is not placed.
The harness marks every hook event once its action is done, before its After hooks run, labeled with the event's name and count, such as "input:1" or "wait:1". While exporting, input, terminal, and program actions are marked once the program has painted its response: when its output has been quiet for the WithCheck interval, or, if it writes nothing, after the WithSettle period (at least 50ms). For input and program actions, only output after the model has handled the action counts, so a still of one shows the response even when other output came first. Input the program does not hear of, such as a click without mouse tracking, takes that period too. A response made later, such as by a command, need not be painted yet. Any output counts for terminal actions, which the program may not hear of. A very large check interval slows those actions. Harness.Close places its mark as it starts, where the recording ends.
The harness also marks each failure it reports as it reports it, "failure:1", "failure:2", and so on, numbered as in Result.Failures, such as for effects.PauseAtMarks to pause on a test's first failure. WithAutoMarks turns the harness's marks off.
func (*Harness) MessageHistory ΒΆ
MessageHistory returns a copy of all messages the model received.
func (*Harness) Messages ΒΆ
Messages returns an iterator over all messages the model received, past and future, until ctx is done. Past messages are complete, but the iterator buffers only 32 new ones: a loop that falls further behind misses the newer messages, which Harness.MessageHistory still has.
func (*Harness) MiddleClick ΒΆ
func (h *Harness) MiddleClick(x, y int, opts ...reel.InputOption) *Harness
MiddleClick is Harness.MouseClick with the middle mouse button.
func (*Harness) ModeSetting ΒΆ
func (h *Harness) ModeSetting(mode ansi.Mode) ansi.ModeSetting
ModeSetting returns the setting of mode, or ansi.ModeNotRecognized for a mode the terminal does not track.
func (*Harness) Mouse ΒΆ
func (h *Harness) Mouse(action vt.MouseAction, button vt.MouseButton, x, y int) *Harness
Mouse sends a mouse event through the terminal. As with a real terminal, it is dropped unless the program enabled mouse tracking.
func (*Harness) MouseClick ΒΆ
func (h *Harness) MouseClick(button vt.MouseButton, x, y int, opts ...reel.InputOption) *Harness
MouseClick sends a press and release at (x, y) (see reel.Session.Click). Pass reel.Repeat for a double click. To click what is on the screen instead of a fixed cell, see Harness.Locate.
func (*Harness) MouseDrag ΒΆ
func (h *Harness) MouseDrag(button vt.MouseButton, x1, y1, x2, y2 int, opts ...reel.InputOption) *Harness
MouseDrag sends a press at (x1, y1), motion through each cell of the straight line to (x2, y2), and a release there (see reel.Session.Drag). Pass reel.Delay to pause after each step.
func (*Harness) Mutate ΒΆ
Mutate applies fn to the model on the program's goroutine, as part of its Update handling. Use it sparingly, for scenarios that are otherwise impossible to set up or would pollute the model with test-only state.
fn must take and return the model type passed to NewHarness or NewComponentHarness, such as func(Model) Model or func(*Model) *Model, or the test fails.
func (*Harness) Notifications ΒΆ
func (h *Harness) Notifications() []vt.Notification
Notifications returns desktop notifications from OSC 9 and OSC 777.
func (*Harness) Paste ΒΆ
Paste pastes text into the terminal, bracketed if the program enabled bracketed paste.
func (*Harness) ProgramStatuses ΒΆ
func (h *Harness) ProgramStatuses() []vt.ProgramStatus
ProgramStatuses returns the current OSC 7501 records (see vt.Terminal.ProgramStatuses). At most 256 are kept.
func (*Harness) QuitProgram ΒΆ
QuitProgram requests a graceful shutdown of the tea.Program.
func (*Harness) Require ΒΆ
Require fails the test immediately unless content appears in view output. content is a string or every string in a []string.
func (*Harness) RequireDimensions ΒΆ
RequireDimensions fails the test immediately unless view output has width columns and height rows.
func (*Harness) RequireFor ΒΆ
RequireFor is Harness.AssertFor, failing the test immediately unless cond holds.
func (*Harness) RequireHasMessage ΒΆ
RequireHasMessage fails the test immediately unless history contains a message of type T.
func (*Harness) RequireHeight ΒΆ
RequireHeight fails the test immediately unless view output has height rows.
func (*Harness) RequireJSON ΒΆ
RequireJSON is Harness.AssertJSON, but fails the test immediately if the snapshot does not match.
func (*Harness) RequireNot ΒΆ
RequireNot fails the test immediately if content appears in view output. content is a string or any string in a []string.
func (*Harness) RequireSnapshot ΒΆ
RequireSnapshot compares Harness.View against a snapshot file. It fails the test immediately if the snapshot does not match.
func (*Harness) RequireWidth ΒΆ
RequireWidth fails the test immediately unless view output has width columns.
func (*Harness) Resize ΒΆ
Resize resizes the terminal, which sends the program a tea.WindowSizeMsg, or a command a SIGWINCH.
func (*Harness) ResizeRequest ΒΆ
ResizeRequest returns the last CSI 8 t window-resize request, with ok false until the program asks. The terminal is not resized.
func (*Harness) RightClick ΒΆ
func (h *Harness) RightClick(x, y int, opts ...reel.InputOption) *Harness
RightClick is Harness.MouseClick with the right mouse button.
func (*Harness) ScrollDown ΒΆ
ScrollDown scrolls the terminal's viewport n rows toward the live screen. See Harness.ScrollUp.
func (*Harness) ScrollToBottom ΒΆ
ScrollToBottom scrolls the terminal's viewport back to the live screen. See Harness.ScrollUp.
func (*Harness) ScrollToTop ΒΆ
ScrollToTop scrolls the terminal's viewport to the oldest scrollback row. See Harness.ScrollUp.
func (*Harness) ScrollUp ΒΆ
ScrollUp scrolls the terminal's viewport n rows toward older scrollback, so Harness.View, snapshots, and a window-chrome scrollbar show the older rows. The program is not told. The viewport stays put as the program writes more, until Harness.ScrollDown or Harness.ScrollToBottom, or input from Harness.Type, Harness.Key, or Harness.Paste (see WithScrollOnInput).
func (*Harness) Scrollback ΒΆ
Scrollback returns a copy of the terminal's scrollback rows (oldest first). It is nil in alternate screen mode.
func (*Harness) ScrollbackCount ΒΆ
ScrollbackCount returns the count of scrollback lines.
func (*Harness) ScrollbackOffset ΒΆ
ScrollbackOffset returns how many rows the terminal's viewport is scrolled up from the bottom, so zero while it shows the live screen.
func (*Harness) SendProgram ΒΆ
SendProgram sends msg to the tea.Program.
Prefer driving input with Harness.Type, Harness.Key, Harness.Paste, or the mouse helpers, which go through the terminal as real input would.
func (*Harness) Session ΒΆ
Session returns the reel.Session the program runs in.
func (*Harness) SetBgColor ΒΆ
SetBgColor sets the terminal emulator background color.
func (*Harness) SetClipboard ΒΆ
SetClipboard sets the host clipboard returned for OSC 52 reads.
func (*Harness) SetCursorColor ΒΆ
SetCursorColor sets the terminal emulator cursor color.
func (*Harness) SetDefaultBgColor ΒΆ
SetDefaultBgColor sets the background color used when the program sets none.
func (*Harness) SetDefaultCursorColor ΒΆ
SetDefaultCursorColor sets the cursor color used when the program sets none.
func (*Harness) SetDefaultFgColor ΒΆ
SetDefaultFgColor sets the foreground color used when the program sets none.
func (*Harness) SetFgColor ΒΆ
SetFgColor sets the terminal emulator foreground color.
func (*Harness) SetScrollbackSize ΒΆ
SetScrollbackSize sets the most scrollback lines the terminal keeps (see reel.Session.SetScrollbackSize).
func (*Harness) Sleep ΒΆ
Sleep lets the program run for d, such as to hold on a screen in a recording or let an animation run. It fails the test if the context is canceled first.
Prefer waiting for the expected screen, such as with Harness.Wait, which does not depend on how fast the program runs.
func (*Harness) Timeline ΒΆ
Timeline returns the session's reel.Timeline, which grows while the program runs.
func (*Harness) Type ΒΆ
func (h *Harness) Type(s string, opts ...reel.InputOption) *Harness
Type sends s to the terminal as key presses (see reel.Session.Type). Use Harness.Key for modifier combinations such as ctrl+a.
Input goes through the terminal, so mixing it with Harness.SendProgram can deliver events to the program in a different order than the calls. Pass reel.Delay to pause after each key press of this call.
func (*Harness) View ΒΆ
View returns the screen's text, which the harness's waits, assertions, and snapshots compare. Empty cells are spaces, so every line is Harness.Width wide and there are Harness.Height lines.
func (*Harness) Wait ΒΆ
Wait waits until view output contains contents. contents is a string, a []byte sequence, or every string in a []string.
func (*Harness) WaitFinished ΒΆ
WaitFinished waits for the program to finish. It fails the test if the program failed: it returned an error other than tea.ErrProgramKilled, or it panicked, which Bubble Tea reports as killed. A command's nonzero exit status is not an error (see Harness.ExitStatus).
See also Harness.FinalModel.
func (*Harness) WaitFor ΒΆ
WaitFor waits until cond holds for the screen (see reel.Session.Wait), such as reel.Matches for a regular expression, reel.ScreenFunc for a condition of the test's own on the screen's text, or reel.OnCursorLine for one on the cursor's line. cond is checked whenever the screen changes.
func (*Harness) WaitLiveMessage ΒΆ
WaitLiveMessage waits until a new message with concrete type T arrives after this call, then returns the first match.
func (*Harness) WaitLiveMessageWhere ΒΆ
WaitLiveMessageWhere waits until fn returns true for a message of type T received after this call. T is inferred from fn. fn should be quick, as for Harness.WaitMessageWhere.
func (*Harness) WaitMessage ΒΆ
WaitMessage waits until at least one message with concrete type T has been observed, then returns the first match.
func (*Harness) WaitMessageWhere ΒΆ
WaitMessageWhere waits until fn returns true for a message of type T across history and later messages. T is inferred from fn. fn should be quick: a wait that falls 32 messages behind misses the newer ones (see Harness.Messages).
func (*Harness) WaitNot ΒΆ
WaitNot waits until view output contains none of contents. contents is a string, a []byte sequence, or any string in a []string.
func (*Harness) WaitSettle ΒΆ
WaitSettle waits until Harness.View has not changed for the settle timeout (WithSettle) (see reel.Session.WaitSettle).
See also Harness.WaitSettleMessages.
func (*Harness) WaitSettleMessages ΒΆ
WaitSettleMessages waits until the model has received no messages for the settle timeout (WithSettle), ignoring types from WithSettleIgnoreMsgs.
See also Harness.WaitSettle.
func (*Harness) WorkingDirectory ΒΆ
WorkingDirectory returns the last OSC 7 working directory.
type Hook ΒΆ
Hook observes harness actions (see WithHooks). Errors fail the test immediately.
metadata is nil, or the action's InputMeta, WaitMeta, AssertMeta, or CaptureMeta, which marshal to JSON as the matching fields of the annotation the harness records for the action.
func LoggerHook ΒΆ
LoggerHook returns a hook that logs events to logger, or with testing.TB.Log when logger is nil.
type HookEvent ΒΆ
type HookEvent int
HookEvent identifies a harness action for hooks and mark labels (see Harness.Mark).
const ( // HookInput is a keyboard, paste, or mouse action, with [InputMeta]. HookInput HookEvent = iota // HookTerminal is a change to the terminal, such as a resize. HookTerminal // HookProgram is an action on the program, such as a message sent to it. HookProgram // HookWait is a wait, or a sleep, with [WaitMeta]. HookWait // HookReady is the program's start. HookReady // HookClose is the program's end, and the harness's. The wait of // [Harness.WaitFinished] has [WaitMeta]. HookClose // HookAssert is an assertion, with [AssertMeta]. HookAssert // HookCapture is a snapshot comparison or image capture, with // [CaptureMeta]. HookCapture )
type HookStage ΒΆ
type HookStage int
HookStage is whether a hook runs before or after the harness action.
type InputKind ΒΆ
type InputKind string
InputKind is the kind of an input action.
const ( // InputKindType is text typed as key presses ([Harness.Type]). InputKindType InputKind = "type" // InputKindKey is a key press ([Harness.Key]). InputKindKey InputKind = "key" // InputKindPaste is a paste ([Harness.Paste]). InputKindPaste InputKind = "paste" // InputKindMouse is a single mouse event ([Harness.Mouse]). InputKindMouse InputKind = "mouse" // InputKindClick is a press and release of a mouse button // ([Harness.MouseClick]). InputKindClick InputKind = "click" // InputKindDrag is a press of a mouse button, motion, and its release // ([Harness.MouseDrag]). InputKindDrag InputKind = "drag" )
type InputMeta ΒΆ
type InputMeta struct {
Kind InputKind `json:"action"`
// Text is the text of [InputKindType] and [InputKindPaste].
Text string `json:"text,omitzero"`
// Key is the key of [InputKindKey], such as "enter" or "ctrl+c".
Key string `json:"key,omitzero"`
// Mouse is the mouse event of [InputKindMouse]: "press", "release", or
// "motion".
Mouse string `json:"mouse,omitzero"`
// Button is the mouse button of [InputKindMouse], [InputKindClick], and
// [InputKindDrag]: "left", "right", "middle", or "none" for motion
// without one.
Button string `json:"button,omitzero"`
}
InputMeta is the metadata of HookInput events.
type Location ΒΆ
type Location struct {
// X and Y are the cell's column and row, from 0.
X, Y int
// contains filtered or unexported fields
}
Location is a cell of the screen, returned by Harness.Locate.
func (Location) LeftClick ΒΆ
func (l Location) LeftClick(opts ...reel.InputOption) *Harness
LeftClick is Location.MouseClick with the left mouse button.
func (Location) MiddleClick ΒΆ
func (l Location) MiddleClick(opts ...reel.InputOption) *Harness
MiddleClick is Location.MouseClick with the middle mouse button.
func (Location) MouseClick ΒΆ
func (l Location) MouseClick(button vt.MouseButton, opts ...reel.InputOption) *Harness
MouseClick is Harness.MouseClick at l. It fails the test if l is off the screen, where the program would only see a release at the screen's edge.
func (Location) Offset ΒΆ
Offset returns the location x columns to the right and y rows below l. Negative values go left and up.
func (Location) RightClick ΒΆ
func (l Location) RightClick(opts ...reel.InputOption) *Harness
RightClick is Location.MouseClick with the right mouse button.
type MessageCollector ΒΆ
type MessageCollector interface {
MessageHistory() iter.Seq[uv.Event]
Messages(ctx context.Context) iter.Seq[uv.Event]
LiveMessages(ctx context.Context) iter.Seq[uv.Event]
}
MessageCollector exposes messages observed by a test harness. Harness implements this interface.
type Option ΒΆ
type Option func(*options)
Option configures a Harness or assertion helper. Options given to NewHarness are defaults for every Harness method that accepts options, and per-call options override them.
func WithANSI ΒΆ
WithANSI determines whether ANSI sequences are kept (the default) in the output that assertions and Harness.AssertSnapshot compare. It does not change JSON snapshots, images, or recordings, or the screen text waits check, which has none.
func WithArtifacts ΒΆ
WithArtifacts sets the directory relative output paths are written under, created when needed. A relative dir is relative to the test's package directory. Without it, files go to testing.TB.ArtifactDir, which is only kept with "go test -artifacts"; without that flag, an export logs that its files are removed. Absolute output paths ignore dir.
Environment: STEEP_EXPORT_DIR (overrides this option unless WithIgnoreEnv is set).
func WithAutoMarks ΒΆ
WithAutoMarks turns the marks the harness places itself (see Harness.Mark) on or off: those of categories, or all of them without categories. The categories are the hook events' names, such as HookInput.String() for "input:1", and MarkFailure. Calls apply in order, so WithAutoMarks(false) then WithAutoMarks(true, MarkFailure) keeps only the marks of failures. All are on by default. It only applies to NewHarness; an unknown category stops the test.
The rest of the recording is unchanged: annotations such as "steep.input" are still recorded, and the recording still ends where Harness.Close starts. A category that an export output's Marks or MarkMatch matches up to the first ":", such as "wait" for "wait:*", "*" for every category, or the events of WithStills, is marked anyway, so its stills are written (a pattern such as "*1" that only matches across the ":" is not). Anything else that looks for a mark that is off, such as effects.PauseAtMarks on "failure:1", finds none; WithRecording says how an export reports that.
func WithCheck ΒΆ
WithCheck configures how often Harness.WaitSettleMessages re-checks for messages. Waits on the screen do not poll: they check it whenever it changes. Defaults to DefaultCheckInterval. While exporting, it is also how long the program's output must stay quiet before an action is marked (see Harness.Mark).
Environment: STEEP_CHECK (overrides this option unless WithIgnoreEnv is set).
func WithColor ΒΆ
func WithColor(p ColorProfile) Option
WithColor sets the color support the harness terminal advertises to the program, through TERM, COLORTERM, and NO_COLOR and tea.WithColorProfile. Without it the terminal reports ColorANSI256, so Bubble Tea downsamples 24-bit colors; use ColorTrueColor for gradients and blends.
It overrides the color variables of WithEnvVars, whatever the order. A tea.WithColorProfile passed through WithProgramOptions wins over it.
For NewExecHarness, it also overrides those of cmd's environment, and without it the command's color support is as reel.Exec sets it.
func WithContext ΒΆ
WithContext sets the parent context for blocking waits and the running program. A Harness defaults to the test's context, canceled on interrupt; other helpers default to context.Background.
func WithEnvVars ΒΆ
WithEnvVars sets environment variables for the tea.Program, in the form of "key=value". Without this option the program sees only the defaults:
- TTY_FORCE=1
- TERM=xterm-256color (see WithColor)
This option replaces those defaults with the test process environment plus vars, so pass TTY_FORCE and TERM again if the program needs them. It panics if an entry is not in "key=value" form.
The program sees the whole test process environment, which in CI may hold tokens and credentials. WithRecordMessages does not record it, but the program can still read and draw it.
For NewExecHarness, vars and the test process environment replace those of the same name in cmd's environment.
func WithExportAlways ΒΆ
func WithExportAlways() Option
WithExportAlways exports the recording (see WithRecording) at Harness.Close, whether the test passed or failed, except for a skipped test. See WithExportOnFailure for caveats and the environment override.
func WithExportOnFailure ΒΆ
func WithExportOnFailure() Option
WithExportOnFailure exports the recording (see WithRecording) at Harness.Close if the test has failed by then. Without an export policy, nothing is written.
Tests that panic or call testing.TB.FailNow still export. A test killed by "go test -timeout", or a panic on another goroutine, writes nothing.
Environment: STEEP_EXPORT_MODE (see the package documentation).
func WithIgnoreEnv ΒΆ
WithIgnoreEnv disables STEEP_* environment overrides. By default they are applied after every other option, so they override options set in code.
func WithLog ΒΆ
WithLog logs every hooked action to tb, as WithHooks with a LoggerHook of a nil logger.
Environment: STEEP_LOG (on, true, or 1) adds the same hook unless WithIgnoreEnv is set.
func WithProgramOptions ΒΆ
func WithProgramOptions(opts ...tea.ProgramOption) Option
WithProgramOptions appends tea.ProgramOption values for NewHarness and NewComponentHarness, and has no effect on NewExecHarness. Environment, context, input, output, tea.WithoutSignals, and tea.WithWindowSize are always set by the harness and cannot be replaced here.
func WithRecordMessages ΒΆ
WithRecordMessages records each message the model receives as a "steep.message" annotation of its type and %+v value. It is off by default, since programs that tick or animate receive many messages, each of which grows the timeline and ".cast" file.
The tea.EnvMsg Bubble Tea sends the model is never recorded, since it holds the program's whole environment (see WithEnvVars). Other messages are recorded as they are, including any secret they hold, as is the text the program draws, which the effects package's Redact hides.
Environment: STEEP_RECORD_MESSAGES (on or off) overrides this option unless WithIgnoreEnv is set.
func WithRecording ΒΆ
WithRecording sets what an export writes as a reel.Profile. It does not export by itself (see WithExportAlways and WithExportOnFailure). Calls merge with reel.Profile.Merge. The profile's Render options also draw Harness.Image and Harness.ImageInto.
Besides reel's path variables and the profile's Vars, output paths may use {name}, the test's name with everything but letters and digits replaced by "_", and {status}, "passed" or "failed". Vars of the same names override them. Relative paths are under WithArtifacts. Nil Outputs write "{name}_{status}.gif" and "{name}_{status}.cast".
At export, reel.Context.Meta is the test's *Result. A mark the profile looks for that the test never placed does not stop the export (see reel.Export): for a failed test it is logged, and for a passing test it is a test error, except for "failure:n" marks, so a profile can pause on "failure:1" whatever the result. The recording ends where Harness.Close starts, so the program's repaint as it exits is left out, even when the close mark is off (see WithAutoMarks).
The STEEP_EXPORT* and STEEP_RENDERER_* variables patch the profile (see the package documentation).
func WithScrollOnInput ΒΆ
WithScrollOnInput determines whether Harness.Type, Harness.Key (and the helpers built on it), and Harness.Paste first scroll a viewport scrolled with Harness.ScrollUp and friends back to the bottom, as a real terminal does on a key press. Enabled by default. Mouse events and Harness.SendProgram never scroll.
func WithSettle ΒΆ
WithSettle configures the quiet period settle waits require. Defaults to DefaultSettleTimeout, and is capped at 80% of WithTimeout. While exporting, it also paces action marks (see Harness.Mark).
Environment: STEEP_SETTLE (overrides this option unless WithIgnoreEnv is set).
func WithSettleIgnoreMsgs ΒΆ
WithSettleIgnoreMsgs marks message types that do not reset the quiet period used by Harness.WaitSettleMessages. Pass a value of each type to ignore, such as a zero value of a periodic tick type; types must match exactly. Calls accumulate.
func WithSlow ΒΆ
WithSlow makes the harness sleep for d after every hooked action, before its After hooks run, giving the program real time between actions for animations, ticks, and timers. Recordings do not need it: they play back the timeline as it happened, at reel.Profile.Speed.
Environment: STEEP_SLOW (overrides this option unless WithIgnoreEnv is set).
func WithSource ΒΆ
WithSource records where in the test each annotation and mark of the recording came from (see reel.WithSource): a "source" member of each annotation, and a "reel.mark" annotation after each mark, of the file, line, and function of the test's line that led to it, past any of the test's helpers. "steep.start" also gets the test's package, its module, and its directory in the module, and file paths are relative to the module's root, so they hold no home or build directories. Annotations and marks no line of the test led to, such as messages the model receives, or those Harness.Close places as a test cleanup, get none. Off by default; while off, no stack is walked.
Environment: STEEP_SOURCE (on or off) overrides this option unless WithIgnoreEnv is set.
func WithStills ΒΆ
WithStills writes stills of kinds at the marks of events (see Harness.Mark), one file per mark: "{name}_{status}_{mark}.png" for StillPNG and "{name}_{status}_{mark}.snap" for StillSnapshot, such as "TestLogin_failed_input-2.png" for the mark "input:2" (the ":" is not allowed in Windows file names; see reel.File.Marks). Without events, it uses input, terminal, program, wait, ready, and close. Calls accumulate.
Each is a reel.File whose reel.File.MarkMatch matches the events' marks, such as "input:[0-9]*", so the harness marks those events even if WithAutoMarks turns their marks off. Stills are only written when the recording is exported. For a single PNG of the last frame, add a ".png" output to the profile instead.
func WithTimeout ΒΆ
WithTimeout configures the maximum time blocking waits (startup, waits, settle, mutation) may run before failing the test. Defaults to DefaultTimeout.
Environment: STEEP_TIMEOUT (overrides this option unless WithIgnoreEnv is set).
func WithWindowSize ΒΆ
WithWindowSize configures the starting terminal size.
See also DefaultTermWidth and DefaultTermHeight.
type Result ΒΆ
type Result struct {
// Name is the test's name, [testing.TB.Name].
Name string
// Failed is whether the test had failed, or was panicking, by the time
// [Harness.Close] ran.
Failed bool
// Failures are the failure messages the harness reported, oldest first,
// followed by "test panicked" for a test that panicked. The harness marks
// each but "test panicked" as "failure:n" (see [Harness.Mark]). Failures
// the test reports through its own [testing.TB] are not included.
Failures []string
// Duration is how long the harness ran, from [NewHarness] to
// [Harness.Close].
Duration time.Duration
}
Result is a test's result, which an export passes to effects as reel.Context.Meta, such as for Outro.
type StillKind ΒΆ
type StillKind uint8
StillKind is a kind of still WithStills writes at a hook event's mark. Kinds combine with |.
const ( // StillPNG is a PNG of the terminal at the mark, drawn with the profile's // Render options and only its [reel.StillEffect] effects. StillPNG StillKind = 1 << iota // StillSnapshot is a ".snap" file of the screen's text at the mark, as // [Harness.View] showed it, from the recording's replay. StillSnapshot )
type Viewable ΒΆ
type Viewable func() string
Viewable returns the output the package-level assertions check, such as Harness.View.
type WaitKind ΒΆ
type WaitKind string
WaitKind is what a wait waits for.
const ( // WaitKindText waits for text to be on the screen ([Harness.Wait]). WaitKindText WaitKind = "text" // WaitKindNotText waits for text not to be on the screen // ([Harness.WaitNot]). WaitKindNotText WaitKind = "not_text" // WaitKindCondition waits for a [reel.Condition] on the screen // ([Harness.WaitFor]). WaitKindCondition WaitKind = "condition" // WaitKindSettle waits for the screen to stay unchanged // ([Harness.WaitSettle]). WaitKindSettle WaitKind = "settle" // WaitKindSettleMessages waits for the model to receive no messages // ([Harness.WaitSettleMessages]). WaitKindSettleMessages WaitKind = "settle_messages" // WaitKindMessage waits for the model to receive a message of a type // ([Harness.WaitMessage] and the like). WaitKindMessage WaitKind = "message" // WaitKindFinished waits for the program to end // ([Harness.WaitFinished]). WaitKindFinished WaitKind = "finished" // WaitKindSleep waits for time to pass ([Harness.Sleep]). WaitKindSleep WaitKind = "sleep" )
type WaitMeta ΒΆ
type WaitMeta struct {
Kind WaitKind `json:"wait"`
// Live is true for a [WaitKindMessage] wait that only counts messages
// received after it starts, such as [Harness.WaitLiveMessage].
Live bool `json:"live,omitzero"`
}
WaitMeta is the metadata of HookWait events, and of the HookClose event of Harness.WaitFinished.
Source Files
ΒΆ
Directories
ΒΆ
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
reel
module
|
|
|
internal
|
|
|
broker
Package broker provides a generic in-memory event broker.
|
Package broker provides a generic in-memory event broker. |
|
typeobserver
Package typeobserver counts the types of values it observes, and when each was first and last seen, for failure messages.
|
Package typeobserver counts the types of values it observes, and when each was first and last seen, for failure messages. |
|
xansi
Package xansi normalizes terminal output for stable snapshots and assertions: stripping ANSI, spinner glyphs, and private-use code points, normalizing newlines, and escaping ESC for readable diffs.
|
Package xansi normalizes terminal output for stable snapshots and assertions: stripping ANSI, spinner glyphs, and private-use code points, normalizing newlines, and escaping ESC for readable diffs. |
|
reel
module
|
|
|
Package snapshot provides snapshot assertions for tests.
|
Package snapshot provides snapshot assertions for tests. |