main 5041353

shell_test.go RawHistoryFolder

1package systemviews
2
3import (
4	"testing"
5
6	"github.com/stretchr/testify/assert"
7)
8
9func TestRenderAppFrame_ReturnsFragment(t *testing.T) {
10	t.Parallel()
11
12	page := renderedPage{
13		route:    RouteHistory,
14		subtitle: "History",
15		body:     `<ul><li>hello</li></ul>`,
16	}
17	theme := shellTheme{RootClass: "sv-dark"}
18
19	out := renderAppFrame(page, theme)
20
21	// Must be a fragment — no full document tags.
22	assert.NotContains(t, out, "<html")
23	assert.NotContains(t, out, "<head")
24	assert.NotContains(t, out, "<body")
25
26	// Root div carries theme class.
27	assert.Contains(t, out, `class="sv-app sv-dark"`)
28
29	// Route and document title are on the root element.
30	assert.Contains(t, out, `data-route="history"`)
31	assert.Contains(t, out, `data-page-title="History"`)
32
33	// Shell wrapper present.
34	assert.Contains(t, out, `class="sv-shell"`)
35
36	// Body content passed through.
37	assert.Contains(t, out, `<ul><li>hello</li></ul>`)
38
39	// Subtitle rendered.
40	assert.Contains(t, out, "History")
41}
42
43func TestRenderAppFrame_DefaultThemeClass(t *testing.T) {
44	t.Parallel()
45
46	page := renderedPage{
47		route:    RouteFavorites,
48		subtitle: "Favorites",
49		body:     `<p>content</p>`,
50	}
51	// Empty theme — should still get sv-app with sv-dark default.
52	out := renderAppFrame(page, shellTheme{})
53
54	assert.Contains(t, out, `class="sv-app sv-dark"`)
55	assert.Contains(t, out, `data-route="favorites"`)
56	assert.Contains(t, out, `data-page-title="Favorites"`)
57}
58
59func TestRenderAppFrame_DocumentTitleUsesExplicitTitle(t *testing.T) {
60	t.Parallel()
61
62	page := renderedPage{
63		route:    RouteHistory,
64		title:    "History — 12 entries",
65		subtitle: "Recent visits",
66		body:     `<p>content</p>`,
67	}
68
69	out := renderAppFrame(page, shellTheme{})
70
71	assert.Contains(t, out, `data-page-title="History — 12 entries"`)
72	assert.Contains(t, out, "Recent visits")
73}
74
75func TestRenderAppFrame_InlineVarsApplied(t *testing.T) {
76	t.Parallel()
77
78	page := renderedPage{
79		route:    RouteConfig,
80		subtitle: "Config",
81		body:     `<p>settings</p>`,
82	}
83	theme := shellTheme{
84		RootClass:  "sv-light",
85		InlineVars: "--sv-background: #fff;",
86	}
87
88	out := renderAppFrame(page, theme)
89
90	assert.Contains(t, out, `style="--sv-background: #fff;"`)
91	assert.Contains(t, out, `class="sv-app sv-light"`)
92}
93
94func TestListHTMLWrapsRows(t *testing.T) {
95	t.Parallel()
96
97	out := listHTML(`<li class="sv-list-row">entry</li>`, "Nothing here")
98
99	assert.Contains(t, out, `class="sv-list"`)
100	assert.Contains(t, out, `class="sv-list-row"`)
101	assert.Contains(t, out, "entry")
102}
103
104func TestListHTMLEmptyState(t *testing.T) {
105	t.Parallel()
106
107	out := listHTML("", "Nothing here")
108
109	assert.Contains(t, out, `class="sv-empty"`)
110	assert.Contains(t, out, "Nothing here")
111}
112
113func TestLinkHTMLSanitizesHref(t *testing.T) {
114	t.Parallel()
115
116	out := linkHTML("javascript:alert(1)", "Bad")
117
118	assert.Contains(t, out, `class="sv-link"`)
119	assert.Contains(t, out, `href="#"`)
120	assert.Contains(t, out, "Bad")
121}
122
123func TestKVHTMLRendersPairs(t *testing.T) {
124	t.Parallel()
125
126	out := kvHTML([]kvPair{{Label: "Engine", Value: "webkit"}})
127
128	assert.Contains(t, out, `class="sv-kv"`)
129	assert.Contains(t, out, "Engine")
130	assert.Contains(t, out, "webkit")
131}
132
133func TestKVHTMLEmptySlice(t *testing.T) {
134	t.Parallel()
135
136	out := kvHTML(nil)
137
138	assert.Contains(t, out, `class="sv-empty"`)
139	assert.Contains(t, out, "No configuration details")
140}
141
142func TestKVHTMLAllEmptyRows(t *testing.T) {
143	t.Parallel()
144
145	out := kvHTML([]kvPair{{}, {Label: " ", Value: ""}})
146
147	assert.Contains(t, out, `class="sv-empty"`)
148	assert.Contains(t, out, "No configuration details")
149}
150
151func TestErrorStateHTML(t *testing.T) {
152	t.Parallel()
153
154	out := errorStateHTML("boom")
155
156	assert.Contains(t, out, `class="sv-error"`)
157	assert.Contains(t, out, `role="alert"`)
158	assert.Contains(t, out, "boom")
159}
160
161func TestSectionHTML(t *testing.T) {
162	t.Parallel()
163
164	out := sectionHTML("test-section", "Test Title", "<p>inner</p>")
165	assert.Contains(t, out, `class="sv-section test-section"`)
166	assert.Contains(t, out, "Test Title")
167	assert.Contains(t, out, "<p>inner</p>")
168}
169
170func TestEmptyStateHTML(t *testing.T) {
171	t.Parallel()
172
173	out := emptyStateHTML("Nothing here")
174	assert.Contains(t, out, `class="sv-empty"`)
175	assert.Contains(t, out, "Nothing here")
176}

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