Skip to content

Commit 6a5dd05

Browse files
committed
chore(popover): add final tests for the popover
1 parent de0dfba commit 6a5dd05

File tree

6 files changed

+217
-20
lines changed

6 files changed

+217
-20
lines changed

.changeset/pink-pans-melt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
We are adding the final set of popover tests. With this we should now have full coverage for both current and legacy browsers.

apps/website/src/routes/docs/headless/popover/examples/programmatic.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ export default component$(() => {
1717
await togglePopover();
1818
}
1919
}}
20+
onClick$={async () => {
21+
await togglePopover();
22+
}}
2023
>
21-
Focus me and press the 'o' key!
24+
Click me or focus me and press the 'o' key!
2225
</button>
2326
<Popover.Panel class="popover-panel popover-programmatic">
2427
I'm a programmatically opened popover!
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Popover, usePopover } from '@qwik-ui/headless';
3+
export default component$(() => {
4+
const { hidePopover } = usePopover('hide-id');
5+
6+
return (
7+
<Popover.Root id="hide-id" manual hover>
8+
<button onClick$={() => hidePopover()}>hide popover</button>
9+
<Popover.Trigger class="popover-trigger">Click me</Popover.Trigger>
10+
<Popover.Panel class="popover">My Hero!</Popover.Panel>
11+
</Popover.Root>
12+
);
13+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { Popover } from '@qwik-ui/headless';
3+
export default component$(() => {
4+
return (
5+
<div class="flex flex-row">
6+
{[0, 1].map((i) => (
7+
<Popover.Root manual key={i}>
8+
<Popover.Trigger class="popover-trigger">Popover {i + 1}</Popover.Trigger>
9+
<Popover.Panel style={{ top: i === 1 ? '25px' : '0' }} class="popover-panel">
10+
Some super really long text that should overlap {i + 1}
11+
</Popover.Panel>
12+
</Popover.Root>
13+
))}
14+
</div>
15+
);
16+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { component$, useSignal } from '@builder.io/qwik';
2+
import { Popover, usePopover } from '@qwik-ui/headless';
3+
export default component$(() => {
4+
const { showPopover } = usePopover(`show-id`);
5+
const anchorRef = useSignal<HTMLElement | undefined>();
6+
7+
return (
8+
<Popover.Root id="show-id" bind:anchor={anchorRef}>
9+
<button ref={anchorRef} onClick$={() => showPopover()}>
10+
show popover
11+
</button>
12+
<Popover.Panel class="popover">My Hero!</Popover.Panel>
13+
</Popover.Root>
14+
);
15+
});

packages/kit-headless/src/components/popover/popover.test.ts

Lines changed: 164 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,44 @@ test.describe('Mouse Behavior', () => {
8585
await expect(secondPopover).toBeVisible();
8686
});
8787

88+
test(`GIVEN a pair of manual popovers
89+
WHEN clicking the first trigger on the page
90+
AND clicking the second trigger
91+
THEN the seconf popover should overlap the first`, async ({ page }) => {
92+
const { driver: d } = await setup(page, 'test-popover-overlap');
93+
94+
const [firstTrigger, secondTrigger] = await d.getAllTriggers();
95+
const [firstPopover, secondPopover] = await d.getAllPopovers();
96+
97+
firstTrigger.click();
98+
secondTrigger.click();
99+
100+
const topPopover = page.locator(
101+
`[popover]:above(:text("${await firstPopover.innerText()}"))`,
102+
);
103+
104+
expect(await topPopover.innerText()).toBe(await secondPopover.innerText());
105+
});
106+
107+
test(`GIVEN a pair of manual popovers
108+
WHEN clicking the second trigger on the page
109+
AND clicking the first trigger
110+
THEN the first popover should overlap the second`, async ({ page }) => {
111+
const { driver: d } = await setup(page, 'test-popover-overlap');
112+
113+
const [firstTrigger, secondTrigger] = await d.getAllTriggers();
114+
const [firstPopover, secondPopover] = await d.getAllPopovers();
115+
116+
firstTrigger.click();
117+
secondTrigger.click();
118+
119+
const topPopover = page.locator(
120+
`[popover]:above(:text("${await secondPopover.innerText()}"))`,
121+
);
122+
123+
expect(await topPopover.innerText()).toBe(await firstPopover.innerText());
124+
});
125+
88126
test(`GIVEN a pair of manual opened popovers
89127
WHEN clicking the first trigger on the page
90128
AND clicking the second trigger
@@ -110,6 +148,43 @@ test.describe('Mouse Behavior', () => {
110148
await expect(secondPopover).toBeHidden();
111149
});
112150

151+
test(`GIVEN a popover with hover enabled
152+
WHEN hovering over the popover
153+
THEN the popover should appear above the trigger`, async ({ page }) => {
154+
const { driver: d } = await setup(page, 'hover');
155+
156+
const popover = d.getPopover();
157+
const trigger = d.getTrigger();
158+
159+
await trigger.hover();
160+
161+
await expect(popover).toBeVisible();
162+
163+
const popoverBoundingBox = await popover.boundingBox();
164+
const triggerBoundingBox = await trigger.boundingBox();
165+
166+
const triggerTopEdge = triggerBoundingBox?.y ?? Number.MAX_VALUE;
167+
168+
expect(popoverBoundingBox?.y).toBeLessThan(triggerTopEdge);
169+
});
170+
171+
test(`GIVEN an open popover with hover enabled
172+
WHEN hovering await from the popover
173+
THEN the popover should disappear`, async ({ page }) => {
174+
const { driver: d } = await setup(page, 'hover');
175+
176+
const popover = d.getPopover();
177+
const trigger = d.getTrigger();
178+
179+
await trigger.hover();
180+
181+
await expect(popover).toBeVisible();
182+
183+
await page.mouse.move(0, 0);
184+
185+
await expect(popover).toBeHidden();
186+
});
187+
113188
test(`GIVEN a popover with placement set to right
114189
WHEN hovering over the popover
115190
THEN the popover should appear to the right of the trigger`, async ({ page }) => {
@@ -193,6 +268,45 @@ test.describe('Mouse Behavior', () => {
193268
yDiff = await calculateYDiff();
194269
expect(yDiff).toBeLessThan(0);
195270
});
271+
272+
test.describe('Programmatic functionality', () => {
273+
test(`GIVEN a programmatic popover
274+
WHEN the showPopover function is called
275+
THEN the popover should be open`, async ({ page }) => {
276+
const { driver: d } = await setup(page, 'test-show');
277+
await expect(d.getPopover()).toBeHidden();
278+
const programmaticTrigger = page.getByRole('button', { name: 'show popover' });
279+
await programmaticTrigger.click();
280+
await expect(d.getPopover()).toBeVisible();
281+
});
282+
283+
test(`GIVEN an open programmatic popover
284+
WHEN the hidePopover function is called
285+
THEN the popover should be hidden`, async ({ page }) => {
286+
const { driver: d } = await setup(page, 'test-hide');
287+
const programmaticTrigger = page.getByRole('button', { name: 'hide popover' });
288+
// initial open
289+
await d.openPopover('click');
290+
await programmaticTrigger.click({ position: { x: 0, y: 0 } });
291+
await expect(d.getPopover()).toBeHidden();
292+
});
293+
294+
test(`GIVEN a progrmmatic popover
295+
WHEN focusing on the button and pressing the 'o' key
296+
THEN the popover should be programmatically opened`, async ({ page }) => {
297+
const { driver: d } = await setup(page, 'programmatic');
298+
299+
await expect(d.getPopover()).toBeHidden();
300+
301+
const programmaticTrigger = page.getByRole('button');
302+
303+
// Using `page` here because driver is scoped to the popover
304+
await expect(programmaticTrigger).toBeVisible();
305+
await programmaticTrigger.click();
306+
307+
await expect(d.getPopover()).toBeVisible();
308+
});
309+
});
196310
});
197311

198312
test.describe('Keyboard Behavior', () => {
@@ -235,25 +349,6 @@ test.describe('Keyboard Behavior', () => {
235349
await expect(d.getTrigger()).toBeFocused();
236350
});
237351

238-
test(`GIVEN a popover
239-
WHEN focusing on the button and pressing the 'o' key
240-
THEN the popover should be programmatically opened`, async ({ page }) => {
241-
const { driver: d } = await setup(page, 'programmatic');
242-
243-
await expect(d.getPopover()).toBeHidden();
244-
245-
const programmaticTrigger = page.getByRole('button', {
246-
name: "Focus me and press the 'o'",
247-
});
248-
249-
// Using `page` here because driver is scoped to the popover
250-
await expect(programmaticTrigger).toBeVisible();
251-
await programmaticTrigger.focus();
252-
await programmaticTrigger.press('o');
253-
254-
await expect(d.getPopover()).toBeVisible();
255-
});
256-
257352
test.describe('auto', () => {
258353
test(`GIVEN a pair of auto popovers
259354
WHEN one popover is open with the enter key
@@ -345,4 +440,54 @@ test.describe('Keyboard Behavior', () => {
345440
(triggerBoundingBox?.width ?? Number.MAX_VALUE),
346441
);
347442
});
443+
444+
test.describe('Programmatic functionality', () => {
445+
test(`GIVEN a programmatic popover
446+
WHEN the showPopover function is called
447+
THEN the popover should be open`, async ({ page }) => {
448+
const { driver: d } = await setup(page, 'test-show');
449+
await expect(d.getPopover()).toBeHidden();
450+
const programmaticTrigger = page.getByRole('button', { name: 'show popover' });
451+
452+
await programmaticTrigger.focus();
453+
await programmaticTrigger.press('Enter');
454+
455+
await expect(d.getPopover()).toBeVisible();
456+
});
457+
458+
test(`GIVEN an open programmatic popover
459+
WHEN the hidePopover function is called
460+
THEN the popover should be hidden`, async ({ page }) => {
461+
const { driver: d } = await setup(page, 'test-hide');
462+
463+
// Initial open
464+
await d.getTrigger().click();
465+
await expect(d.getPopover()).toBeVisible();
466+
467+
const programmaticTrigger = page.getByRole('button', { name: 'hide popover' });
468+
await programmaticTrigger.focus();
469+
await programmaticTrigger.press('Enter');
470+
471+
await expect(d.getPopover()).toBeHidden();
472+
});
473+
474+
test(`GIVEN a progrmmatic popover
475+
WHEN focusing on the button and pressing the 'o' key
476+
THEN the popover should be programmatically opened`, async ({ page }) => {
477+
const { driver: d } = await setup(page, 'programmatic');
478+
479+
await expect(d.getPopover()).toBeHidden();
480+
481+
const programmaticTrigger = page.getByRole('button', {
482+
name: "Focus me and press the 'o'",
483+
});
484+
485+
// Using `page` here because driver is scoped to the popover
486+
await expect(programmaticTrigger).toBeVisible();
487+
await programmaticTrigger.focus();
488+
await programmaticTrigger.press('o');
489+
490+
await expect(d.getPopover()).toBeVisible();
491+
});
492+
});
348493
});

0 commit comments

Comments
 (0)