Files
ssh-netbox-wrapper/internal/tui/v2_test.go
T
2026-10-27 22:29:54 +01:00

124 lines
3.9 KiB
Go

package tui
import (
"strings"
"testing"
tea "charm.land/bubbletea/v2"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
)
func TestV2PasteFollowsFocusedEditor(t *testing.T) {
t.Run("search", func(t *testing.T) {
m := New(nil, nil, "")
_, cmd := m.Update(tea.PasteMsg{Content: "web-ä"})
if m.input.Value() != "web-ä" || m.seq != 1 || cmd == nil {
t.Fatalf("paste did not start search: %q, seq %d", m.input.Value(), m.seq)
}
})
t.Run("connection editor", func(t *testing.T) {
m := New(nil, nil, "")
m.openEdit(hostItem{name: "web", ip: "10.0.0.1"})
m.editInput.SetValue("")
m.Update(tea.PasteMsg{Content: "ops@web:2222"})
m.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
if m.selected == nil || m.selected.User != "ops" || m.selected.Port != "2222" {
t.Fatalf("paste lost in editor: %+v", m.selected)
}
if m.input.Value() != "" {
t.Fatal("editor paste changed search")
}
})
t.Run("filter", func(t *testing.T) {
m := New(nil, nil, "")
m.lastResults = []netbox.HostEntry{{Name: "vm", Kind: "vm"}, {Name: "device", Kind: "device"}}
m.updateListItems(m.lastResults)
m.Update(tea.KeyPressMsg{Code: 'f', Mod: tea.ModCtrl})
m.Update(tea.PasteMsg{Content: "kind:vm"})
if m.filterInput.Value() != "kind:vm" || len(m.list.Items()) != 1 {
t.Fatalf("paste did not filter: %q, %d results", m.filterInput.Value(), len(m.list.Items()))
}
if m.input.Value() != "" {
t.Fatal("filter paste changed search")
}
})
t.Run("notes", func(t *testing.T) {
m := New(nil, nil, "")
m.noteMode = true
m.input.Blur()
m.noteInput.Focus()
m.Update(tea.PasteMsg{Content: "First line\nSecond line"})
if m.noteInput.Value() != "First line\nSecond line" {
t.Fatalf("multiline paste lost: %q", m.noteInput.Value())
}
m.noteBusy = true
m.Update(tea.PasteMsg{Content: "must not change busy note"})
if m.noteInput.Value() != "First line\nSecond line" {
t.Fatal("paste edited note while loading/saving")
}
})
}
func TestV2ViewKeepsAlternateScreenInEachMode(t *testing.T) {
for _, mode := range []string{"search", "edit", "notes"} {
t.Run(mode, func(t *testing.T) {
m := New(nil, nil, "")
m.Update(tea.WindowSizeMsg{Width: 80, Height: 24})
if mode == "edit" {
m.openEdit(hostItem{name: "web"})
}
if mode == "notes" {
m.noteMode = true
}
view := m.View()
if !view.AltScreen || strings.TrimSpace(view.Content) == "" {
t.Fatalf("invalid %s view: %+v", mode, view)
}
})
}
}
func TestV2KeyReleaseDoesNotTypeTwice(t *testing.T) {
m := New(nil, nil, "")
m.Update(tea.KeyPressMsg{Code: 'e', Text: "e"})
m.Update(tea.KeyReleaseMsg{Code: 'e', Text: "e"})
if m.input.Value() != "e" {
t.Fatalf("key release changed input: %q", m.input.Value())
}
m.Update(tea.KeyPressMsg{Code: ' ', Text: " "})
if m.input.Value() != "e " {
t.Fatalf("space not inserted: %q", m.input.Value())
}
}
func TestV2ResizeShowsFullSearchPromptAndFooter(t *testing.T) {
m := New(nil, nil, "")
m.Update(tea.WindowSizeMsg{Width: 100, Height: 24})
var entries []netbox.HostEntry
for range 30 {
entries = append(entries, netbox.HostEntry{Name: "web", Kind: "device"})
}
m.updateListItems(entries)
view := m.View()
if m.input.Width() != 98 || m.filterInput.Width() != 92 || m.editInput.Width() != 88 {
t.Fatalf("editors were not sized for terminal: search=%d filter=%d edit=%d", m.input.Width(), m.filterInput.Width(), m.editInput.Width())
}
if !strings.Contains(view.Content, "earch hostname") || !strings.Contains(view.Content, "ctrl+c quit") {
t.Fatalf("search prompt or footer missing: %s", view.Content)
}
assertFits := func() {
t.Helper()
if rows := strings.Count(m.View().Content, "\n"); rows > 24 {
t.Fatalf("view overflows terminal: %d rows", rows)
}
}
assertFits()
m.lastResults = entries
m.Update(tea.KeyPressMsg{Code: 'f', Mod: tea.ModCtrl})
assertFits()
m.Update(tea.KeyPressMsg{Code: 'f', Mod: tea.ModCtrl})
m.Update(tea.KeyPressMsg{Code: 'e', Mod: tea.ModCtrl})
assertFits()
}