nub/internal/ui/tui/question_test.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

146 lines
4.2 KiB
Go

package tui
import (
"context"
"strings"
"testing"
"time"
)
func TestAskUser_BlocksUntilAnswered(t *testing.T) {
m := newTestModel(t)
m.askCh = make(chan askRequest)
resultCh := make(chan string, 1)
errCh := make(chan error, 1)
go func() {
answer, err := m.askUser(context.Background(), "which format?", []string{"json", "yaml"})
resultCh <- answer
errCh <- err
}()
var req askRequest
select {
case req = <-m.askCh:
case <-time.After(time.Second):
t.Fatal("timed out waiting for the request on askCh")
}
if req.question != "which format?" {
t.Errorf("req.question = %q, want %q", req.question, "which format?")
}
if len(req.options) != 2 || req.options[0] != "json" || req.options[1] != "yaml" {
t.Errorf("req.options = %v", req.options)
}
select {
case <-resultCh:
t.Fatal("askUser returned before the response was sent")
case <-time.After(50 * time.Millisecond):
}
req.resp <- "json please"
select {
case got := <-resultCh:
if got != "json please" {
t.Errorf("askUser returned %q, want %q", got, "json please")
}
if err := <-errCh; err != nil {
t.Errorf("unexpected error: %v", err)
}
case <-time.After(time.Second):
t.Fatal("timed out waiting for askUser to return")
}
}
func TestAskUser_ContextCancelReturnsErrorWithoutHanging(t *testing.T) {
m := newTestModel(t)
m.askCh = make(chan askRequest) // niemand liest daraus
ctx, cancel := context.WithCancel(context.Background())
errCh := make(chan error, 1)
go func() {
_, err := m.askUser(ctx, "irrelevant", nil)
errCh <- err
}()
cancel()
select {
case err := <-errCh:
if err == nil {
t.Error("expected a cancelled context to return an error")
}
case <-time.After(time.Second):
t.Fatal("askUser did not return after context cancellation")
}
}
func TestUpdate_AskRequestMsgOpensPromptAndReListens(t *testing.T) {
m := newTestModel(t)
m.askCh = make(chan askRequest, 1)
req := askRequest{question: "which format?", options: []string{"json", "yaml"}, resp: make(chan string, 1)}
_, cmd := m.Update(askRequestMsg{req: req})
if m.askReq == nil || m.askReq.question != "which format?" {
t.Fatalf("expected askReq to be set to the incoming request, got %+v", m.askReq)
}
if cmd == nil {
t.Fatal("expected Update to re-arm listenAskRequests")
}
if len(m.entries) != 1 || m.entries[0].kind != entryQuestion {
t.Fatalf("expected the request to appear inline in the transcript, got %+v", m.entries)
}
if !strings.Contains(m.entries[0].text, "which format?") {
t.Errorf("question entry should contain the question, got: %q", m.entries[0].text)
}
if m.textarea.Placeholder != askInputPlaceholder {
t.Errorf("expected the placeholder to switch to askInputPlaceholder, got %q", m.textarea.Placeholder)
}
}
func TestSubmit_WithOpenAskRequestAnswersInsteadOfSendingAMessage(t *testing.T) {
m := newTestModel(t)
resp := make(chan string, 1)
m.askReq = &askRequest{question: "which format?", resp: resp}
cmd := m.submit("json please", false)
if cmd != nil {
t.Error("expected submit to not return a chat/command cmd while answering a question")
}
if m.askReq != nil {
t.Error("expected askReq to be cleared")
}
select {
case got := <-resp:
if got != "json please" {
t.Errorf("resp received %q, want %q", got, "json please")
}
default:
t.Fatal("expected the answer to be sent on resp")
}
if m.textarea.Placeholder != defaultInputPlaceholder {
t.Errorf("expected the placeholder to reset to defaultInputPlaceholder, got %q", m.textarea.Placeholder)
}
if len(m.history) != 0 {
t.Error("expected the answer to not be recorded as chat history")
}
}
func TestView_AskRequestDoesNotTakeOverTheScreen(t *testing.T) {
m := newTestModelWithStore(t) // renderStatusLine liest m.store.ID
m.ready = true
m.width, m.height = 80, 24
m.viewport.Width, m.viewport.Height = 80, 20
m.entries = []entry{{kind: entryUser, text: "hello from before"}}
m.renderViewport()
m.askReq = &askRequest{question: "which format?", resp: make(chan string, 1)}
view := m.View()
if !strings.Contains(view, m.textarea.View()) {
t.Error("expected the input box to remain visible while a question is pending")
}
if !strings.Contains(stripANSI(view), "hello from before") {
t.Error("expected prior transcript content to remain visible, not be replaced by a full-screen overlay")
}
}