v0.28.0 3cb3770

scheme_handler_test.go RawHistoryFolder

1package webkit
2
3import (
4	"context"
5	"net/url"
6	"testing"
7
8	"github.com/bnema/dumber/assets"
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11)
12
13func TestCrashOriginalURI(t *testing.T) {
14	assert.Equal(t, "https://example.com/path?q=1", crashOriginalURI("dumb://home/crash?url=https%3A%2F%2Fexample.com%2Fpath%3Fq%3D1"))
15	assert.Empty(t, crashOriginalURI("dumb://home/crash"))
16	assert.Empty(t, crashOriginalURI("%%%"))
17}
18
19func TestBuildCrashPageHTMLIncludesReloadTarget(t *testing.T) {
20	body := buildCrashPageHTML("https://example.com/foo?a=1&b=2")
21	assert.Contains(t, body, `data-target="https://example.com/foo?a=1&b=2"`)
22	assert.Contains(t, body, "https://example.com/foo?a=1&b=2")
23}
24
25func TestBuildCrashPageHTMLFallbackReloadWithoutTarget(t *testing.T) {
26	body := buildCrashPageHTML("")
27	assert.Contains(t, body, "window.location.reload();")
28}
29
30func TestBuildCrashPageHTMLRejectsUnsafeReloadScheme(t *testing.T) {
31	// buildCrashPageHTML receives already-sanitized input from the caller.
32	// sanitizeCrashPageOriginalURI strips unsafe schemes to "".
33	sanitized := sanitizeCrashPageOriginalURI("javascript:alert(1)")
34	assert.Empty(t, sanitized)
35	body := buildCrashPageHTML(sanitized)
36	assert.Contains(t, body, `data-target=""`)
37}
38
39func TestBuildCrashPageHTMLAllowsDumbSchemeTarget(t *testing.T) {
40	body := buildCrashPageHTML("dumb://home")
41	assert.Contains(t, body, `data-target="dumb://home"`)
42}
43
44func TestBuildCrashPageHTMLEscapesScriptBreakoutPayload(t *testing.T) {
45	payload := `https://example.com/?q=</script><script>alert(1)</script>`
46	body := buildCrashPageHTML(payload)
47	assert.NotContains(t, body, "</script><script>alert(1)</script>")
48	assert.Contains(t, body, "&lt;/script&gt;&lt;script&gt;alert(1)&lt;/script&gt;")
49}
50
51func TestRegisterDefaultsIncludesCrashHandler(t *testing.T) {
52	handler := NewDumbSchemeHandler(context.Background())
53	require.NotNil(t, handler)
54
55	handler.mu.RLock()
56	crashHandler, ok := handler.handlers["/crash"]
57	handler.mu.RUnlock()
58	require.True(t, ok)
59	require.NotNil(t, crashHandler)
60
61	resp := crashHandler.Handle(&SchemeRequest{
62		URI:    "dumb://home/crash?url=https%3A%2F%2Fexample.com",
63		Path:   "/crash",
64		Method: "GET",
65		Scheme: "dumb",
66	})
67	require.NotNil(t, resp)
68	assert.Equal(t, 200, resp.StatusCode)
69	assert.Equal(t, "text/html; charset=utf-8", resp.ContentType)
70	assert.Contains(t, string(resp.Data), "Renderer process ended")
71}
72
73func TestCrashHandlerSanitizesUnsafeURLQuery(t *testing.T) {
74	handler := NewDumbSchemeHandler(context.Background())
75	require.NotNil(t, handler)
76
77	handler.mu.RLock()
78	crashHandler, ok := handler.handlers["/crash"]
79	handler.mu.RUnlock()
80	require.True(t, ok)
81	require.NotNil(t, crashHandler)
82
83	resp := crashHandler.Handle(&SchemeRequest{
84		URI:    "dumb://home/crash?url=javascript%3Aalert(1)",
85		Path:   "/crash",
86		Method: "GET",
87		Scheme: "dumb",
88	})
89	require.NotNil(t, resp)
90	assert.Contains(t, string(resp.Data), `data-target=""`)
91}
92
93func TestHandleAsset_WebRTCRootServesInternalWebRTCTester(t *testing.T) {
94	h := NewDumbSchemeHandler(context.Background())
95	h.SetAssets(assets.WebUIAssets)
96
97	u, err := url.Parse("dumb://webrtc/")
98	require.NoError(t, err)
99
100	resp := h.handleAsset(u)
101	require.NotNil(t, resp)
102	assert.Equal(t, "text/html; charset=utf-8", resp.ContentType)
103	assert.Contains(t, string(resp.Data), "webrtc.min.js")
104}
105
106func TestHandleAsset_WebRTCOpaqueFormServesInternalWebRTCTester(t *testing.T) {
107	h := NewDumbSchemeHandler(context.Background())
108	h.SetAssets(assets.WebUIAssets)
109
110	u, err := url.Parse("dumb:webrtc")
111	require.NoError(t, err)
112
113	resp := h.handleAsset(u)
114	require.NotNil(t, resp)
115	assert.Equal(t, "text/html; charset=utf-8", resp.ContentType)
116	assert.Contains(t, string(resp.Data), "webrtc.min.js")
117}
118
119func TestHandleAsset_ConfigOpaqueFormServesConfigPage(t *testing.T) {
120	h := NewDumbSchemeHandler(context.Background())
121	h.SetAssets(assets.WebUIAssets)
122
123	u, err := url.Parse("dumb:config")
124	require.NoError(t, err)
125
126	resp := h.handleAsset(u)
127	require.NotNil(t, resp)
128	assert.Equal(t, "text/html; charset=utf-8", resp.ContentType)
129	assert.Contains(t, string(resp.Data), "config")
130}

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