v0.31.0 bf0756b

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 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close