146 lines
4.2 KiB
Go
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")
|
|
}
|
|
}
|