11// Imports
22import path from 'path' ;
3-
4- // Destructured constant for readability
5- const { keyboard } = page ;
3+ import { Page } from 'puppeteer' ;
64
75// Helper functions used in multiple tests
86const currentFocusID = ( ) => page . evaluate ( ( ) => document . activeElement . id ) ;
97const menuOpen = ( ) => page . waitForSelector ( '#menu' , { visible : true } ) ;
108const menuClosed = ( ) => page . waitForSelector ( '#menu' , { hidden : true } ) ;
9+ const sleep = ( ms : number ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
10+
11+ const menuIsOpen = async ( page : Page ) =>
12+ await page . evaluate ( ( ) => {
13+ const element = document . querySelector ( '#menu' ) ;
14+ const style = getComputedStyle ( element ) ;
15+ const rect = element . getBoundingClientRect ( ) ;
16+
17+ return style . visibility !== 'hidden' && ! ! ( rect . bottom || rect . top || rect . height || rect . width ) ;
18+ } ) ;
1119
1220// Tests
1321beforeEach ( async ( ) => {
22+ await jestPuppeteer . resetPage ( ) ;
23+
1424 await page . goto ( `file://${ path . join ( __dirname , '..' , '..' , 'demo' , 'build' , 'index.html' ) } ` , {
1525 waitUntil : 'load' ,
1626 } ) ;
@@ -29,41 +39,41 @@ it('leaves focus on the button after clicking it', async () => {
2939
3040it ( 'focuses on the menu button after pressing escape' , async ( ) => {
3141 await page . focus ( '#menu-button' ) ;
32- await keyboard . down ( 'Enter' ) ;
42+ await page . keyboard . down ( 'Enter' ) ;
3343 await menuOpen ( ) ;
3444
35- await keyboard . down ( 'Escape' ) ;
45+ await page . keyboard . down ( 'Escape' ) ;
3646 await menuClosed ( ) ;
3747
3848 expect ( await currentFocusID ( ) ) . toBe ( 'menu-button' ) ;
3949} ) ;
4050
4151it ( 'focuses on the next item in the tab order after pressing tab' , async ( ) => {
4252 await page . focus ( '#menu-button' ) ;
43- await keyboard . down ( 'Enter' ) ;
53+ await page . keyboard . down ( 'Enter' ) ;
4454 await menuOpen ( ) ;
4555
46- await keyboard . down ( 'Tab' ) ;
56+ await page . keyboard . down ( 'Tab' ) ;
4757 await menuClosed ( ) ;
4858
4959 expect ( await currentFocusID ( ) ) . toBe ( 'first-footer-link' ) ;
5060} ) ;
5161
5262it ( 'focuses on the previous item in the tab order after pressing shift-tab' , async ( ) => {
5363 await page . focus ( '#menu-button' ) ;
54- await keyboard . down ( 'Enter' ) ;
64+ await page . keyboard . down ( 'Enter' ) ;
5565 await menuOpen ( ) ;
5666
57- await keyboard . down ( 'Shift' ) ;
58- await keyboard . down ( 'Tab' ) ;
67+ await page . keyboard . down ( 'Shift' ) ;
68+ await page . keyboard . down ( 'Tab' ) ;
5969 await menuClosed ( ) ;
6070
6171 expect ( await currentFocusID ( ) ) . toBe ( 'menu-button' ) ;
6272} ) ;
6373
6474it ( 'closes the menu if you click outside of it' , async ( ) => {
6575 await page . focus ( '#menu-button' ) ;
66- await keyboard . down ( 'Enter' ) ;
76+ await page . keyboard . down ( 'Enter' ) ;
6777 await menuOpen ( ) ;
6878
6979 await page . click ( 'h1' ) ;
@@ -74,16 +84,26 @@ it('closes the menu if you click outside of it', async () => {
7484
7585it ( 'leaves the menu open if you click inside of it' , async ( ) => {
7686 await page . focus ( '#menu-button' ) ;
77- await keyboard . down ( 'Enter' ) ;
87+ await page . keyboard . down ( 'Enter' ) ;
7888 await menuOpen ( ) ;
7989
80- await page . click ( '#menu-item-1' ) ;
81- await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ; // visibility: hidden is delayed via CSS
82- await menuOpen ( ) ; // times out if menu closes
90+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
91+ page . once ( 'dialog' , async ( dialog ) => {
92+ await dialog . dismiss ( ) ;
93+ } ) ;
94+
95+ await page . click ( '#menu-item-3' ) ;
96+ await sleep ( 1000 ) ; // visibility: hidden is delayed via CSS
97+ expect ( await menuIsOpen ( page ) ) . toBe ( true ) ;
98+
99+ const { xOffset, yOffset } = await page . evaluate ( ( el : HTMLElement ) => {
100+ const { left : xOffset , top : yOffset } = el . getBoundingClientRect ( ) ;
101+ return { xOffset, yOffset } ;
102+ } , await page . $ ( '#menu' ) ) ;
83103
84- await page . click ( '#menu' ) ;
85- await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ; // visibility: hidden is delayed via CSS
86- await menuOpen ( ) ; // times out if menu closes
104+ await page . mouse . click ( xOffset + 2 , yOffset + 2 ) ; // Click just inside the top left corner (`page.click()` clicks the center, which is a link to NPM)
105+ await sleep ( 1000 ) ; // visibility: hidden is delayed via CSS
106+ expect ( await menuIsOpen ( page ) ) . toBe ( true ) ;
87107
88108 expect ( true ) . toBe ( true ) ;
89109} ) ;
@@ -92,7 +112,7 @@ it('reroutes enter presses on menu items as clicks', async () => {
92112 let alertAppeared = false ;
93113
94114 await page . focus ( '#menu-button' ) ;
95- await keyboard . down ( 'Enter' ) ;
115+ await page . keyboard . down ( 'Enter' ) ;
96116 await menuOpen ( ) ;
97117
98118 // eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -102,7 +122,7 @@ it('reroutes enter presses on menu items as clicks', async () => {
102122 } ) ;
103123
104124 await page . focus ( '#menu-item-3' ) ;
105- await keyboard . down ( 'Enter' ) ;
125+ await page . keyboard . down ( 'Enter' ) ;
106126
107127 expect ( alertAppeared ) . toBe ( true ) ;
108128} ) ;
0 commit comments