runtime_config_test.go RawHistoryFolder

1package ui
2
3import (
4	"context"
5	"testing"
6
7	"github.com/stretchr/testify/mock"
8
9	"github.com/bnema/dumber/internal/application/dto"
10	"github.com/bnema/dumber/internal/application/port"
11	portmocks "github.com/bnema/dumber/internal/application/port/mocks"
12	"github.com/bnema/dumber/internal/domain/entity"
13	"github.com/bnema/dumber/internal/shared/syncdispatch"
14	"github.com/bnema/dumber/internal/ui/coordinator/content"
15)
16
17func TestDependenciesValidateAcceptsRuntimeConfigOnly(t *testing.T) {
18	runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)
19	engine := portmocks.NewMockEngine(t)
20	deps := &Dependencies{
21		Ctx:           context.Background(),
22		RuntimeConfig: runtimeConfig,
23		Engine:        engine,
24		HandlerDeps: port.HandlerDeps{
25			SaveConfig: func(context.Context, dto.WebUIConfig) error {
26				return nil
27			},
28			SaveOmniboxInitialBehavior: func(context.Context, entity.OmniboxInitialBehavior) error {
29				return nil
30			},
31		},
32	}
33
34	if err := deps.Validate(); err != nil {
35		t.Fatalf("Validate() error = %v, want nil", err)
36	}
37}
38
39func TestAppRuntimeConfigReturnsProviderSnapshot(t *testing.T) {
40	provider := portmocks.NewMockRuntimeConfigProvider(t)
41	provider.EXPECT().
42		Current().
43		Return(entity.RuntimeConfigSnapshot{
44			UI: entity.RuntimeUIConfig{DefaultUIScale: 1.6},
45		}).
46		Once()
47	app := &App{deps: &Dependencies{RuntimeConfig: provider}}
48
49	got := app.runtimeConfigSnapshot()
50
51	if got.UI.DefaultUIScale != 1.6 {
52		t.Fatalf("DefaultUIScale=%v, want 1.6", got.UI.DefaultUIScale)
53	}
54}
55
56func TestAppRuntimeConfigStateStoresLatestSnapshot(t *testing.T) {
57	app := &App{}
58	setRuntimeConfigSnapshotForTest(app, entity.RuntimeConfigSnapshot{
59		UI: entity.RuntimeUIConfig{SidebarWidth: 340},
60	})
61
62	got := app.runtimeConfigSnapshot()
63	if got.UI.SidebarWidth != 340 {
64		t.Fatalf("SidebarWidth=%d, want 340", got.UI.SidebarWidth)
65	}
66}
67
68func TestConfigWatcherOnChangeUpdatesRuntimeConfigState(t *testing.T) {
69	ctx := context.Background()
70	provider := portmocks.NewMockRuntimeConfigProvider(t)
71	provider.EXPECT().Watch().Return(nil).Once()
72	var onChange func(entity.RuntimeConfigSnapshot)
73	provider.EXPECT().
74		OnChange(mock.Anything).
75		Run(func(fn func(entity.RuntimeConfigSnapshot)) {
76			onChange = fn
77		}).
78		Once()
79
80	initial := entity.RuntimeConfigSnapshot{
81		UI: entity.RuntimeUIConfig{
82			Workspace: entity.WorkspaceConfig{
83				BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: true},
84			},
85		},
86	}
87	app := &App{
88		deps:           &Dependencies{RuntimeConfig: provider},
89		runtimeConfig:  runtimeConfigStateFromSnapshotForTest(initial),
90		contentCoord:   &content.Coordinator{},
91		browserWindows: map[string]*browserWindow{},
92		dispatchOnMainThread: func(label string, fn func()) syncdispatch.SyncDispatchResult {
93			if label != "ui.runtime_config_reload" {
94				t.Fatalf("dispatch label=%q, want ui.runtime_config_reload", label)
95			}
96			fn()
97			return syncdispatch.SyncDispatchResult{Label: label, Status: syncdispatch.SyncDispatchCompleted}
98		},
99	}
100	app.contentCoord.SetPopupConfig(nil, &initial.UI.Workspace.BrowsingContexts, nil)
101
102	app.initConfigWatcher(ctx)
103	if onChange == nil {
104		t.Fatal("runtime config OnChange callback was not registered")
105	}
106
107	onChange(entity.RuntimeConfigSnapshot{
108		UI: entity.RuntimeUIConfig{
109			SidebarWidth: 360,
110			Workspace: entity.WorkspaceConfig{
111				BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: false, OAuthAutoClose: true},
112			},
113		},
114	})
115
116	got := app.runtimeConfigSnapshot()
117	if got.UI.SidebarWidth != 360 {
118		t.Fatalf("SidebarWidth=%d, want 360", got.UI.SidebarWidth)
119	}
120	if got.UI.Workspace.BrowsingContexts.OpenInNewPane {
121		t.Fatal("runtime config state did not observe updated popup OpenInNewPane")
122	}
123	if !got.UI.Workspace.BrowsingContexts.OAuthAutoClose {
124		t.Fatal("runtime config state did not observe updated popup OAuthAutoClose")
125	}
126}

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