omnibox_initial_behavior_test.go RawHistoryFolder
1package component
2
3import (
4 "context"
5 "errors"
6 "testing"
7 "time"
8
9 appusecase "github.com/bnema/dumber/internal/application/usecase"
10 "github.com/bnema/dumber/internal/domain/entity"
11 repomocks "github.com/bnema/dumber/internal/domain/repository/mocks"
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/mock"
14)
15
16func TestOmniboxInitialBehaviorBadgeState(t *testing.T) {
17 tests := []struct {
18 name string
19 behavior entity.OmniboxInitialBehavior
20 wantVisible bool
21 wantLabel string
22 wantTooltip string
23 wantNext entity.OmniboxInitialBehavior
24 }{
25 {
26 name: "recent",
27 behavior: entity.OmniboxInitialBehaviorRecent,
28 wantVisible: true,
29 wantLabel: "Recent",
30 wantTooltip: "Toggle default history order (Ctrl+R)",
31 wantNext: entity.OmniboxInitialBehaviorMostVisited,
32 },
33 {
34 name: "most visited",
35 behavior: entity.OmniboxInitialBehaviorMostVisited,
36 wantVisible: true,
37 wantLabel: "Most used",
38 wantTooltip: "Toggle default history order (Ctrl+R)",
39 wantNext: entity.OmniboxInitialBehaviorRecent,
40 },
41 {
42 name: "none",
43 behavior: entity.OmniboxInitialBehaviorNone,
44 },
45 {
46 name: "invalid",
47 behavior: entity.OmniboxInitialBehavior("unsupported"),
48 },
49 }
50
51 for _, tt := range tests {
52 t.Run(tt.name, func(t *testing.T) {
53 got := initialBehaviorBadgeState(tt.behavior)
54 assert.Equal(t, tt.wantVisible, got.visible)
55 assert.Equal(t, tt.wantLabel, got.label)
56 assert.Equal(t, tt.wantTooltip, got.tooltip)
57 assert.Equal(t, tt.wantNext, got.nextBehavior)
58 })
59 }
60}
61
62func TestShouldRefreshInitialHistoryAfterToggle(t *testing.T) {
63 tests := []struct {
64 name string
65 viewMode ViewMode
66 query string
67 behavior entity.OmniboxInitialBehavior
68 wantRefresh bool
69 }{
70 {
71 name: "empty history mode",
72 viewMode: ViewModeHistory,
73 query: "",
74 behavior: entity.OmniboxInitialBehaviorRecent,
75 wantRefresh: true,
76 },
77 {
78 name: "typed query",
79 viewMode: ViewModeHistory,
80 query: "go",
81 behavior: entity.OmniboxInitialBehaviorRecent,
82 wantRefresh: false,
83 },
84 {
85 name: "favorites mode",
86 viewMode: ViewModeFavorites,
87 query: "",
88 behavior: entity.OmniboxInitialBehaviorRecent,
89 wantRefresh: false,
90 },
91 {
92 name: "unsupported behavior",
93 viewMode: ViewModeHistory,
94 query: "",
95 behavior: entity.OmniboxInitialBehaviorNone,
96 wantRefresh: false,
97 },
98 }
99
100 for _, tt := range tests {
101 t.Run(tt.name, func(t *testing.T) {
102 assert.Equal(t, tt.wantRefresh, shouldRefreshInitialHistoryAfterToggle(tt.viewMode, tt.query, tt.behavior))
103 })
104 }
105}
106
107func TestOmniboxToggleInitialBehaviorPreference_SaveFailureKeepsBehaviorAndShowsToast(t *testing.T) {
108 o := &Omnibox{initialBehavior: entity.OmniboxInitialBehaviorRecent, ctx: context.Background()}
109 o.saveInitialBehaviorFn = func(context.Context, entity.OmniboxInitialBehavior) error {
110 return errors.New("boom")
111 }
112
113 var gotMessage string
114 var gotLevel ToastLevel
115 o.onToast = func(_ context.Context, message string, level ToastLevel) {
116 gotMessage = message
117 gotLevel = level
118 }
119
120 refreshCalls := 0
121 origLoadInitialHistoryFn := loadInitialHistoryFn
122 loadInitialHistoryFn = func(*Omnibox, uint64) {
123 refreshCalls++
124 }
125 t.Cleanup(func() {
126 loadInitialHistoryFn = origLoadInitialHistoryFn
127 })
128
129 assert.False(t, o.toggleInitialBehaviorPreference())
130 assert.Equal(t, entity.OmniboxInitialBehaviorRecent, o.initialBehavior)
131 assert.Equal(t, "Failed to save default history order", gotMessage)
132 assert.Equal(t, ToastError, gotLevel)
133 assert.Equal(t, 0, refreshCalls)
134}
135
136func TestOmniboxToggleInitialBehaviorPreference_RefreshesEmptyHistory(t *testing.T) {
137 o := &Omnibox{initialBehavior: entity.OmniboxInitialBehaviorRecent, viewMode: ViewModeHistory, ctx: context.Background()}
138 o.saveInitialBehaviorFn = func(context.Context, entity.OmniboxInitialBehavior) error {
139 return nil
140 }
141
142 refreshCalls := 0
143 origLoadInitialHistoryFn := loadInitialHistoryFn
144 loadInitialHistoryFn = func(*Omnibox, uint64) {
145 refreshCalls++
146 }
147 t.Cleanup(func() {
148 loadInitialHistoryFn = origLoadInitialHistoryFn
149 })
150
151 assert.True(t, o.toggleInitialBehaviorPreference())
152 assert.Equal(t, entity.OmniboxInitialBehaviorMostVisited, o.initialBehavior)
153 assert.Equal(t, 1, refreshCalls)
154}
155
156func TestOmniboxLoadInitialHistory_UsesCapturedInitialBehavior(t *testing.T) {
157 repo := repomocks.NewMockHistoryRepository(t)
158 done := make(chan struct{})
159 repo.EXPECT().GetRecent(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(
160 func(context.Context, int, int) ([]*entity.HistoryEntry, error) {
161 close(done)
162 return []*entity.HistoryEntry{{URL: "https://example.com"}}, nil
163 },
164 )
165
166 o := &Omnibox{
167 historyUC: appusecase.NewSearchHistoryUseCase(repo),
168 initialBehavior: entity.OmniboxInitialBehaviorRecent,
169 ctx: context.Background(),
170 }
171
172 o.loadInitialHistory(1)
173 o.initialBehavior = entity.OmniboxInitialBehaviorMostVisited
174
175 select {
176 case <-done:
177 case <-time.After(2 * time.Second):
178 t.Fatal("timed out waiting for recent-history load")
179 }
180}
181
182func TestOmniboxLoadInitialHistory_MostVisitedUsesThirtyDayWindow(t *testing.T) {
183 repo := repomocks.NewMockHistoryRepository(t)
184 done := make(chan struct{})
185 repo.EXPECT().GetMostVisited(mock.Anything, 30).RunAndReturn(
186 func(context.Context, int) ([]*entity.HistoryEntry, error) {
187 close(done)
188 return []*entity.HistoryEntry{{URL: "https://example.com"}}, nil
189 },
190 )
191
192 o := &Omnibox{
193 historyUC: appusecase.NewSearchHistoryUseCase(repo),
194 initialBehavior: entity.OmniboxInitialBehaviorMostVisited,
195 mostVisitedDays: 30,
196 ctx: context.Background(),
197 }
198
199 o.loadInitialHistory(1)
200
201 select {
202 case <-done:
203 case <-time.After(2 * time.Second):
204 t.Fatal("timed out waiting for most-visited load")
205 }
206}
207
208func TestOmniboxLoadInitialHistory_MostVisitedUsesConfiguredWindow(t *testing.T) {
209 repo := repomocks.NewMockHistoryRepository(t)
210 done := make(chan struct{})
211 repo.EXPECT().GetMostVisited(mock.Anything, 7).RunAndReturn(
212 func(context.Context, int) ([]*entity.HistoryEntry, error) {
213 close(done)
214 return []*entity.HistoryEntry{{URL: "https://example.com"}}, nil
215 },
216 )
217
218 o := &Omnibox{
219 historyUC: appusecase.NewSearchHistoryUseCase(repo),
220 initialBehavior: entity.OmniboxInitialBehaviorMostVisited,
221 mostVisitedDays: 7,
222 ctx: context.Background(),
223 }
224
225 o.loadInitialHistory(1)
226
227 select {
228 case <-done:
229 case <-time.After(2 * time.Second):
230 t.Fatal("timed out waiting for configured most-visited load")
231 }
232}
233
234func TestOmniboxLoadInitialHistory_MostVisitedZeroWindowUsesAllHistory(t *testing.T) {
235 repo := repomocks.NewMockHistoryRepository(t)
236 done := make(chan struct{})
237 repo.EXPECT().GetAllMostVisited(mock.Anything).RunAndReturn(
238 func(context.Context) ([]*entity.HistoryEntry, error) {
239 close(done)
240 return []*entity.HistoryEntry{{URL: "https://example.com"}}, nil
241 },
242 )
243
244 o := &Omnibox{
245 historyUC: appusecase.NewSearchHistoryUseCase(repo),
246 initialBehavior: entity.OmniboxInitialBehaviorMostVisited,
247 mostVisitedDays: 0,
248 ctx: context.Background(),
249 }
250
251 o.loadInitialHistory(1)
252
253 select {
254 case <-done:
255 case <-time.After(2 * time.Second):
256 t.Fatal("timed out waiting for all-history most-visited load")
257 }
258}