browser_window_favorites_sidebar_test.go RawHistoryFolder
1package ui
2
3import (
4 "context"
5 "errors"
6 "testing"
7
8 "github.com/bnema/dumber/internal/application/usecase"
9 "github.com/bnema/dumber/internal/domain/entity"
10 "github.com/bnema/dumber/internal/ui/component"
11 contentcoord "github.com/bnema/dumber/internal/ui/coordinator/content"
12 "github.com/bnema/dumber/internal/ui/window"
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15)
16
17func TestBrowserWindow_FavoritesSidebarToggle_CoexistsWithHistorySidebar(t *testing.T) {
18 bw := &browserWindow{
19 id: "test-window",
20 mainWindow: &window.MainWindow{},
21 historySidebar: &component.HistorySidebar{},
22 favoritesSidebar: &component.FavoritesSidebar{},
23 }
24
25 bw.showHistorySidebar()
26 assert.True(t, bw.sidebarVisible)
27 assert.Equal(t, nativeSidebarHistory, bw.activeSidebarKind)
28
29 bw.toggleFavoritesSidebar()
30 assert.True(t, bw.sidebarVisible)
31 assert.Equal(t, nativeSidebarFavorites, bw.activeSidebarKind)
32
33 bw.toggleHistorySidebar()
34 assert.True(t, bw.sidebarVisible)
35 assert.Equal(t, nativeSidebarHistory, bw.activeSidebarKind)
36
37 bw.toggleHistorySidebar()
38 assert.False(t, bw.sidebarVisible)
39 assert.Equal(t, nativeSidebarNone, bw.activeSidebarKind)
40}
41
42func TestApp_ToggleFavoritesSidebarActionHidesActiveFavoritesSidebar(t *testing.T) {
43 bw := &browserWindow{
44 id: "w",
45 mainWindow: &window.MainWindow{},
46 favoritesSidebar: &component.FavoritesSidebar{},
47 sidebarVisible: true,
48 activeSidebarKind: nativeSidebarFavorites,
49 }
50 app := &App{browserWindows: map[string]*browserWindow{bw.id: bw}, lastFocusedWindowID: bw.id}
51
52 require.NoError(t, app.toggleFavoritesSidebarAction(context.Background()))
53
54 assert.False(t, bw.sidebarVisible)
55 assert.Equal(t, nativeSidebarNone, bw.activeSidebarKind)
56}
57
58func TestFavoritesSidebarConfigOnCloseHidesFavoritesSidebar(t *testing.T) {
59 bw := &browserWindow{
60 id: "w",
61 mainWindow: &window.MainWindow{},
62 favoritesSidebar: &component.FavoritesSidebar{},
63 sidebarVisible: true,
64 activeSidebarKind: nativeSidebarFavorites,
65 }
66 app := &App{browserWindows: map[string]*browserWindow{bw.id: bw}, lastFocusedWindowID: bw.id}
67
68 cfg := app.buildFavoritesSidebarConfig(bw)
69 require.NotNil(t, cfg.OnClose)
70 cfg.OnClose()
71
72 assert.False(t, bw.sidebarVisible)
73 assert.Equal(t, nativeSidebarNone, bw.activeSidebarKind)
74}
75
76func TestApp_ToggleFavoritesSidebarActionErrorsWhenUnavailable(t *testing.T) {
77 app := &App{browserWindows: map[string]*browserWindow{"w": {id: "w"}}, lastFocusedWindowID: "w"}
78 err := app.toggleFavoritesSidebarAction(context.Background())
79 require.Error(t, err)
80 assert.ErrorContains(t, err, "favorites sidebar unavailable")
81}
82
83func TestApp_ToggleCurrentPageFavoriteTogglesActiveWebViewURI(t *testing.T) {
84 ctx := context.Background()
85 tab := entity.NewTab(entity.TabID("tab-1"), entity.WorkspaceID("ws-1"), entity.NewPane(entity.PaneID("pane-1")))
86 tabs := entity.NewTabList()
87 tabs.Add(tab)
88 tabs.SetActive(tab.ID)
89 bw := &browserWindow{id: "w", tabs: tabs}
90
91 contentCoord := contentcoord.NewCoordinator(ctx, nil, nil, nil, nil, nil, nil, nil)
92 wv := &recordingWebView{id: 1, loadURILastURI: "https://example.com/page"}
93 contentCoord.RegisterPopupWebView(entity.PaneID("pane-1"), wv)
94
95 favRepo := newMemoryFavoriteRepo()
96 app := &App{
97 deps: &Dependencies{FavoritesUC: usecase.NewManageFavoritesUseCase(favRepo, &memoryTagRepo{})},
98 browserWindows: map[string]*browserWindow{bw.id: bw},
99 lastFocusedWindowID: bw.id,
100 contentCoord: contentCoord,
101 workspaceViews: map[entity.TabID]*component.WorkspaceView{tab.ID: {}},
102 }
103
104 require.NoError(t, app.toggleCurrentPageFavoriteAction(ctx))
105 assert.Len(t, favRepo.byURL, 1)
106 _, ok := favRepo.byURL["https://example.com/page"]
107 assert.True(t, ok)
108
109 require.NoError(t, app.toggleCurrentPageFavoriteAction(ctx))
110 assert.Empty(t, favRepo.byURL)
111}
112
113func TestApp_ToggleCurrentPageFavoriteErrorCases(t *testing.T) {
114 ctx := context.Background()
115 require.ErrorContains(t, (&App{}).toggleCurrentPageFavoriteAction(ctx), "usecase not configured")
116
117 app := &App{deps: &Dependencies{FavoritesUC: usecase.NewManageFavoritesUseCase(newMemoryFavoriteRepo(), &memoryTagRepo{})}}
118 require.ErrorContains(t, app.toggleCurrentPageFavoriteAction(ctx), "no active webview")
119
120 tab := entity.NewTab(entity.TabID("tab-1"), entity.WorkspaceID("ws-1"), entity.NewPane(entity.PaneID("pane-1")))
121 tabs := entity.NewTabList()
122 tabs.Add(tab)
123 tabs.SetActive(tab.ID)
124 bw := &browserWindow{id: "w", tabs: tabs}
125 contentCoord := contentcoord.NewCoordinator(ctx, nil, nil, nil, nil, nil, nil, nil)
126 contentCoord.RegisterPopupWebView(entity.PaneID("pane-1"), &recordingWebView{id: 2})
127 app = &App{
128 deps: &Dependencies{FavoritesUC: usecase.NewManageFavoritesUseCase(newMemoryFavoriteRepo(), &memoryTagRepo{})},
129 browserWindows: map[string]*browserWindow{bw.id: bw},
130 lastFocusedWindowID: bw.id,
131 contentCoord: contentCoord,
132 workspaceViews: map[entity.TabID]*component.WorkspaceView{tab.ID: {}},
133 }
134 assert.ErrorContains(t, app.toggleCurrentPageFavoriteAction(ctx), "active page has no URI")
135}
136
137type memoryFavoriteRepo struct {
138 nextID entity.FavoriteID
139 byID map[entity.FavoriteID]*entity.Favorite
140 byURL map[string]*entity.Favorite
141 err error
142}
143
144func newMemoryFavoriteRepo() *memoryFavoriteRepo {
145 return &memoryFavoriteRepo{nextID: 1, byID: map[entity.FavoriteID]*entity.Favorite{}, byURL: map[string]*entity.Favorite{}}
146}
147
148func (r *memoryFavoriteRepo) Save(_ context.Context, fav *entity.Favorite) error {
149 if r.err != nil {
150 return r.err
151 }
152 if fav.ID == 0 {
153 fav.ID = r.nextID
154 r.nextID++
155 }
156 cp := *fav
157 r.byID[fav.ID] = &cp
158 r.byURL[fav.URL] = &cp
159 return nil
160}
161func (r *memoryFavoriteRepo) FindByID(context.Context, entity.FavoriteID) (*entity.Favorite, error) {
162 return nil, r.err
163}
164func (r *memoryFavoriteRepo) FindByURL(_ context.Context, url string) (*entity.Favorite, error) {
165 return r.byURL[url], r.err
166}
167func (r *memoryFavoriteRepo) GetAll(context.Context) ([]*entity.Favorite, error) { return nil, r.err }
168func (r *memoryFavoriteRepo) GetByTag(context.Context, entity.TagID) ([]*entity.Favorite, error) {
169 return nil, r.err
170}
171func (r *memoryFavoriteRepo) GetByShortcut(context.Context, int) (*entity.Favorite, error) {
172 return nil, r.err
173}
174func (r *memoryFavoriteRepo) UpdatePosition(context.Context, entity.FavoriteID, int) error {
175 return r.err
176}
177func (r *memoryFavoriteRepo) SetShortcut(context.Context, entity.FavoriteID, *int) error {
178 return r.err
179}
180func (r *memoryFavoriteRepo) Delete(_ context.Context, id entity.FavoriteID) error {
181 if r.err != nil {
182 return r.err
183 }
184 fav := r.byID[id]
185 if fav == nil {
186 return errors.New("favorite not found")
187 }
188 delete(r.byID, id)
189 delete(r.byURL, fav.URL)
190 return nil
191}
192
193type memoryTagRepo struct{}
194
195func (*memoryTagRepo) Save(context.Context, *entity.Tag) error { return nil }
196func (*memoryTagRepo) FindByID(context.Context, entity.TagID) (*entity.Tag, error) { return nil, nil }
197func (*memoryTagRepo) FindByName(context.Context, string) (*entity.Tag, error) { return nil, nil }
198func (*memoryTagRepo) GetAll(context.Context) ([]*entity.Tag, error) { return nil, nil }
199func (*memoryTagRepo) AssignToFavorite(context.Context, entity.TagID, entity.FavoriteID) error {
200 return nil
201}
202func (*memoryTagRepo) RemoveFromFavorite(context.Context, entity.TagID, entity.FavoriteID) error {
203 return nil
204}
205func (*memoryTagRepo) GetForFavorite(context.Context, entity.FavoriteID) ([]*entity.Tag, error) {
206 return nil, nil
207}
208func (*memoryTagRepo) Delete(context.Context, entity.TagID) error { return nil }