The progress of a command is part of what it does. A test can check it as it checks the result: which spans started, how each ended, and that the events keep every promise of the vocabulary.
Procedure#
- Call
progresstest.Watchwith the context of the test. It returns a context with a Bus, and aprogresstest.Watcher. - Run the code under test with that context.
- Compare the tree of the Watcher with the tree you expect. Targets that read the same fold into one line, so the tree is the same however the work was scheduled.
- Call
Finish. It checks every rule of the events. A test that does not call it is checked when it ends.
_ = func(t *testing.T) {
ctx, w := progresstest.Watch(t.Context(), t)
_ = reset(ctx, []string{"exe1", "exe2", "exe3"})
want := `step reset the machines total=3 [fold]: failed (target): exe3: no answer
target exe3: failed (target): {}: no answer
target exe[1-2]: ok
`
if got := w.Finish(); got != want {
t.Errorf("the work reported\n%s\nwant\n%s", got, want)
}
}progress/progresstest/example_test.go. CI compiles it.The rules that progresstest.Check enforces are an
interface (decision 15). A new or stricter rule is a breaking change, so a
test that passes today does not fail after a minor release for a rule.
Test what a display draws#
A progresstest.Screen is a terminal in memory. It
applies the cursor moves and erases that a display writes, and shows what a
person would see. With Styles set, it records the colours of each run of
text too.
screen := &progresstest.Screen{}
fmt.Fprint(screen, "uptime · 1/3 · 0:01")
fmt.Fprint(screen, "\r\x1b[2Kuptime · 3/3 · 0:02\n")
fmt.Fprint(screen, "\x1b[?25l")
fmt.Println(screen.String())uptime · 3/3 · 0:02
^[[?25lprogress/progresstest/example_test.go. CI runs it and checks its output.The recordings on this site come from a Screen. A test of the site checks them against the displays, so they show what the code draws.