From 41a8328d19e6e587579a9cc278f91412637edba1 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Thu, 8 Feb 2024 15:02:57 -0300 Subject: [PATCH] teatest: use one program within another Signed-off-by: Carlos Alexandro Becker --- exp/teatest/send_test.go | 87 +++++++++++++++++++ exp/teatest/teatest.go | 8 +- .../testdata/TestAppSendToOtherProgram.golden | 7 ++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 exp/teatest/send_test.go create mode 100644 exp/teatest/testdata/TestAppSendToOtherProgram.golden diff --git a/exp/teatest/send_test.go b/exp/teatest/send_test.go new file mode 100644 index 00000000..371cf561 --- /dev/null +++ b/exp/teatest/send_test.go @@ -0,0 +1,87 @@ +package teatest_test + +import ( + "fmt" + "strings" + "testing" + "time" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/x/exp/teatest" +) + +func TestAppSendToOtherProgram(t *testing.T) { + m1 := &connectedModel{ + name: "m1", + } + m2 := &connectedModel{ + name: "m2", + } + + tm1 := teatest.NewTestModel(t, m1, teatest.WithInitialTermSize(70, 30)) + t.Cleanup(func() { + if err := tm1.Quit(); err != nil { + t.Fatal(err) + } + }) + tm2 := teatest.NewTestModel(t, m2, teatest.WithInitialTermSize(70, 30)) + t.Cleanup(func() { + if err := tm2.Quit(); err != nil { + t.Fatal(err) + } + }) + m1.programs = append(m1.programs, tm2) + m2.programs = append(m2.programs, tm1) + + tm1.Type("pp") + tm2.Type("pppp") + + tm1.Type("q") + tm2.Type("q") + + out1 := readBts(t, tm1.FinalOutput(t, teatest.WithFinalTimeout(time.Second))) + out2 := readBts(t, tm2.FinalOutput(t, teatest.WithFinalTimeout(time.Second))) + + if string(out1) != string(out2) { + t.Errorf("output of both models should be the same, got:\n%v\nand:\n%v\n", string(out1), string(out2)) + } + + teatest.RequireEqualOutput(t, out1) +} + +type connectedModel struct { + name string + programs []interface{ Send(tea.Msg) } + msgs []string +} + +type ping string + +func (m *connectedModel) Init() tea.Cmd { + return nil +} + +func (m *connectedModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "p": + send := ping("from " + m.name) + m.msgs = append(m.msgs, string(send)) + for _, p := range m.programs { + p.Send(send) + } + fmt.Printf("sent ping %q to others\n", send) + case "q": + return m, tea.Quit + } + case ping: + fmt.Printf("rcvd ping %q on %s\n", msg, m.name) + m.msgs = append(m.msgs, string(msg)) + } + return m, nil +} + +func (m *connectedModel) View() string { + return "All pings:\n" + strings.Join(m.msgs, "\n") +} diff --git a/exp/teatest/teatest.go b/exp/teatest/teatest.go index 8a9ac8fc..1ea14728 100644 --- a/exp/teatest/teatest.go +++ b/exp/teatest/teatest.go @@ -148,7 +148,7 @@ func NewTestModel(tb testing.TB, m tea.Model, options ...TestOption) *TestModel <-interruptions signal.Stop(interruptions) tb.Log("interrupted") - tm.program.Quit() + tm.program.Kill() }() var opts TestModelOptions @@ -162,6 +162,10 @@ func NewTestModel(tb testing.TB, m tea.Model, options ...TestOption) *TestModel return tm } +// GetProgram returns the underlying program. +// This should be used only to test apps that talk to other apps. +// func (tm *TestModel) GetProgram() *tea.Program { return tm.program } + func (tm *TestModel) waitDone(tb testing.TB, opts []FinalOpt) { tm.done.Do(func() { fopts := FinalOpts{} @@ -244,7 +248,7 @@ func (tm *TestModel) Quit() error { // Type types the given text into the given program. func (tm *TestModel) Type(s string) { for _, c := range []byte(s) { - tm.program.Send(tea.KeyMsg{ + tm.Send(tea.KeyMsg{ Runes: []rune{rune(c)}, Type: tea.KeyRunes, }) diff --git a/exp/teatest/testdata/TestAppSendToOtherProgram.golden b/exp/teatest/testdata/TestAppSendToOtherProgram.golden new file mode 100644 index 00000000..ad2c2a0f --- /dev/null +++ b/exp/teatest/testdata/TestAppSendToOtherProgram.golden @@ -0,0 +1,7 @@ +[?25lAll pings: +from m1 +from m1 +from m2 +from m2 +from m2 +from m2[?25h[?1002l[?1003l[?1006l \ No newline at end of file