@@ -6,6 +6,7 @@ import (
66 "testing"
77
88 "charm.land/bubbles/v2/textarea"
9+ "github.com/charmbracelet/crush/internal/session"
910 "github.com/charmbracelet/crush/internal/ui/chat"
1011 "github.com/charmbracelet/crush/internal/ui/common"
1112)
@@ -118,3 +119,109 @@ func TestHandleTextareaHeightChange_FollowModeStaysAtBottom(t *testing.T) {
118119 t.Fatal("expected chat to remain at bottom after editor resize in follow mode")
119120 }
120121}
122+
123+func TestAutoExpandPillsIfReasonable(t *testing.T) {
124+ t.Parallel()
125+
126+ t.Run("expands when terminal is tall enough and todos exist", func(t *testing.T) {
127+ t.Parallel()
128+
129+ u := newTestUI()
130+ u.height = 50
131+ u.session = &session.Session{ID: "s1", Todos: []session.Todo{
132+ {Status: session.TodoStatusInProgress, Content: "do work"},
133+ {Status: session.TodoStatusPending, Content: "do more"},
134+ }}
135+
136+ u.autoExpandPillsIfReasonable()
137+
138+ if !u.pillsExpanded {
139+ t.Fatal("expected pillsExpanded to be true")
140+ }
141+ if u.focusedPillSection != pillSectionTodos {
142+ t.Fatalf("expected focusedPillSection to be pillSectionTodos, got %d", u.focusedPillSection)
143+ }
144+ })
145+
146+ t.Run("does not expand when terminal is too short", func(t *testing.T) {
147+ t.Parallel()
148+
149+ u := newTestUI()
150+ u.height = 30
151+ u.session = &session.Session{ID: "s1", Todos: []session.Todo{
152+ {Status: session.TodoStatusInProgress, Content: "do work"},
153+ }}
154+
155+ u.autoExpandPillsIfReasonable()
156+
157+ if u.pillsExpanded {
158+ t.Fatal("expected pillsExpanded to be false when terminal height is below threshold")
159+ }
160+ })
161+
162+ t.Run("does not expand when all todos are completed", func(t *testing.T) {
163+ t.Parallel()
164+
165+ u := newTestUI()
166+ u.height = 50
167+ u.session = &session.Session{ID: "s1", Todos: []session.Todo{
168+ {Status: session.TodoStatusCompleted, Content: "done"},
169+ }}
170+
171+ u.autoExpandPillsIfReasonable()
172+
173+ if u.pillsExpanded {
174+ t.Fatal("expected pillsExpanded to be false when all todos are completed")
175+ }
176+ })
177+
178+ t.Run("does not expand when already expanded", func(t *testing.T) {
179+ t.Parallel()
180+
181+ u := newTestUI()
182+ u.height = 50
183+ u.pillsExpanded = true
184+ u.session = &session.Session{ID: "s1", Todos: []session.Todo{
185+ {Status: session.TodoStatusInProgress, Content: "do work"},
186+ }}
187+ u.updateLayoutAndSize()
188+
189+ u.autoExpandPillsIfReasonable()
190+
191+ if !u.pillsExpanded {
192+ t.Fatal("expected pillsExpanded to stay true")
193+ }
194+ })
195+
196+ t.Run("expands for prompt queue when no todos", func(t *testing.T) {
197+ t.Parallel()
198+
199+ u := newTestUI()
200+ u.height = 50
201+ u.session = &session.Session{ID: "s1", Todos: []session.Todo{}}
202+ u.promptQueue = 2
203+
204+ u.autoExpandPillsIfReasonable()
205+
206+ if !u.pillsExpanded {
207+ t.Fatal("expected pillsExpanded to be true for prompt queue")
208+ }
209+ if u.focusedPillSection != pillSectionQueue {
210+ t.Fatalf("expected focusedPillSection to be pillSectionQueue, got %d", u.focusedPillSection)
211+ }
212+ })
213+
214+ t.Run("does not expand when no session", func(t *testing.T) {
215+ t.Parallel()
216+
217+ u := newTestUI()
218+ u.height = 50
219+ u.session = nil
220+
221+ u.autoExpandPillsIfReasonable()
222+
223+ if u.pillsExpanded {
224+ t.Fatal("expected pillsExpanded to be false when there is no session")
225+ }
226+ })
227+}