@@ -21,7 +21,7 @@ test('@Visual diff', async ({ page }) => {
2121} ) ;
2222
2323test . describe ( 'Mouse Behavior' , ( ) => {
24- test ( `GIVEN a closed popover
24+ test ( `GIVEN a closed hero popover
2525 WHEN clicking on the trigger
2626 THEN the popover should be opened ` , async ( { page } ) => {
2727 const { driver : d } = await setup ( page , 'hero' ) ;
@@ -31,4 +31,333 @@ test.describe('Mouse Behavior', () => {
3131
3232 await expect ( d . getPopover ( ) ) . toBeVisible ( ) ;
3333 } ) ;
34+
35+ test ( `GIVEN an open hero popover
36+ WHEN clicking elsewhere on the page
37+ THEN the popover should close` , async ( { page } ) => {
38+ const { driver : d } = await setup ( page , 'hero' ) ;
39+
40+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
41+ await d . getTrigger ( ) . click ( ) ;
42+
43+ // If I use `toBeVisible` here, the test fails that the `toBeHidden` check below????
44+ await expect ( d . getPopover ( ) ) . toHaveCSS ( 'opacity' , '1' ) ;
45+
46+ await page . mouse . click ( 0 , 0 ) ;
47+
48+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
49+ } ) ;
50+
51+ test ( `GIVEN an open auto popover
52+ WHEN clicking the first trigger on the page and then clicking the second trigger
53+ THEN the first popover should close and the second one appear` , async ( { page } ) => {
54+ const { driver : d } = await setup ( page , 'auto' ) ;
55+ //ask shai: is it good to use nth here???
56+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
57+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
58+
59+ await expect ( firstPopOver ) . toBeHidden ( ) ;
60+ await expect ( secondPopOver ) . toBeHidden ( ) ;
61+
62+ await firstPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
63+ await expect ( firstPopOver ) . toBeVisible ( ) ;
64+
65+ await secondPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
66+ await expect ( secondPopOver ) . toBeVisible ( ) ;
67+
68+ await expect ( firstPopOver ) . toBeHidden ( ) ;
69+ } ) ;
70+
71+ test ( `GIVEN a pair of manual popovers
72+ WHEN clicking the first trigger on the page and then clicking the second trigger
73+ THEN then both popovers should be opened` , async ( { page } ) => {
74+ const { driver : d } = await setup ( page , 'manual' ) ;
75+
76+ //ask shai: is it good to use nth here???
77+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
78+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
79+
80+ await expect ( firstPopOver ) . toBeHidden ( ) ;
81+ await expect ( secondPopOver ) . toBeHidden ( ) ;
82+
83+ await firstPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
84+ await secondPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
85+
86+ await expect ( firstPopOver ) . toBeVisible ( ) ;
87+ await expect ( secondPopOver ) . toBeVisible ( ) ;
88+ } ) ;
89+
90+ test ( `GIVEN a pair of manual opened popovers
91+ WHEN clicking the first trigger on the page and then clicking the second trigger
92+ THEN then both popovers should be closed` , async ( { page } ) => {
93+ const { driver : d } = await setup ( page , 'manual' ) ;
94+
95+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
96+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
97+
98+ // Arrange
99+ await firstPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
100+ await secondPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
101+
102+ await expect ( firstPopOver ) . toBeVisible ( ) ;
103+ await expect ( secondPopOver ) . toBeVisible ( ) ;
104+
105+ // Need to be explicit about where we're clicking. By default
106+ // the click action tries to click the center of the element
107+ // but in this case, the popover is covering it.
108+ await firstPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
109+ await secondPopoverTrigger . click ( { position : { x : 1 , y : 1 } } ) ;
110+
111+ // Assert
112+ await expect ( firstPopOver ) . toBeHidden ( ) ;
113+ await expect ( secondPopOver ) . toBeHidden ( ) ;
114+ } ) ;
115+
116+ test ( `GIVEN a popover with placement set to top
117+ WHEN opening the popover
118+ THEN the popover should appear to the right of the trigger` , async ( { page } ) => {
119+ const { driver : d } = await setup ( page , 'placement' ) ;
120+
121+ const popover = d . getPopover ( ) ;
122+ const trigger = d . getTrigger ( ) ;
123+
124+ await trigger . hover ( ) ;
125+
126+ await expect ( popover ) . toBeVisible ( ) ;
127+
128+ const popoverBoundingBox = await popover . boundingBox ( ) ;
129+ const triggerBoundingBox = await trigger . boundingBox ( ) ;
130+
131+ expect ( popoverBoundingBox ?. x ) . toBeGreaterThan (
132+ ( triggerBoundingBox ?. x ?? Number . MAX_VALUE ) +
133+ ( triggerBoundingBox ?. width ?? Number . MAX_VALUE ) ,
134+ ) ;
135+ } ) ;
136+
137+ test ( `GIVEN a popover with a gutter configured
138+ WHEN opening the popover
139+ THEN the popover should be spaced 40px from the popover` , async ( { page } ) => {
140+ const { driver : d } = await setup ( page , 'gutter' ) ;
141+
142+ const popover = d . getPopover ( ) ;
143+ const trigger = d . getTrigger ( ) ;
144+
145+ await trigger . click ( ) ;
146+
147+ await expect ( popover ) . toBeVisible ( ) ;
148+
149+ const popoverBoundingBox = await popover . boundingBox ( ) ;
150+ const triggerBoundingBox = await trigger . boundingBox ( ) ;
151+
152+ expect (
153+ ( triggerBoundingBox ?. y ?? 0 ) -
154+ ( ( popoverBoundingBox ?. y ?? 0 ) + ( popoverBoundingBox ?. height ?? 0 ) ) ,
155+ ) . toBe ( 40 ) ;
156+ } ) ;
157+
158+ // test(`GIVEN a combobox with a flip configured
159+ // WHEN scrolling the page
160+ // THEN the popover flip to the opposite end once space runs out`, async ({ page }) => {
161+ // const { driver: d } = await setup(page, 'flip');
162+
163+ // const popover = d.getPopover();
164+ // const trigger = d.getTrigger();
165+
166+ // // Introduce artificial spacing
167+ // await trigger.evaluate((element) => (element.style.top = '800px'));
168+
169+ // await trigger.click();
170+
171+ // await expect(popover).toBeVisible();
172+
173+ // const popoverBoundingBox = await popover.boundingBox();
174+ // const triggerBoundingBox = await trigger.boundingBox();
175+
176+ // console.log(triggerBoundingBox, popoverBoundingBox);
177+
178+ // const triggerBottomAbsolutePosition =
179+ // (triggerBoundingBox?.y ?? 0) + (triggerBoundingBox?.height ?? 0);
180+
181+ // expect((popoverBoundingBox?.y ?? 0) - triggerBottomAbsolutePosition).toBe(24);
182+ // });
183+ } ) ;
184+
185+ test . describe ( 'Keyboard Behavior' , ( ) => {
186+ for ( const key of [ 'Enter' , 'Space' ] ) {
187+ test ( `GIVEN a closed hero popover
188+ WHEN focusing on the button and pressing the '${ key } ' key
189+ THEN the popover should open` , async ( { page } ) => {
190+ const { driver : d } = await setup ( page , 'hero' ) ;
191+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
192+
193+ await d . getTrigger ( ) . press ( key ) ;
194+
195+ await expect ( d . getPopover ( ) ) . toBeVisible ( ) ;
196+ } ) ;
197+
198+ test ( `GIVEN a open hero popover
199+ WHEN focusing on the button and pressing the '${ key } ' key
200+ THEN the popover should close` , async ( { page } ) => {
201+ const { driver : d } = await setup ( page , 'hero' ) ;
202+
203+ // Open the popover
204+ await d . getTrigger ( ) . press ( key ) ;
205+
206+ await expect ( d . getPopover ( ) ) . toBeVisible ( ) ;
207+
208+ // Close the popover
209+ await d . getTrigger ( ) . press ( key ) ;
210+
211+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
212+ } ) ;
213+ }
214+
215+ test ( `GIVEN a open hero popover
216+ WHEN focusing on the button and pressing the 'Escape' key
217+ THEN the popover should close and the trigger be focused` , async ( { page } ) => {
218+ const { driver : d } = await setup ( page , 'hero' ) ;
219+
220+ // Open the popover
221+ await d . getTrigger ( ) . press ( 'Enter' ) ;
222+
223+ await expect ( d . getPopover ( ) ) . toBeVisible ( ) ;
224+
225+ // Close the popover
226+ page . keyboard . press ( 'Escape' ) ;
227+
228+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
229+ await expect ( d . getTrigger ( ) ) . toBeFocused ( ) ;
230+ } ) ;
231+
232+ test ( `GIVEN a programmatic popover with a programmatic trigger
233+ WHEN focusing on the button and pressing the 'o' key
234+ THEN the popover should open` , async ( { page } ) => {
235+ const { driver : d } = await setup ( page , 'programmatic' ) ;
236+
237+ await expect ( d . getPopover ( ) ) . toBeHidden ( ) ;
238+
239+ // Using `page` here because driver is scoped to the popover
240+ await page . getByRole ( 'button' , { name : "Focus me and press the 'o'" } ) . focus ( ) ;
241+ await page . keyboard . type ( 'o' ) ;
242+
243+ await expect ( d . getPopover ( ) ) . toBeVisible ( ) ;
244+ } ) ;
245+ test ( `GIVEN an open auto popover
246+ WHEN the first trigger open and the focus changes to the second popover
247+ THEN the first popover should close and the second one appear` , async ( { page } ) => {
248+ const { driver : d } = await setup ( page , 'auto' ) ;
249+
250+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
251+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
252+
253+ await expect ( firstPopOver ) . toBeHidden ( ) ;
254+ await expect ( secondPopOver ) . toBeHidden ( ) ;
255+
256+ await firstPopoverTrigger . press ( 'Enter' ) ;
257+ await expect ( firstPopOver ) . toBeVisible ( ) ;
258+ await firstPopoverTrigger . press ( 'Tab' ) ;
259+ await expect ( secondPopoverTrigger ) . toBeFocused ( ) ;
260+
261+ await secondPopoverTrigger . press ( 'Enter' ) ;
262+ await expect ( secondPopOver ) . toBeVisible ( ) ;
263+
264+ await expect ( firstPopOver ) . toBeHidden ( ) ;
265+ } ) ;
266+
267+ test ( `GIVEN a pair of manual popovers
268+ WHEN clicking the first trigger on the page and then clicking the second trigger
269+ THEN then both popovers should be opened` , async ( { page } ) => {
270+ const { driver : d } = await setup ( page , 'manual' ) ;
271+
272+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
273+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
274+
275+ await expect ( firstPopOver ) . toBeHidden ( ) ;
276+ await expect ( secondPopOver ) . toBeHidden ( ) ;
277+
278+ await firstPopoverTrigger . press ( 'Enter' ) ;
279+
280+ await secondPopoverTrigger . press ( 'Enter' ) ;
281+
282+ await expect ( firstPopOver ) . toBeVisible ( ) ;
283+ await expect ( secondPopOver ) . toBeVisible ( ) ;
284+ } ) ;
285+
286+ test ( `GIVEN a pair of manual opened popovers
287+ WHEN activating the first trigger on the page and then activating the second trigger
288+ THEN then both popovers should be closed` , async ( { page } ) => {
289+ const { driver : d } = await setup ( page , 'manual' ) ;
290+
291+ const [ firstPopOver , secondPopOver ] = await d . getAllPopovers ( ) ;
292+ const [ firstPopoverTrigger , secondPopoverTrigger ] = await d . getAllTriggers ( ) ;
293+
294+ // Arrange
295+ await firstPopoverTrigger . press ( 'Enter' ) ;
296+
297+ await secondPopoverTrigger . press ( 'Enter' ) ;
298+
299+ await expect ( firstPopOver ) . toBeVisible ( ) ;
300+ await expect ( secondPopOver ) . toBeVisible ( ) ;
301+
302+ // Act
303+ await secondPopoverTrigger . press ( 'Enter' ) ;
304+ await expect ( secondPopOver ) . toBeHidden ( ) ;
305+
306+ // Assert
307+ await firstPopoverTrigger . press ( 'Enter' ) ;
308+ await expect ( firstPopOver ) . toBeHidden ( ) ;
309+ } ) ;
310+
311+ test ( `GIVEN a programmatic popover
312+ WHEN focusing the button on the page and then typing 'o'
313+ THEN the popover should open` , async ( { page } ) => {
314+ const { driver : d } = await setup ( page , 'programmatic' ) ;
315+
316+ const popover = d . getPopover ( ) ;
317+ const programmaticButtonTrigger = d . getProgrammaticButtonTrigger ( ) ;
318+
319+ await expect ( popover ) . toBeHidden ( ) ;
320+
321+ await programmaticButtonTrigger . press ( 'o' ) ;
322+
323+ await expect ( popover ) . toBeVisible ( ) ;
324+ } ) ;
325+
326+ test ( `GIVEN an open programmatic popover
327+ WHEN focusing the button on the page and then typing 'o'
328+ THEN the popover should close` , async ( { page } ) => {
329+ const { driver : d } = await setup ( page , 'programmatic' ) ;
330+
331+ const popover = d . getPopover ( ) ;
332+ const programmaticButtonTrigger = d . getProgrammaticButtonTrigger ( ) ;
333+
334+ await programmaticButtonTrigger . press ( 'o' ) ;
335+
336+ await expect ( popover ) . toBeVisible ( ) ;
337+
338+ await programmaticButtonTrigger . press ( 'o' ) ;
339+
340+ await expect ( popover ) . toBeHidden ( ) ;
341+ } ) ;
342+
343+ test ( `GIVEN a popover with placement set to top
344+ WHEN opening the popover using the keyboard
345+ THEN the popover should appear to the right of the trigger` , async ( { page } ) => {
346+ const { driver : d } = await setup ( page , 'placement' ) ;
347+
348+ const popover = d . getPopover ( ) ;
349+ const trigger = d . getTrigger ( ) ;
350+
351+ await trigger . press ( 'Enter' ) ;
352+
353+ await expect ( popover ) . toBeVisible ( ) ;
354+
355+ const popoverBoundingBox = await popover . boundingBox ( ) ;
356+ const triggerBoundingBox = await trigger . boundingBox ( ) ;
357+
358+ expect ( popoverBoundingBox ?. x ) . toBeGreaterThan (
359+ ( triggerBoundingBox ?. x ?? Number . MAX_VALUE ) +
360+ ( triggerBoundingBox ?. width ?? Number . MAX_VALUE ) ,
361+ ) ;
362+ } ) ;
34363} ) ;
0 commit comments