1package dialog
2
3import (
4 "context"
5 "testing"
6
7 "github.com/bnema/dumber/internal/application/port"
8 "github.com/bnema/dumber/internal/domain/entity"
9 "github.com/stretchr/testify/assert"
10)
11
12type fakePermissionPopup struct {
13 showCalls []fakePopupShowCall
14 callback func(allowed, persistent bool)
15}
16
17type fakePopupShowCall struct {
18 heading string
19 body string
20}
21
22func (f *fakePermissionPopup) Show(
23 _ context.Context,
24 heading string,
25 body string,
26 callback func(allowed, persistent bool),
27) {
28 f.showCalls = append(f.showCalls, fakePopupShowCall{
29 heading: heading,
30 body: body,
31 })
32 f.callback = callback
33}
34
35func (f *fakePermissionPopup) Respond(allowed, persistent bool) {
36 if f.callback == nil {
37 return
38 }
39 cb := f.callback
40 f.callback = nil
41 cb(allowed, persistent)
42}
43
44func TestPermissionDialog_QueuesRequestsWhilePopupVisible(t *testing.T) {
45 popup := &fakePermissionPopup{}
46 d := &PermissionDialog{popup: popup}
47
48 var firstResult port.PermissionDialogResult
49 firstCalled := false
50 d.ShowPermissionDialog(
51 context.Background(),
52 "https://example.com",
53 []entity.PermissionType{entity.PermissionTypeMicrophone},
54 nil,
55 func(result port.PermissionDialogResult) {
56 firstCalled = true
57 firstResult = result
58 },
59 )
60
61 secondCalled := false
62 var secondResult port.PermissionDialogResult
63 d.ShowPermissionDialog(
64 context.Background(),
65 "https://example.com",
66 []entity.PermissionType{entity.PermissionTypeCamera},
67 nil,
68 func(result port.PermissionDialogResult) {
69 secondCalled = true
70 secondResult = result
71 },
72 )
73
74 if assert.Len(t, popup.showCalls, 1) {
75 assert.Equal(t, "Allow Microphone Access?", popup.showCalls[0].heading)
76 }
77 assert.False(t, firstCalled)
78 assert.False(t, secondCalled)
79
80 popup.Respond(true, false)
81 assert.True(t, firstCalled)
82 assert.Equal(t, port.PermissionDialogResult{Allowed: true, Persistent: false}, firstResult)
83
84 if assert.Len(t, popup.showCalls, 2) {
85 assert.Equal(t, "Allow Camera Access?", popup.showCalls[1].heading)
86 }
87 assert.False(t, secondCalled)
88
89 popup.Respond(false, true)
90 assert.True(t, secondCalled)
91 assert.Equal(t, port.PermissionDialogResult{Allowed: false, Persistent: true}, secondResult)
92}
93
94func TestPermissionDialog_NoPopup_DeniesRequest(t *testing.T) {
95 d := &PermissionDialog{popup: nil}
96
97 called := false
98 result := port.PermissionDialogResult{}
99 d.ShowPermissionDialog(
100 context.Background(),
101 "https://example.com",
102 []entity.PermissionType{entity.PermissionTypeMicrophone},
103 nil,
104 func(r port.PermissionDialogResult) {
105 called = true
106 result = r
107 },
108 )
109
110 assert.True(t, called)
111 assert.Equal(t, port.PermissionDialogResult{Allowed: false, Persistent: false}, result)
112}
113
114func TestPermissionDialog_BuildHeadingAndBody_DisplayCombinations(t *testing.T) {
115 d := &PermissionDialog{}
116 origin := "https://meet.example.com"
117
118 tests := []struct {
119 name string
120 permTypes []entity.PermissionType
121 expectHeading string
122 expectedAction string
123 }{
124 {
125 name: "display only",
126 permTypes: []entity.PermissionType{entity.PermissionTypeDisplay},
127 expectHeading: "Allow Screen Sharing?",
128 expectedAction: "share your screen",
129 },
130 {
131 name: "microphone and display",
132 permTypes: []entity.PermissionType{entity.PermissionTypeMicrophone, entity.PermissionTypeDisplay},
133 expectHeading: "Allow Microphone and Screen Sharing?",
134 expectedAction: "access your microphone and share your screen",
135 },
136 {
137 name: "camera and display",
138 permTypes: []entity.PermissionType{entity.PermissionTypeCamera, entity.PermissionTypeDisplay},
139 expectHeading: "Allow Camera and Screen Sharing?",
140 expectedAction: "access your camera and share your screen",
141 },
142 {
143 name: "all three",
144 permTypes: []entity.PermissionType{entity.PermissionTypeMicrophone, entity.PermissionTypeCamera, entity.PermissionTypeDisplay},
145 expectHeading: "Allow Microphone, Camera, and Screen Sharing?",
146 expectedAction: "access your microphone and camera, and share your screen",
147 },
148 {
149 name: "website data access only",
150 permTypes: []entity.PermissionType{entity.PermissionTypeWebsiteDataAccess},
151 expectHeading: "Allow Third-Party Data Access?",
152 expectedAction: "access its stored data while you browse this site",
153 },
154 }
155
156 for _, tt := range tests {
157 t.Run(tt.name, func(t *testing.T) {
158 assert.Equal(t, tt.expectHeading, d.buildHeading(tt.permTypes))
159 assert.Equal(t, origin+" wants to "+tt.expectedAction+".", d.buildBody(origin, tt.permTypes, nil))
160 })
161 }
162
163 // Test website_data_access with populated metadata (Epiphany-style rich message)
164 t.Run("website data access with both domains", func(t *testing.T) {
165 meta := entity.PermissionMetadata{
166 entity.PermissionMetadataKeyRequestingDomain: "accounts.google.com",
167 entity.PermissionMetadataKeyCurrentDomain: "shop.example.com",
168 }
169 body := d.buildBody(origin, []entity.PermissionType{entity.PermissionTypeWebsiteDataAccess}, meta)
170 assert.Equal(t, origin+" wants to allow accounts.google.com to access its data (including cookies) while you browse shop.example.com.", body)
171 })
172}