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