@@ -281,6 +281,86 @@ configs({ directions: ['ltr'] }).forEach(({ title, config, screenshot }) => {
281281 const popover = page . locator ( 'ion-popover' ) ;
282282 await expect ( popover ) . toHaveScreenshot ( screenshot ( `select-basic-popover-scroll-to-selected` ) ) ;
283283 } ) ;
284+
285+ test ( 'opening a popover with Enter should not immediately dismiss it' , async ( { page, skip } , testInfo ) => {
286+ // TODO (ROU-5437)
287+ skip . browser ( 'webkit' , 'Safari 16 only allows text fields and pop-up menus to be focused.' ) ;
288+
289+ testInfo . annotations . push ( {
290+ type : 'issue' ,
291+ description : 'https://github.com/ionic-team/ionic-framework/issues/30561' ,
292+ } ) ;
293+
294+ await page . setContent (
295+ `
296+ <ion-app>
297+ <ion-select aria-label="Fruit" interface="popover">
298+ <ion-select-option value="apple">Apple</ion-select-option>
299+ <ion-select-option value="banana">Banana</ion-select-option>
300+ </ion-select>
301+ </ion-app>
302+ ` ,
303+ config
304+ ) ;
305+
306+ const ionPopoverDidPresent = await page . spyOnEvent ( 'ionPopoverDidPresent' ) ;
307+ const ionPopoverDidDismiss = await page . spyOnEvent ( 'ionPopoverDidDismiss' ) ;
308+
309+ await page . locator ( 'ion-select button' ) . focus ( ) ;
310+ await page . keyboard . press ( 'Enter' ) ;
311+ await ionPopoverDidPresent . next ( ) ;
312+
313+ const popover = page . locator ( 'ion-popover' ) ;
314+ await expect ( popover ) . toBeVisible ( ) ;
315+
316+ await page . waitForChanges ( ) ;
317+ expect ( ionPopoverDidDismiss ) . toHaveReceivedEventTimes ( 0 ) ;
318+ await expect ( popover ) . toBeVisible ( ) ;
319+ } ) ;
320+
321+ test ( 'holding Enter to open a popover should not immediately dismiss it' , async ( { page, skip } , testInfo ) => {
322+ // TODO (ROU-5437)
323+ skip . browser ( 'webkit' , 'Safari 16 only allows text fields and pop-up menus to be focused.' ) ;
324+
325+ testInfo . annotations . push ( {
326+ type : 'issue' ,
327+ description : 'https://github.com/ionic-team/ionic-framework/issues/30561' ,
328+ } ) ;
329+
330+ await page . setContent (
331+ `
332+ <ion-app>
333+ <ion-select aria-label="Fruit" interface="popover">
334+ <ion-select-option value="apple">Apple</ion-select-option>
335+ <ion-select-option value="banana">Banana</ion-select-option>
336+ </ion-select>
337+ </ion-app>
338+ ` ,
339+ config
340+ ) ;
341+
342+ const ionPopoverDidPresent = await page . spyOnEvent ( 'ionPopoverDidPresent' ) ;
343+ const ionPopoverDidDismiss = await page . spyOnEvent ( 'ionPopoverDidDismiss' ) ;
344+ const select = page . locator ( 'ion-select' ) as E2ELocator ;
345+ const ionChange = await select . spyOnEvent ( 'ionChange' ) ;
346+
347+ await page . locator ( 'ion-select button' ) . focus ( ) ;
348+ await page . keyboard . down ( 'Enter' ) ;
349+ await ionPopoverDidPresent . next ( ) ;
350+
351+ const popover = page . locator ( 'ion-popover' ) ;
352+ await expect ( popover ) . toBeVisible ( ) ;
353+
354+ // Second down('Enter') fires a repeat keydown (repeat=true),
355+ // which is the path guarded against in radio-group.
356+ await page . keyboard . down ( 'Enter' ) ;
357+ await page . keyboard . up ( 'Enter' ) ;
358+ await page . waitForChanges ( ) ;
359+
360+ expect ( ionPopoverDidDismiss ) . toHaveReceivedEventTimes ( 0 ) ;
361+ expect ( ionChange ) . toHaveReceivedEventTimes ( 0 ) ;
362+ await expect ( popover ) . toBeVisible ( ) ;
363+ } ) ;
284364 } ) ;
285365
286366 test . describe ( 'select: modal' , ( ) => {
@@ -450,6 +530,49 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
450530 expect ( ionChange ) . toHaveReceivedEventTimes ( 1 ) ;
451531 } ) ;
452532
533+ test ( 'should fire ionChange when confirming a popover value with Enter' , async ( { page, skip } , testInfo ) => {
534+ // TODO (ROU-5437)
535+ skip . browser ( 'webkit' , 'Safari 16 only allows text fields and pop-up menus to be focused.' ) ;
536+
537+ testInfo . annotations . push ( {
538+ type : 'issue' ,
539+ description : 'https://github.com/ionic-team/ionic-framework/issues/30561' ,
540+ } ) ;
541+
542+ await page . setContent (
543+ `
544+ <ion-app>
545+ <ion-select aria-label="Fruit" interface="popover">
546+ <ion-select-option value="apple">Apple</ion-select-option>
547+ <ion-select-option value="banana">Banana</ion-select-option>
548+ </ion-select>
549+ </ion-app>
550+ ` ,
551+ config
552+ ) ;
553+
554+ const ionPopoverDidPresent = await page . spyOnEvent ( 'ionPopoverDidPresent' ) ;
555+ const ionPopoverDidDismiss = await page . spyOnEvent ( 'ionPopoverDidDismiss' ) ;
556+ const select = page . locator ( 'ion-select' ) as E2ELocator ;
557+ const ionChange = await select . spyOnEvent ( 'ionChange' ) ;
558+
559+ await select . click ( ) ;
560+ await ionPopoverDidPresent . next ( ) ;
561+
562+ const popover = page . locator ( 'ion-popover' ) ;
563+ const secondRadio = popover . locator ( 'ion-radio' ) . nth ( 1 ) ;
564+
565+ await secondRadio . focus ( ) ;
566+ await page . keyboard . press ( 'Enter' ) ;
567+
568+ await ionChange . next ( ) ;
569+ await ionPopoverDidDismiss . next ( ) ;
570+
571+ expect ( ionChange ) . toHaveReceivedEventDetail ( { value : 'banana' } ) ;
572+ expect ( ionChange ) . toHaveReceivedEventTimes ( 1 ) ;
573+ await expect ( popover ) . not . toBeVisible ( ) ;
574+ } ) ;
575+
453576 test ( 'should fire ionChange when confirming a value from a popover' , async ( { page } ) => {
454577 await page . setContent (
455578 `
0 commit comments