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() }