v0.31.0 bf0756b

browser_transport_test.go RawHistoryFolder

1package systemviewsbridge
2
3import (
4	"bytes"
5	"encoding/json"
6	"testing"
7)
8
9func TestDecodeBrowserRequest_DirectConfigEndpoint(t *testing.T) {
10	t.Parallel()
11
12	body, err := buildMessageEnvelope("/api/config", struct {
13		RequestID string `json:"requestId"`
14	}{RequestID: "req-1"})
15	if err != nil {
16		t.Fatalf("buildMessageEnvelope() error = %v", err)
17	}
18
19	req, err := decodeBrowserRequest(body)
20	if err != nil {
21		t.Fatalf("decodeBrowserRequest() error = %v", err)
22	}
23	if req.messageType != "/api/config" {
24		t.Fatalf("messageType = %q, want %q", req.messageType, "/api/config")
25	}
26	if req.requestID != "req-1" {
27		t.Fatalf("requestID = %q, want %q", req.requestID, "req-1")
28	}
29	if !req.directAPI {
30		t.Fatal("directAPI = false, want true")
31	}
32}
33
34func TestDecodeBrowserRequest_MessageEnvelopeUsesBridgeShim(t *testing.T) {
35	t.Parallel()
36
37	body, err := buildMessageEnvelope("history_timeline", struct {
38		RequestID string `json:"requestId"`
39		Limit     int    `json:"limit"`
40	}{RequestID: "req-2", Limit: 25})
41	if err != nil {
42		t.Fatalf("buildMessageEnvelope() error = %v", err)
43	}
44
45	req, err := decodeBrowserRequest(body)
46	if err != nil {
47		t.Fatalf("decodeBrowserRequest() error = %v", err)
48	}
49	if req.messageType != "history_timeline" {
50		t.Fatalf("messageType = %q, want %q", req.messageType, "history_timeline")
51	}
52	if req.requestID != "req-2" {
53		t.Fatalf("requestID = %q, want %q", req.requestID, "req-2")
54	}
55	if req.directAPI {
56		t.Fatal("directAPI = true, want false")
57	}
58	if !bytes.Equal(req.body, body) {
59		t.Fatalf("body = %s, want %s", req.body, body)
60	}
61}
62
63func TestNormalizeBridgeShimResponse_UnwrapsNestedBridgeEnvelope(t *testing.T) {
64	t.Parallel()
65
66	got, err := normalizeBridgeShimResponse("req-3", []byte(`{"data":{"requestId":"req-3","success":true,"data":[{"title":"Example"}]},"_callback":"__dumber_homepage_response"}`))
67	if err != nil {
68		t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
69	}
70
71	var resp bridgeResponse
72	if err := json.Unmarshal(got, &resp); err != nil {
73		t.Fatalf("json.Unmarshal() error = %v", err)
74	}
75	if !resp.Success {
76		t.Fatal("success = false, want true")
77	}
78	if resp.RequestID != "req-3" {
79		t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-3")
80	}
81	if string(resp.Data) != `[{"title":"Example"}]` {
82		t.Fatalf("data = %s, want %s", resp.Data, `[{"title":"Example"}]`)
83	}
84}
85
86func TestNormalizeBridgeShimResponse_DoesNotTreatRequestIDDataAsEnvelope(t *testing.T) {
87	t.Parallel()
88
89	got, err := normalizeBridgeShimResponse("req-raw", []byte(`{"data":{"requestId":"external-id","title":"Example"},"_callback":"__dumber_homepage_response"}`))
90	if err != nil {
91		t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
92	}
93
94	var resp bridgeResponse
95	if err := json.Unmarshal(got, &resp); err != nil {
96		t.Fatalf("json.Unmarshal() error = %v", err)
97	}
98	if string(resp.Data) != `{"requestId":"external-id","title":"Example"}` {
99		t.Fatalf("data = %s, want raw payload", resp.Data)
100	}
101}
102
103func TestNormalizeBridgeShimResponse_DoesNotTreatNonBooleanSuccessDataAsEnvelope(t *testing.T) {
104	t.Parallel()
105
106	got, err := normalizeBridgeShimResponse("req-raw-success", []byte(`{"data":{"success":"yes","title":"Example"},"_callback":"__dumber_homepage_response"}`))
107	if err != nil {
108		t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
109	}
110
111	var resp bridgeResponse
112	if err := json.Unmarshal(got, &resp); err != nil {
113		t.Fatalf("json.Unmarshal() error = %v", err)
114	}
115	if string(resp.Data) != `{"success":"yes","title":"Example"}` {
116		t.Fatalf("data = %s, want raw payload", resp.Data)
117	}
118}
119
120func TestNormalizeBridgeShimResponse_WrapsRawCallbackPayload(t *testing.T) {
121	t.Parallel()
122
123	got, err := normalizeBridgeShimResponse("req-4", []byte(`{"data":{"status":"success"},"_callback":"__dumber_config_saved"}`))
124	if err != nil {
125		t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
126	}
127
128	var resp bridgeResponse
129	if err := json.Unmarshal(got, &resp); err != nil {
130		t.Fatalf("json.Unmarshal() error = %v", err)
131	}
132	if !resp.Success {
133		t.Fatal("success = false, want true")
134	}
135	if resp.RequestID != "req-4" {
136		t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-4")
137	}
138	if string(resp.Data) != `{"status":"success"}` {
139		t.Fatalf("data = %s, want %s", resp.Data, `{"status":"success"}`)
140	}
141}
142
143func TestNormalizeBridgeShimResponse_WrapsTopLevelErrorWithoutData(t *testing.T) {
144	t.Parallel()
145
146	got, err := normalizeBridgeShimResponse("req-error", []byte(`{"error":"bridge failed"}`))
147	if err != nil {
148		t.Fatalf("normalizeBridgeShimResponse() error = %v", err)
149	}
150
151	var resp bridgeResponse
152	if err := json.Unmarshal(got, &resp); err != nil {
153		t.Fatalf("json.Unmarshal() error = %v", err)
154	}
155	if resp.RequestID != "req-error" {
156		t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-error")
157	}
158	if resp.Error != "bridge failed" {
159		t.Fatalf("error = %q, want %q", resp.Error, "bridge failed")
160	}
161}
162
163func TestNormalizeBridgeShimResponse_RejectsMalformedJSON(t *testing.T) {
164	t.Parallel()
165
166	if _, err := normalizeBridgeShimResponse("req-bad", []byte(`{"data":`)); err == nil {
167		t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
168	}
169}
170
171func TestNormalizeBridgeShimResponse_RejectsMissingData(t *testing.T) {
172	t.Parallel()
173
174	if _, err := normalizeBridgeShimResponse("req-missing", []byte(`{"_callback":"__dumber_config_saved"}`)); err == nil {
175		t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
176	}
177}
178
179func TestNormalizeBridgeShimResponse_RejectsEmptyBody(t *testing.T) {
180	t.Parallel()
181
182	if _, err := normalizeBridgeShimResponse("req-empty", nil); err == nil {
183		t.Fatal("normalizeBridgeShimResponse() error = nil, want error")
184	}
185}
186
187func TestWrapDirectAPIResponse_PreservesPayload(t *testing.T) {
188	t.Parallel()
189
190	got, err := wrapDirectAPIResponse("req-5", []byte(`{"engine_type":"webkit"}`))
191	if err != nil {
192		t.Fatalf("wrapDirectAPIResponse() error = %v", err)
193	}
194
195	var resp bridgeResponse
196	if err := json.Unmarshal(got, &resp); err != nil {
197		t.Fatalf("json.Unmarshal() error = %v", err)
198	}
199	if !resp.Success {
200		t.Fatal("success = false, want true")
201	}
202	if resp.RequestID != "req-5" {
203		t.Fatalf("requestId = %q, want %q", resp.RequestID, "req-5")
204	}
205	if string(resp.Data) != `{"engine_type":"webkit"}` {
206		t.Fatalf("data = %s, want %s", resp.Data, `{"engine_type":"webkit"}`)
207	}
208}

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