@@ -115,6 +115,42 @@ async function submitForm(container: Locator) {
115115 await container . locator ( ".form-expanded-content" ) . getByRole ( "button" ) . click ( ) ;
116116}
117117
118+ async function isFocusInsideFeedbackDialog ( page : Page ) {
119+ return await page . evaluate ( ( containerElementId ) => {
120+ const container = document . querySelector ( `#${ containerElementId } ` ) ;
121+
122+ if ( ! container || ! container . shadowRoot ) return false ;
123+
124+ let activeElement : Element | null = document . activeElement ;
125+ while ( activeElement instanceof HTMLElement && activeElement . shadowRoot ) {
126+ const shadowActiveElement = activeElement . shadowRoot . activeElement ;
127+ if ( ! shadowActiveElement ) break ;
128+ activeElement = shadowActiveElement ;
129+ }
130+
131+ return activeElement ? container . shadowRoot . contains ( activeElement ) : false ;
132+ } , feedbackContainerId ) ;
133+ }
134+
135+ async function isFeedbackDialogOpen ( page : Page ) {
136+ return await page . evaluate ( ( containerElementId ) => {
137+ const container = document . querySelector ( `#${ containerElementId } ` ) ;
138+ const dialog = container ?. shadowRoot ?. querySelector ( ".dialog" ) ;
139+ if ( ! dialog ) return false ;
140+
141+ const modalOpen = dialog . hasAttribute ( "open" ) ;
142+ let popoverOpen = false ;
143+
144+ try {
145+ popoverOpen = dialog . matches ( ":popover-open" ) ;
146+ } catch {
147+ popoverOpen = false ;
148+ }
149+
150+ return modalOpen || popoverOpen ;
151+ } , feedbackContainerId ) ;
152+ }
153+
118154test . beforeEach ( async ( { page, browserName } ) => {
119155 // Log any calls to front.reflag.com which aren't mocked by subsequent
120156 // `page.route` calls. With page.route, the last matching mock takes
@@ -142,7 +178,7 @@ test("Opens a feedback widget", async ({ page }) => {
142178 const container = await getOpenedWidgetContainer ( page ) ;
143179
144180 await expect ( container ) . toBeAttached ( ) ;
145- await expect ( container . locator ( "dialog" ) ) . toHaveAttribute ( "open" , "" ) ;
181+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( true ) ;
146182} ) ;
147183
148184test ( "Opens a feedback widget multiple times in same session" , async ( {
@@ -152,14 +188,54 @@ test("Opens a feedback widget multiple times in same session", async ({
152188
153189 await page . getByTestId ( "give-feedback-button" ) . click ( ) ;
154190 await expect ( container ) . toBeAttached ( ) ;
155- await expect ( container . locator ( "dialog" ) ) . toHaveAttribute ( "open" , "" ) ;
191+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( true ) ;
156192
157- await container . locator ( "dialog .close" ) . click ( ) ;
158- await expect ( container . locator ( "dialog" ) ) . not . toHaveAttribute ( "open" , "" ) ;
193+ await container . locator ( ". dialog .close" ) . click ( ) ;
194+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( false ) ;
159195
160196 await page . getByTestId ( "give-feedback-button" ) . click ( ) ;
161197 await expect ( container ) . toBeAttached ( ) ;
162- await expect ( container . locator ( "dialog" ) ) . toHaveAttribute ( "open" , "" ) ;
198+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( true ) ;
199+ } ) ;
200+
201+ test ( "Does not steal focus in DIALOG mode" , async ( { page } ) => {
202+ await getGiveFeedbackPageContainer ( page , {
203+ feedback : {
204+ ui : {
205+ position : {
206+ type : "DIALOG" ,
207+ placement : "bottom-right" ,
208+ } ,
209+ } ,
210+ } ,
211+ } ) ;
212+
213+ await page . getByTestId ( "give-feedback-button" ) . focus ( ) ;
214+ await expect ( page . getByTestId ( "give-feedback-button" ) ) . toBeFocused ( ) ;
215+
216+ await page . getByTestId ( "give-feedback-button" ) . click ( ) ;
217+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( true ) ;
218+ await expect . poll ( ( ) => isFocusInsideFeedbackDialog ( page ) ) . toBe ( false ) ;
219+ } ) ;
220+
221+ test ( "Steals focus in MODAL mode" , async ( { page } ) => {
222+ await getGiveFeedbackPageContainer ( page , {
223+ feedback : {
224+ ui : {
225+ position : {
226+ type : "MODAL" ,
227+ } ,
228+ } ,
229+ } ,
230+ } ) ;
231+
232+ await page . getByTestId ( "give-feedback-button" ) . focus ( ) ;
233+ await expect ( page . getByTestId ( "give-feedback-button" ) ) . toBeFocused ( ) ;
234+
235+ await page . getByTestId ( "give-feedback-button" ) . click ( ) ;
236+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( true ) ;
237+ await expect ( page . getByTestId ( "give-feedback-button" ) ) . not . toBeFocused ( ) ;
238+ await expect . poll ( ( ) => isFocusInsideFeedbackDialog ( page ) ) . toBe ( true ) ;
163239} ) ;
164240
165241test ( "Opens a feedback widget in the bottom right by default" , async ( {
@@ -169,7 +245,7 @@ test("Opens a feedback widget in the bottom right by default", async ({
169245
170246 await expect ( container ) . toBeAttached ( ) ;
171247
172- const bbox = await container . locator ( "dialog" ) . boundingBox ( ) ;
248+ const bbox = await container . locator ( ". dialog" ) . boundingBox ( ) ;
173249 expect ( bbox ?. x ) . toEqual ( WINDOW_WIDTH - bbox ! . width - 16 ) ;
174250 expect ( bbox ?. y ) . toBeGreaterThan ( WINDOW_HEIGHT - bbox ! . height - 30 ) ; // Account for browser differences
175251 expect ( bbox ?. y ) . toBeLessThan ( WINDOW_HEIGHT - bbox ! . height ) ;
@@ -191,7 +267,7 @@ test("Opens a feedback widget in the correct position when overridden", async ({
191267
192268 await expect ( container ) . toBeAttached ( ) ;
193269
194- const bbox = await container . locator ( "dialog" ) . boundingBox ( ) ;
270+ const bbox = await container . locator ( ". dialog" ) . boundingBox ( ) ;
195271 expect ( bbox ?. x ) . toEqual ( 16 ) ;
196272 expect ( bbox ?. y ) . toBeGreaterThan ( 0 ) ; // Account for browser differences
197273 expect ( bbox ?. y ) . toBeLessThanOrEqual ( 16 ) ;
@@ -411,7 +487,7 @@ test("Closes the dialog shortly after submitting", async ({ page }) => {
411487 await setComment ( container , "Test comment!" ) ;
412488 await submitForm ( container ) ;
413489
414- await expect ( container . locator ( "dialog" ) ) . not . toHaveAttribute ( "open" , "" ) ;
490+ await expect . poll ( ( ) => isFeedbackDialogOpen ( page ) ) . toBe ( false ) ;
415491} ) ;
416492
417493test ( "Blocks event propagation to the containing document" , async ( {
0 commit comments