Skip to content

Commit 5c61dbd

Browse files
committed
test: add teatest-based Spawn coverage and WindowSizeMsg test
Extract runProgram function variable from Spawn (matching existing testability pattern) and use teatest/v2 to exercise Spawn through a real Bubbletea program lifecycle. Adds WindowSizeMsg handler coverage.
1 parent 4b2eb7a commit 5c61dbd

4 files changed

Lines changed: 44 additions & 3 deletions

File tree

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ require (
1616
require (
1717
charm.land/lipgloss/v2 v2.0.2 // indirect
1818
github.com/atotto/clipboard v0.1.4 // indirect
19+
github.com/aymanbagabas/go-udiff v0.4.1 // indirect
1920
github.com/charmbracelet/colorprofile v0.4.2 // indirect
2021
github.com/charmbracelet/ultraviolet v0.0.0-20260205113103-524a6607adb8 // indirect
2122
github.com/charmbracelet/x/ansi v0.11.6 // indirect
23+
github.com/charmbracelet/x/exp/golden v0.0.0-20251109135125-8916d276318f // indirect
24+
github.com/charmbracelet/x/exp/teatest/v2 v2.0.0-20260323091123-df7b1bcffcca // indirect
2225
github.com/charmbracelet/x/term v0.2.2 // indirect
2326
github.com/charmbracelet/x/termios v0.1.1 // indirect
2427
github.com/charmbracelet/x/windows v0.2.2 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF
1616
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
1717
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA=
1818
github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I=
19+
github.com/charmbracelet/x/exp/golden v0.0.0-20251109135125-8916d276318f h1:8CnFOYzrMArVN42jYaGvnBo3mxdONgt09fly+9B96GY=
20+
github.com/charmbracelet/x/exp/golden v0.0.0-20251109135125-8916d276318f/go.mod h1:V8n/g3qVKNxr2FR37Y+otCsMySvZr601T0C7coEP0bw=
21+
github.com/charmbracelet/x/exp/teatest/v2 v2.0.0-20260323091123-df7b1bcffcca h1:Tl5ey00ZDMTGQ3ZWAJAADx2/OxNgN0LFTxmwPKvq04A=
22+
github.com/charmbracelet/x/exp/teatest/v2 v2.0.0-20260323091123-df7b1bcffcca/go.mod h1:aRoQwQWmN9LBG2xi3sVByMFt2fdkPCagd0GAJ1qwOfw=
1923
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
2024
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
2125
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=

internal/shell/shell.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ func outputBufferSize(hostCount int) int {
1818
return size
1919
}
2020

21+
var runProgram = func(m tea.Model) (tea.Model, error) {
22+
return tea.NewProgram(m).Run()
23+
}
24+
2125
func Spawn(hostList *sshConn.HostList) {
2226
broker := make(chan sshConn.CommandRequest)
2327
hostCount := 0
@@ -27,8 +31,7 @@ func Spawn(hostList *sshConn.HostList) {
2731
events := make(chan sshConn.OutputEvent, outputBufferSize(hostCount))
2832
go sshConn.Broker(hostList, broker, events)
2933

30-
p := tea.NewProgram(initialModel(hostList, broker, events))
31-
if _, err := p.Run(); err != nil {
34+
if _, err := runProgram(initialModel(hostList, broker, events)); err != nil {
3235
panic(err)
3336
}
3437
}

internal/shell/shell_test.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package shell
22

3-
import "testing"
3+
import (
4+
"testing"
5+
"time"
6+
7+
tea "charm.land/bubbletea/v2"
8+
teatest "github.com/charmbracelet/x/exp/teatest/v2"
9+
"github.com/ncode/pretty/internal/sshConn"
10+
)
411

512
func TestOutputBufferSizeMinimum(t *testing.T) {
613
if got := outputBufferSize(0); got != 128 {
@@ -13,3 +20,27 @@ func TestOutputBufferSizeScales(t *testing.T) {
1320
t.Fatalf("unexpected size: %d", got)
1421
}
1522
}
23+
24+
func TestSpawnExitsOnBye(t *testing.T) {
25+
orig := runProgram
26+
t.Cleanup(func() { runProgram = orig })
27+
28+
var final tea.Model
29+
runProgram = func(m tea.Model) (tea.Model, error) {
30+
tm := teatest.NewTestModel(t, m, teatest.WithInitialTermSize(80, 24))
31+
tm.Type(":bye")
32+
tm.Send(tea.KeyPressMsg{Code: tea.KeyEnter})
33+
final = tm.FinalModel(t, teatest.WithFinalTimeout(5*time.Second))
34+
return final, nil
35+
}
36+
37+
Spawn(sshConn.NewHostList())
38+
39+
m, ok := final.(model)
40+
if !ok {
41+
t.Fatalf("expected model, got %T", final)
42+
}
43+
if !m.quit {
44+
t.Fatal("expected model to be in quit state")
45+
}
46+
}

0 commit comments

Comments
 (0)