github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/hud/prompt/prompt_test.go (about) 1 package prompt 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "net/url" 8 "reflect" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/assert" 13 14 "github.com/tilt-dev/tilt/internal/store" 15 "github.com/tilt-dev/tilt/internal/testutils" 16 "github.com/tilt-dev/tilt/internal/testutils/bufsync" 17 "github.com/tilt-dev/tilt/pkg/model" 18 ) 19 20 const FakeURL = "http://localhost:10350/" 21 22 func TestOpenBrowser(t *testing.T) { 23 f := newFixture(t) 24 25 _ = f.prompt.OnChange(f.ctx, f.st, store.LegacyChangeSummary()) 26 27 assert.Contains(t, f.out.String(), "(space) to open the browser") 28 29 f.input.nextRune <- ' ' 30 assert.Equal(t, FakeURL, f.b.WaitForURL(t)) 31 } 32 33 func TestOpenStream(t *testing.T) { 34 f := newFixture(t) 35 36 _ = f.prompt.OnChange(f.ctx, f.st, store.LegacyChangeSummary()) 37 38 assert.Contains(t, f.out.String(), "(s) to stream logs") 39 40 f.input.nextRune <- 's' 41 42 action := f.st.WaitForAction(t, reflect.TypeOf(SwitchTerminalModeAction{})) 43 assert.Equal(t, SwitchTerminalModeAction{Mode: store.TerminalModeStream}, action) 44 } 45 46 func TestOpenHUD(t *testing.T) { 47 f := newFixture(t) 48 49 _ = f.prompt.OnChange(f.ctx, f.st, store.LegacyChangeSummary()) 50 51 assert.Contains(t, f.out.String(), "(t) to open legacy terminal mode") 52 53 f.input.nextRune <- 't' 54 55 action := f.st.WaitForAction(t, reflect.TypeOf(SwitchTerminalModeAction{})) 56 assert.Equal(t, SwitchTerminalModeAction{Mode: store.TerminalModeHUD}, action) 57 } 58 59 func TestInitOutput(t *testing.T) { 60 f := newFixture(t) 61 62 f.prompt.SetInitOutput(bytes.NewBuffer([]byte("this is a warning\n"))) 63 _ = f.prompt.OnChange(f.ctx, f.st, store.LegacyChangeSummary()) 64 65 assert.Contains(t, f.out.String(), `this is a warning 66 67 (space) to open the browser`) 68 } 69 70 type fixture struct { 71 ctx context.Context 72 cancel func() 73 out *bufsync.ThreadSafeBuffer 74 st *store.TestingStore 75 b *fakeBrowser 76 input *fakeInput 77 prompt *TerminalPrompt 78 } 79 80 func newFixture(t *testing.T) *fixture { 81 ctx, _, ta := testutils.CtxAndAnalyticsForTest() 82 ctx, cancel := context.WithCancel(ctx) 83 out := bufsync.NewThreadSafeBuffer() 84 st := store.NewTestingStore() 85 st.WithState(func(state *store.EngineState) { 86 state.TerminalMode = store.TerminalModePrompt 87 }) 88 i := &fakeInput{ctx: ctx, nextRune: make(chan rune)} 89 b := &fakeBrowser{url: make(chan string)} 90 openInput := OpenInput(func() (TerminalInput, error) { return i, nil }) 91 92 url, _ := url.Parse(FakeURL) 93 94 prompt := NewTerminalPrompt(ta, openInput, b.OpenURL, out, "localhost", model.WebURL(*url)) 95 ret := &fixture{ 96 ctx: ctx, 97 cancel: cancel, 98 out: out, 99 st: st, 100 input: i, 101 b: b, 102 prompt: prompt, 103 } 104 105 t.Cleanup(ret.TearDown) 106 107 return ret 108 } 109 110 func (f *fixture) TearDown() { 111 f.cancel() 112 } 113 114 type fakeInput struct { 115 ctx context.Context 116 nextRune chan rune 117 } 118 119 func (i *fakeInput) Close() error { return nil } 120 121 func (i *fakeInput) ReadRune() (rune, error) { 122 select { 123 case r := <-i.nextRune: 124 return r, nil 125 case <-i.ctx.Done(): 126 return 0, i.ctx.Err() 127 } 128 } 129 130 type fakeBrowser struct { 131 url chan string 132 } 133 134 func (b *fakeBrowser) WaitForURL(t *testing.T) string { 135 select { 136 case <-time.After(time.Second): 137 t.Fatal("timeout waiting for url") 138 return "" 139 case url := <-b.url: 140 return url 141 } 142 } 143 144 func (b *fakeBrowser) OpenURL(url string, w io.Writer) error { 145 b.url <- url 146 return nil 147 }