v0.31.0 bf0756b

popup_opener_renderer_test.go RawHistoryFolder

1package cef
2
3import (
4	"testing"
5	"unsafe"
6
7	purecef "github.com/bnema/purego-cef/cef"
8	cefmocks "github.com/bnema/purego-cef/cef/mocks"
9	"github.com/stretchr/testify/require"
10)
11
12type testPopupOpenerDictionaryValue struct {
13	strings map[string]string
14	bools   map[string]int32
15}
16
17func (v testPopupOpenerDictionaryValue) IsValid() bool                        { return true }
18func (v testPopupOpenerDictionaryValue) IsOwned() bool                        { return true }
19func (v testPopupOpenerDictionaryValue) IsReadOnly() bool                     { return false }
20func (v testPopupOpenerDictionaryValue) IsSame(purecef.DictionaryValue) bool  { return false }
21func (v testPopupOpenerDictionaryValue) IsEqual(purecef.DictionaryValue) bool { return false }
22func (v testPopupOpenerDictionaryValue) Copy(int32) purecef.DictionaryValue   { return v }
23func (v testPopupOpenerDictionaryValue) GetSize() int                         { return len(v.strings) + len(v.bools) }
24func (v testPopupOpenerDictionaryValue) Clear() int32                         { return 1 }
25func (v testPopupOpenerDictionaryValue) HasKey(key string) bool {
26	_, ok := v.strings[key]
27	if ok {
28		return true
29	}
30	_, ok = v.bools[key]
31	return ok
32}
33func (v testPopupOpenerDictionaryValue) GetKeys(purecef.StringList) int32             { return 0 }
34func (v testPopupOpenerDictionaryValue) Remove(string) int32                          { return 1 }
35func (v testPopupOpenerDictionaryValue) GetType(string) purecef.ValueType             { return 0 }
36func (v testPopupOpenerDictionaryValue) GetValue(string) purecef.Value                { return nil }
37func (v testPopupOpenerDictionaryValue) GetBool(key string) int32                     { return v.bools[key] }
38func (v testPopupOpenerDictionaryValue) GetInt(string) int32                          { return 0 }
39func (v testPopupOpenerDictionaryValue) GetDouble(string) float64                     { return 0 }
40func (v testPopupOpenerDictionaryValue) GetString(key string) string                  { return v.strings[key] }
41func (v testPopupOpenerDictionaryValue) GetBinary(string) purecef.BinaryValue         { return nil }
42func (v testPopupOpenerDictionaryValue) GetDictionary(string) purecef.DictionaryValue { return nil }
43func (v testPopupOpenerDictionaryValue) GetList(string) purecef.ListValue             { return nil }
44func (v testPopupOpenerDictionaryValue) SetValue(string, purecef.Value) int32         { return 1 }
45func (v testPopupOpenerDictionaryValue) SetNull(string) int32                         { return 1 }
46func (v testPopupOpenerDictionaryValue) SetBool(string, int32) int32                  { return 1 }
47func (v testPopupOpenerDictionaryValue) SetInt(string, int32) int32                   { return 1 }
48func (v testPopupOpenerDictionaryValue) SetDouble(string, float64) int32              { return 1 }
49func (v testPopupOpenerDictionaryValue) SetString(string, string) int32               { return 1 }
50func (v testPopupOpenerDictionaryValue) SetBinary(string, purecef.BinaryValue) int32  { return 1 }
51func (v testPopupOpenerDictionaryValue) SetDictionary(string, purecef.DictionaryValue) int32 {
52	return 1
53}
54func (v testPopupOpenerDictionaryValue) SetList(string, purecef.ListValue) int32 { return 1 }
55
56type testPopupOpenerV8Context struct {
57	valid      bool
58	evalCode   string
59	evalURL    string
60	enterCalls int
61	exitCalls  int
62}
63
64func (c *testPopupOpenerV8Context) GetTaskRunner() purecef.TaskRunner { return nil }
65func (c *testPopupOpenerV8Context) IsValid() bool                     { return c.valid }
66func (c *testPopupOpenerV8Context) GetBrowser() purecef.Browser       { return nil }
67func (c *testPopupOpenerV8Context) GetFrame() purecef.Frame           { return nil }
68func (c *testPopupOpenerV8Context) GetGlobal() purecef.V8Value        { return nil }
69func (c *testPopupOpenerV8Context) Enter() int32 {
70	c.enterCalls++
71	return 1
72}
73func (c *testPopupOpenerV8Context) Exit() int32 {
74	c.exitCalls++
75	return 1
76}
77func (c *testPopupOpenerV8Context) IsSame(that purecef.V8Context) bool { return c == that }
78func (c *testPopupOpenerV8Context) Eval(code, scriptURL string, _ int32, _, _ unsafe.Pointer) int32 {
79	c.evalCode = code
80	c.evalURL = scriptURL
81	return 1
82}
83func (c *testPopupOpenerV8Context) RawPointer() unsafe.Pointer { return nil }
84func (c *testPopupOpenerV8Context) Release()                   {}
85
86func TestDecodePopupOpenerRenderMetadata(t *testing.T) {
87	metadata, ok := decodePopupOpenerRenderMetadata(testPopupOpenerDictionaryValue{
88		strings: map[string]string{
89			popupOpenerExtraInfoParentURIKey:   "https://example.com/login",
90			popupOpenerExtraInfoBridgeNonceKey: "bridge-nonce",
91		},
92		bools: map[string]int32{
93			popupOpenerExtraInfoEnabledKey: 1,
94		},
95	})
96
97	require.True(t, ok)
98	require.Equal(t, "https://example.com/login", metadata.ParentURI)
99	require.Equal(t, "bridge-nonce", metadata.BridgeNonce)
100}
101
102func TestPopupOpenerRenderProcessHandler_OnContextCreatedInstallsBridgeForConfiguredMainFrame(t *testing.T) {
103	h := newPopupOpenerRenderProcessHandler()
104	browser := cefmocks.NewMockBrowser(t)
105	browser.EXPECT().GetIdentifier().Return(int32(42)).Twice()
106	ctx := &testPopupOpenerV8Context{valid: true}
107
108	h.OnBrowserCreated(browser, testPopupOpenerDictionaryValue{
109		strings: map[string]string{
110			popupOpenerExtraInfoParentURIKey:   "https://example.com/login",
111			popupOpenerExtraInfoBridgeNonceKey: "bridge-nonce",
112		},
113		bools: map[string]int32{
114			popupOpenerExtraInfoEnabledKey: 1,
115		},
116	})
117	h.OnContextCreated(browser, stubFrame{main: true, url: "https://example.com/popup"}, ctx)
118
119	require.Equal(t, 1, ctx.enterCalls)
120	require.Equal(t, 1, ctx.exitCalls)
121	require.Contains(t, ctx.evalCode, "popup-opener-navigate")
122	require.Contains(t, ctx.evalCode, "popup-opener-post-message")
123	require.Contains(t, ctx.evalCode, "https://example.com/login")
124	require.Contains(t, ctx.evalCode, "bridge-nonce")
125	require.Equal(t, popupOpenerRenderScriptURL, ctx.evalURL)
126}
127
128func TestPopupOpenerRenderProcessHandler_OnContextCreatedSkipsWithoutMetadata(t *testing.T) {
129	h := newPopupOpenerRenderProcessHandler()
130	browser := cefmocks.NewMockBrowser(t)
131	browser.EXPECT().GetIdentifier().Return(int32(7)).Once()
132	ctx := &testPopupOpenerV8Context{valid: true}
133
134	h.OnContextCreated(browser, stubFrame{main: true, url: "https://example.com/popup"}, ctx)
135
136	require.Zero(t, ctx.enterCalls)
137	require.Empty(t, ctx.evalCode)
138}
139
140func TestEnablePopupOpenerBridge_SyncsPendingCreateExtraInfo(t *testing.T) {
141	oldBuilder := popupOpenerRenderExtraInfoBuilder
142	popupOpenerRenderExtraInfoBuilder = func(parentURI, bridgeNonce string) purecef.DictionaryValue {
143		require.Equal(t, "https://example.com/login", parentURI)
144		require.NotEmpty(t, bridgeNonce)
145		return testPopupOpenerDictionaryValue{strings: map[string]string{"ok": "1"}}
146	}
147	t.Cleanup(func() {
148		popupOpenerRenderExtraInfoBuilder = oldBuilder
149	})
150
151	parent := &WebView{}
152	parent.updateURI("https://example.com/login")
153	windowInfo := purecef.NewWindowInfo()
154	wv := &WebView{pendingCreate: &pendingBrowserCreate{windowInfo: &windowInfo}}
155
156	wv.EnablePopupOpenerBridge(parent, false)
157
158	require.NotNil(t, wv.pendingCreate.extraInfo)
159	require.NotEmpty(t, wv.bridgeNonce)
160}

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