cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package ui
2
3import (
4 "testing"
5 "time"
6
7 tea "github.com/charmbracelet/bubbletea"
8 "github.com/stormlightlabs/noteleaf/internal/shared"
9)
10
11type mockListModel struct {
12 showingHelp bool
13 width int
14 height int
15}
16
17func createMockListModel() *mockListModel {
18 return &mockListModel{width: 80, height: 24}
19}
20
21func (m *mockListModel) Init() tea.Cmd {
22 return nil
23}
24
25func (m *mockListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
26 switch msg := msg.(type) {
27 case tea.KeyMsg:
28 switch msg.String() {
29 case "?":
30 m.showingHelp = !m.showingHelp
31 case "q":
32 return m, tea.Quit
33 case "esc":
34 m.showingHelp = false
35 }
36 case tea.WindowSizeMsg:
37 m.width = msg.Width
38 m.height = msg.Height
39 }
40 return m, nil
41}
42
43func (m *mockListModel) View() string {
44 if m.showingHelp {
45 return "help: showing help content"
46 }
47 return "mock list view - normal mode"
48}
49
50func TestDataListInteractiveBehavior(t *testing.T) {
51 t.Run("Help Toggle with TUI Framework", func(t *testing.T) {
52 model := createMockListModel()
53
54 suite := NewTUITestSuite(t, model)
55 suite.Start()
56
57 if err := suite.SendKeyString("?"); err != nil {
58 t.Fatalf("Failed to send '?' key: %v", err)
59 }
60
61 if err := suite.WaitForView("help", 1*time.Second); err != nil {
62 t.Errorf("Expected help to be shown: %v", err)
63 }
64
65 if err := suite.SendKey(tea.KeyEsc); err != nil {
66 t.Fatalf("Failed to send escape key: %v", err)
67 }
68
69 if err := suite.WaitFor(func(m tea.Model) bool {
70 view := m.View()
71 return !shared.ContainsString(view, "help")
72 }, 1*time.Second); err != nil {
73 t.Errorf("Help should have been hidden: %v", err)
74 }
75 })
76
77 t.Run("Page Navigation with TUI Framework", func(t *testing.T) {
78 model := createMockListModel()
79
80 suite := NewTUITestSuite(t, model)
81 suite.Start()
82
83 if err := suite.SendKey(tea.KeyPgDown); err != nil {
84 t.Fatalf("Failed to send page down key: %v", err)
85 }
86
87 time.Sleep(100 * time.Millisecond)
88
89 if err := suite.SendKey(tea.KeyPgUp); err != nil {
90 t.Fatalf("Failed to send page up key: %v", err)
91 }
92
93 if err := suite.SendKey(tea.KeyHome); err != nil {
94 t.Fatalf("Failed to send home key: %v", err)
95 }
96
97 if err := suite.SendKey(tea.KeyEnd); err != nil {
98 t.Fatalf("Failed to send end key: %v", err)
99 }
100
101 view := suite.GetCurrentView()
102 if len(view) == 0 {
103 t.Error("View should not be empty after navigation")
104 }
105 })
106
107 t.Run("Quit Command with TUI Framework", func(t *testing.T) {
108 model := createMockListModel()
109
110 suite := NewTUITestSuite(t, model)
111 suite.Start()
112
113 if err := suite.SendKeyString("q"); err != nil {
114 t.Fatalf("Failed to send 'q' key: %v", err)
115 }
116
117 if err := suite.WaitFor(func(m tea.Model) bool {
118 return true
119 }, 1*time.Second); err != nil {
120 t.Errorf("Quit command should have been processed: %v", err)
121 }
122 })
123}
124
125func TestTUIPatternMatching(t *testing.T) {
126 t.Run("Key Message Switch Cases", func(t *testing.T) {
127 model := createMockListModel()
128 suite := NewTUITestSuite(t, model)
129 suite.Start()
130
131 testKeys := []tea.KeyType{
132 tea.KeyUp,
133 tea.KeyDown,
134 tea.KeyLeft,
135 tea.KeyRight,
136 tea.KeyEnter,
137 tea.KeySpace,
138 tea.KeyTab,
139 }
140
141 for _, keyType := range testKeys {
142 err := suite.SendKey(keyType)
143 if err != nil {
144 t.Errorf("Failed to send key %v: %v", keyType, err)
145 }
146
147 time.Sleep(50 * time.Millisecond)
148 }
149
150 view := suite.GetCurrentView()
151 if len(view) == 0 {
152 t.Error("View should not be empty after key processing")
153 }
154 })
155
156 t.Run("Message Type Switch Cases", func(t *testing.T) {
157 model := createMockListModel()
158 suite := NewTUITestSuite(t, model)
159 suite.Start()
160
161 messages := []tea.Msg{
162 tea.WindowSizeMsg{Width: 100, Height: 30},
163 tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'r'}},
164 tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'/'}},
165 }
166
167 for _, msg := range messages {
168 err := suite.SendMessage(msg)
169 if err != nil {
170 t.Errorf("Failed to send message %T: %v", msg, err)
171 }
172
173 time.Sleep(50 * time.Millisecond)
174 }
175
176 view := suite.GetCurrentView()
177 if len(view) == 0 {
178 t.Error("View should not be empty after message processing")
179 }
180 })
181}