detached 5041353

semantic_navigation_test.go RawHistoryFolder

1package cef
2
3import (
4	"context"
5	"testing"
6
7	purecef "github.com/bnema/purego-cef/cef"
8	cefmocks "github.com/bnema/purego-cef/cef/mocks"
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/mock"
11	"github.com/stretchr/testify/require"
12
13	"github.com/bnema/dumber/internal/application/dto"
14)
15
16func TestWebViewNavigateSemantic_HeadingExecutesStrictNavigationScript(t *testing.T) {
17	browser := cefmocks.NewMockBrowser(t)
18	frame := cefmocks.NewMockFrame(t)
19	browser.EXPECT().GetMainFrame().Return(frame).Once()
20	frame.EXPECT().ExecuteJavaScript(mock.MatchedBy(mockStringContaining(t,
21		"document.querySelectorAll(\"h1,h2,h3,h4,h5,h6\")",
22		"heading.closest(\"[hidden],[inert],[aria-hidden=\\\"true\\\"]\")",
23		"window.getComputedStyle(heading)",
24		"firstAtOrAfterViewportTop",
25		"if (next < 0 || next >= headings.length) return;",
26		"previous && previous !== target",
27		"scrollIntoView",
28		"window[stateKey] = target",
29		"const highlightColor = \"#22c55e\"",
30		"const targetAttribute = \"data-dumber-vim-heading-",
31		"let style = document.querySelector(\"style[\" + styleAttribute + \"]\")",
32		"style.textContent = \"[\" + targetAttribute + \"]\"",
33		"1 * 3",
34	)), "", int32(0)).Once()
35
36	wv := &WebView{browser: browser}
37	err := wv.NavigateSemantic(context.Background(), dto.SemanticNavigationRequest{
38		Target:         dto.SemanticNavigationTargetHeading,
39		Direction:      dto.SemanticNavigationForward,
40		Count:          3,
41		HighlightColor: "#22c55e",
42	})
43	require.NoError(t, err)
44}
45
46func TestWebViewActivateSemanticNavigationTargetClicksSelectedHeadingLink(t *testing.T) {
47	browser := cefmocks.NewMockBrowser(t)
48	frame := cefmocks.NewMockFrame(t)
49	browser.EXPECT().GetMainFrame().Return(frame).Once()
50	frame.EXPECT().ExecuteJavaScript(mock.MatchedBy(mockStringContaining(t,
51		"const target = window[stateKey]",
52		"target.closest(\"a[href]\")",
53		"target.querySelector(\"a[href]\")",
54		"link.click()",
55	)), "", int32(0)).Once()
56
57	wv := &WebView{browser: browser}
58	require.NoError(t, wv.ActivateSemanticNavigationTarget(context.Background()))
59}
60
61func TestWebViewClearSemanticNavigationHighlightRemovesTargetArtifacts(t *testing.T) {
62	browser := cefmocks.NewMockBrowser(t)
63	frame := cefmocks.NewMockFrame(t)
64	browser.EXPECT().GetMainFrame().Return(frame).Once()
65	frame.EXPECT().ExecuteJavaScript(mock.MatchedBy(mockStringContaining(t,
66		"const targetAttribute = \"data-dumber-vim-heading-",
67		"document.querySelectorAll(\"[\" + targetAttribute + \"]\")",
68		"target.removeAttribute(targetAttribute)",
69		"style[\" + styleAttribute + \"]",
70		"delete window[stateKey]",
71	)), "", int32(0)).Once()
72
73	wv := &WebView{browser: browser}
74	require.NoError(t, wv.ClearSemanticNavigationHighlight(context.Background()))
75}
76
77func TestWebViewClearSemanticNavigationHighlightReportsSchedulingFailure(t *testing.T) {
78	oldNewTask, oldPostTask := cefNewTask, cefPostTask
79	defer func() { cefNewTask, cefPostTask = oldNewTask, oldPostTask }()
80	cefNewTask = func(task purecef.Task) purecef.Task { return task }
81	cefPostTask = func(purecef.ThreadID, purecef.Task) int32 { return 0 }
82
83	wv := &WebView{engine: &Engine{}, browser: cefmocks.NewMockBrowser(t)}
84	require.Error(t, wv.ClearSemanticNavigationHighlight(context.Background()))
85}
86
87func TestWebViewNavigateSemantic_NormalizesCountAndRejectsUnsupportedRequests(t *testing.T) {
88	forward := headingNavigationScript(1, 1, "", "test")
89	backward := headingNavigationScript(-1, 1, "#4ade80", "test")
90	assert.Contains(t, forward, "index = firstAtOrAfterViewportTop - 1")
91	assert.Contains(t, forward, "if (index < -1) index = -1;")
92	assert.Contains(t, backward, "index = firstAtOrAfterViewportTop >= 0 ? firstAtOrAfterViewportTop : headings.length")
93	assert.Contains(t, backward, "-1 * 1")
94	assert.NotContains(t, backward, "window.innerHeight")
95	assert.Contains(t, forward, "const highlightColor = \"#fbbf24\"")
96	assert.Contains(t, backward, "const highlightColor = \"#4ade80\"")
97
98	wv := &WebView{}
99	err := wv.NavigateSemantic(context.Background(), dto.SemanticNavigationRequest{
100		Target:    dto.SemanticNavigationTargetHeading,
101		Direction: dto.SemanticNavigationForward,
102		Count:     0,
103	})
104	require.NoError(t, err)
105
106	err = wv.NavigateSemantic(context.Background(), dto.SemanticNavigationRequest{
107		Target:    dto.SemanticNavigationTargetHeading + 1,
108		Direction: dto.SemanticNavigationForward,
109	})
110	require.Error(t, err)
111
112	err = wv.NavigateSemantic(context.Background(), dto.SemanticNavigationRequest{
113		Target:    dto.SemanticNavigationTargetHeading,
114		Direction: 0,
115	})
116	require.Error(t, err)
117}
118
119func mockStringContaining(t *testing.T, fragments ...string) func(string) bool {
120	t.Helper()
121	return func(script string) bool {
122		for _, fragment := range fragments {
123			if !assert.Contains(t, script, fragment) {
124				return false
125			}
126		}
127		return true
128	}
129}

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