main ba1e2c7

favorites_test.go RawHistoryFolder

1package homepage
2
3import (
4	"context"
5	"encoding/json"
6	"testing"
7
8	"github.com/bnema/dumber/internal/application/dto"
9	"github.com/bnema/dumber/internal/application/port"
10	portmocks "github.com/bnema/dumber/internal/application/port/mocks"
11	"github.com/bnema/dumber/internal/domain/entity"
12	"github.com/stretchr/testify/mock"
13	"github.com/stretchr/testify/require"
14)
15
16func TestHandleFavoriteCreatePassesTagsOnlyPayload(t *testing.T) {
17	t.Parallel()
18
19	favorites := portmocks.NewMockHomepageFavorites(t)
20	favorites.EXPECT().
21		AddFavorite(mock.Anything, dto.FavoriteCreateInput{
22			URL:   "https://example.com",
23			Title: "Example",
24			Tags:  []entity.TagID{7, 9},
25		}).
26		Return(&entity.Favorite{ID: 1, URL: "https://example.com", Title: "Example"}, nil).
27		Once()
28
29	handler := NewFavoritesHandlers(favorites).HandleCreate()
30	got, err := handler.Handle(context.Background(), port.WebViewID(0), json.RawMessage(`{"requestId":"req-1","url":" https://example.com ","title":"Example","tags":[7,9]}`))
31	require.NoError(t, err)
32
33	resp, ok := got.(Response)
34	require.True(t, ok)
35	require.True(t, resp.Success)
36}
37
38func TestHandleFavoriteCreateRejectsInvalidTagIDs(t *testing.T) {
39	t.Parallel()
40
41	handler := NewFavoritesHandlers(portmocks.NewMockHomepageFavorites(t)).HandleCreate()
42	got, err := handler.Handle(context.Background(), port.WebViewID(0), json.RawMessage(`{"requestId":"req-2","url":"https://example.com","tags":[0]}`))
43	require.NoError(t, err)
44
45	resp, ok := got.(Response)
46	require.True(t, ok)
47	require.False(t, resp.Success)
48	require.Contains(t, resp.Error, "tag id must be positive")
49}
50
51func TestHandleFavoriteUpdatePassesTagsOnlyPayload(t *testing.T) {
52	t.Parallel()
53
54	shortcut := 4
55	favorites := portmocks.NewMockHomepageFavorites(t)
56	favorites.EXPECT().
57		UpdateFavorite(mock.Anything, dto.FavoriteUpdateInput{
58			ID:             entity.FavoriteID(42),
59			Title:          "Updated",
60			FaviconURL:     "https://example.com/favicon.ico",
61			ShortcutKey:    &shortcut,
62			ShortcutKeySet: true,
63		}).
64		Return(&entity.Favorite{ID: 42, URL: "https://example.com", Title: "Updated", ShortcutKey: &shortcut}, nil).
65		Once()
66
67	handler := NewFavoritesHandlers(favorites).HandleUpdate()
68	got, err := handler.Handle(context.Background(), port.WebViewID(0), json.RawMessage(`{"requestId":"req-3","id":42,"title":"Updated","favicon_url":"https://example.com/favicon.ico","shortcut_key":4}`))
69	require.NoError(t, err)
70
71	resp, ok := got.(Response)
72	require.True(t, ok)
73	require.True(t, resp.Success)
74}
75func TestHandleFavoriteUpdatePreservesShortcutWhenOmitted(t *testing.T) {
76	t.Parallel()
77
78	favorites := portmocks.NewMockHomepageFavorites(t)
79	favorites.EXPECT().
80		UpdateFavorite(mock.Anything, dto.FavoriteUpdateInput{
81			ID:         entity.FavoriteID(42),
82			Title:      "Updated",
83			FaviconURL: "https://example.com/favicon.ico",
84		}).
85		Return(&entity.Favorite{ID: 42, URL: "https://example.com", Title: "Updated"}, nil).
86		Once()
87
88	handler := NewFavoritesHandlers(favorites).HandleUpdate()
89	got, err := handler.Handle(context.Background(), port.WebViewID(0), json.RawMessage(`{"requestId":"req-4","id":42,"title":"Updated","favicon_url":"https://example.com/favicon.ico"}`))
90	require.NoError(t, err)
91
92	resp, ok := got.(Response)
93	require.True(t, ok)
94	require.True(t, resp.Success)
95}
96func TestHandleFavoriteUpdateClearsShortcutWhenExplicitNull(t *testing.T) {
97	t.Parallel()
98
99	favorites := portmocks.NewMockHomepageFavorites(t)
100	favorites.EXPECT().
101		UpdateFavorite(mock.Anything, dto.FavoriteUpdateInput{
102			ID:             entity.FavoriteID(42),
103			Title:          "Updated",
104			FaviconURL:     "https://example.com/favicon.ico",
105			ShortcutKeySet: true,
106		}).
107		Return(&entity.Favorite{ID: 42, URL: "https://example.com", Title: "Updated"}, nil).
108		Once()
109
110	handler := NewFavoritesHandlers(favorites).HandleUpdate()
111	got, err := handler.Handle(context.Background(), port.WebViewID(0), json.RawMessage(`{"requestId":"req-5","id":42,"title":"Updated","favicon_url":"https://example.com/favicon.ico","shortcut_key":null}`))
112	require.NoError(t, err)
113
114	resp, ok := got.(Response)
115	require.True(t, ok)
116	require.True(t, resp.Success)
117}

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