1package component
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/stretchr/testify/assert"
8
9 "github.com/bnema/dumber/internal/application/port"
10)
11
12func TestJSDialogOriginLabel(t *testing.T) {
13 assert.Equal(t, "example.com", jsDialogOriginLabel("https://example.com/a?b=c"))
14 assert.Equal(t, "example.com:8080", jsDialogOriginLabel("http://example.com:8080/"))
15 assert.Equal(t, "This page", jsDialogOriginLabel(""))
16 assert.Equal(t, "This page", jsDialogOriginLabel("not a url"))
17 assert.Equal(t, "file:", jsDialogOriginLabel("file:///tmp/x.html"))
18 long := jsDialogOriginLabel("https://" + strings.Repeat("a", 500) + ".example.com/")
19 assert.LessOrEqual(t, len([]rune(long)), jsDialogMaxHostChars+1)
20}
21
22func TestJSDialogOriginLabelOpaqueSchemes(t *testing.T) {
23 cases := map[string]string{
24 "blob:https://example.com/3f1c-uuid": "example.com",
25 "blob:http://sub.example.com:8080/uuid": "sub.example.com:8080",
26 "filesystem:https://example.com/temporary/file.txt": "example.com",
27 "blob:null/uuid": "blob:",
28 "blob:": "blob:",
29 "data:text/html,<b>x</b>": "data:",
30 "javascript:alert(1)": "javascript:",
31 }
32 for in, want := range cases {
33 assert.Equal(t, want, jsDialogOriginLabel(in), in)
34 }
35}
36
37func TestJSDialogOriginLabelKeepsRegistrableDomain(t *testing.T) {
38 // A long attacker-controlled prefix must not push the real domain out.
39 label := jsDialogOriginLabel("https://" + strings.Repeat("paypal.com.", 20) + "evil.test/")
40 assert.True(t, strings.HasPrefix(label, "…"))
41 assert.True(t, strings.HasSuffix(label, "evil.test"))
42}
43
44func TestBuildJSDialogContentCapsPageText(t *testing.T) {
45 huge := strings.Repeat("x", jsDialogMaxTextRunes*3)
46 c := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogAlert, Message: huge})
47 assert.LessOrEqual(t, len([]rune(c.Body)), jsDialogMaxTextRunes+1)
48}
49
50func TestBuildJSDialogContentBeforeUnloadUsesFixedText(t *testing.T) {
51 c := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogBeforeUnload, Origin: "https://example.com", Message: "page text"})
52 assert.Contains(t, c.Body, jsDialogBeforeUnloadText)
53 assert.NotContains(t, c.Body, "page text")
54}
55
56func TestBuildJSDialogContent(t *testing.T) {
57 origin := "https://example.com/x"
58
59 alert := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogAlert, Origin: origin, Message: "<b>hi</b>"})
60 assert.Equal(t, "example.com says:", alert.Heading)
61 assert.Equal(t, "<b>hi</b>", alert.Body, "message must stay plain text")
62 assert.Equal(t, "OK", alert.OKLabel)
63 assert.Empty(t, alert.CancelLabel)
64 assert.False(t, alert.ShowInput)
65
66 confirm := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogConfirm, Origin: origin})
67 assert.Equal(t, "Cancel", confirm.CancelLabel)
68 assert.False(t, confirm.ShowInput)
69
70 prompt := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogPrompt, Origin: origin})
71 assert.True(t, prompt.ShowInput)
72 assert.Equal(t, "Cancel", prompt.CancelLabel)
73
74 leave := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogBeforeUnload, Origin: origin})
75 assert.Equal(t, "Leave page?", leave.Heading)
76 assert.Equal(t, "Leave", leave.OKLabel)
77 assert.Equal(t, "Stay", leave.CancelLabel)
78 assert.Contains(t, leave.Body, "example.com")
79
80 reload := buildJSDialogContent(port.JSDialogRequest{Type: port.JSDialogBeforeUnload, Origin: origin, IsReload: true, Message: "x"})
81 assert.Equal(t, "Reload page?", reload.Heading)
82}