Skip to content

Commit 27fe572

Browse files
authored
test: add tooltip e2e (#1988)
1 parent 9a31a52 commit 27fe572

File tree

2 files changed

+192
-7
lines changed

2 files changed

+192
-7
lines changed

packages/blade/src/components/Tooltip/Tooltip.web.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,8 @@ const Tooltip = ({
5353
open: isOpen,
5454
strategy: 'fixed',
5555
onOpenChange: (open) => {
56-
if (open) {
57-
setIsOpen(true);
58-
onOpenChange?.({ isOpen: open });
59-
} else {
60-
setIsOpen(false);
61-
onOpenChange?.({ isOpen: open });
62-
}
56+
setIsOpen(open);
57+
onOpenChange?.({ isOpen: open });
6358
},
6459
middleware: [
6560
shift({ crossAxis: false, padding: GAP }),
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import type { StoryFn } from '@storybook/react';
2+
import { within, userEvent } from '@storybook/testing-library';
3+
import { expect, jest } from '@storybook/jest';
4+
import React from 'react';
5+
import { TooltipInteractiveWrapper, Tooltip as TooltipComponent } from '..';
6+
import { Button } from '~components/Button';
7+
import { Text } from '~components/Typography';
8+
import { Badge } from '~components/Badge';
9+
import BaseBox from '~components/Box/BaseBox';
10+
import type { BladeCommonEvents } from '~components/types';
11+
12+
const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
13+
14+
const onOpenChange = jest.fn();
15+
16+
export const TestTooltipOpenClose: StoryFn<typeof TooltipComponent> = (
17+
props,
18+
): React.ReactElement => {
19+
return (
20+
<TooltipComponent {...props} onOpenChange={onOpenChange}>
21+
<Button>Hover me</Button>
22+
</TooltipComponent>
23+
);
24+
};
25+
26+
TestTooltipOpenClose.args = {
27+
content: 'Some text',
28+
};
29+
TestTooltipOpenClose.play = async () => {
30+
const { getByRole, queryByText } = within(document.body);
31+
const tooltipContent = 'Some text';
32+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
33+
const showButton = getByRole('button', { name: 'Hover me' });
34+
// open
35+
await userEvent.hover(showButton);
36+
await sleep(600);
37+
await expect(onOpenChange).toBeCalledWith({ isOpen: true });
38+
await expect(queryByText(tooltipContent)).toBeVisible();
39+
// close
40+
await userEvent.unhover(showButton);
41+
await sleep(600);
42+
await expect(onOpenChange).toBeCalledWith({ isOpen: false });
43+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
44+
};
45+
46+
// TooltipInteractiveWrapper
47+
export const TestTooltipInteractiveWrapper: StoryFn<typeof TooltipComponent> = (
48+
props,
49+
): React.ReactElement => {
50+
onOpenChange.mockReset();
51+
return (
52+
<TooltipComponent {...props} onOpenChange={onOpenChange}>
53+
<TooltipInteractiveWrapper>
54+
<Badge>NEW</Badge>
55+
</TooltipInteractiveWrapper>
56+
</TooltipComponent>
57+
);
58+
};
59+
TestTooltipInteractiveWrapper.args = {
60+
content: 'Hello World',
61+
};
62+
TestTooltipInteractiveWrapper.play = async () => {
63+
const { getByText, queryByText } = within(document.body);
64+
const tooltipContent = 'Hello World';
65+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
66+
const badge = getByText('NEW');
67+
// open
68+
await userEvent.hover(badge);
69+
await sleep(600);
70+
await expect(onOpenChange).toBeCalledWith({ isOpen: true });
71+
await expect(queryByText(tooltipContent)).toBeVisible();
72+
// close
73+
await userEvent.unhover(badge);
74+
await sleep(600);
75+
await expect(onOpenChange).toBeCalledWith({ isOpen: false });
76+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
77+
};
78+
79+
const CustomTrigger = React.forwardRef<
80+
HTMLDivElement,
81+
{ children: React.ReactNode } & BladeCommonEvents
82+
>(
83+
(
84+
{
85+
children,
86+
onBlur,
87+
onFocus,
88+
onMouseLeave,
89+
onMouseMove,
90+
onPointerDown,
91+
onPointerEnter,
92+
onTouchEnd,
93+
onTouchStart,
94+
},
95+
ref,
96+
) => {
97+
return (
98+
<BaseBox
99+
width="80px"
100+
height="80px"
101+
backgroundColor="surface.background.level2.lowContrast"
102+
textAlign="center"
103+
ref={ref}
104+
tabIndex={0}
105+
onBlur={onBlur}
106+
onFocus={onFocus}
107+
onMouseLeave={onMouseLeave}
108+
onMouseMove={onMouseMove}
109+
onPointerDown={onPointerDown}
110+
onPointerEnter={onPointerEnter}
111+
onTouchEnd={onTouchEnd}
112+
onTouchStart={onTouchStart}
113+
>
114+
<Text contrast="low">{children}</Text>
115+
</BaseBox>
116+
);
117+
},
118+
);
119+
120+
// custom trigger
121+
export const TestCustomTrigger: StoryFn<typeof TooltipComponent> = (props): React.ReactElement => {
122+
onOpenChange.mockReset();
123+
return (
124+
<TooltipComponent {...props} onOpenChange={onOpenChange}>
125+
<CustomTrigger>Custom Trigger</CustomTrigger>
126+
</TooltipComponent>
127+
);
128+
};
129+
TestCustomTrigger.args = {
130+
content: 'Hello World',
131+
};
132+
TestCustomTrigger.play = async () => {
133+
const { getByText, queryByText } = within(document.body);
134+
const tooltipContent = 'Hello World';
135+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
136+
const trigger = getByText('Custom Trigger');
137+
// open
138+
await userEvent.hover(trigger);
139+
await sleep(600);
140+
await expect(onOpenChange).toBeCalledWith({ isOpen: true });
141+
await expect(queryByText(tooltipContent)).toBeVisible();
142+
// close
143+
await userEvent.unhover(trigger);
144+
await sleep(600);
145+
await expect(onOpenChange).toBeCalledWith({ isOpen: false });
146+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
147+
};
148+
149+
// should open/close immediately on focus/blur without the default delay of 300ms
150+
export const TestTooltipOpenCloseFocus: StoryFn<typeof TooltipComponent> = (
151+
props,
152+
): React.ReactElement => {
153+
return (
154+
<TooltipComponent {...props} onOpenChange={onOpenChange}>
155+
<Button>Hover me</Button>
156+
</TooltipComponent>
157+
);
158+
};
159+
160+
TestTooltipOpenCloseFocus.args = {
161+
content: 'Some text',
162+
};
163+
TestTooltipOpenCloseFocus.play = async () => {
164+
const { queryByText } = within(document.body);
165+
const tooltipContent = 'Some text';
166+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
167+
// open
168+
await userEvent.keyboard('{Tab}', {});
169+
await sleep(600);
170+
await expect(onOpenChange).toBeCalledWith({ isOpen: true });
171+
await expect(queryByText(tooltipContent)).toBeVisible();
172+
// close
173+
await userEvent.keyboard('{Tab}', {});
174+
await sleep(600);
175+
await expect(onOpenChange).toBeCalledWith({ isOpen: false });
176+
await expect(queryByText(tooltipContent)).not.toBeInTheDocument();
177+
};
178+
179+
export default {
180+
title: 'Components/Interaction Tests/Tooltip',
181+
component: TooltipComponent,
182+
parameters: {
183+
controls: {
184+
disable: true,
185+
},
186+
a11y: { disable: true },
187+
essentials: { disable: true },
188+
actions: { disable: true },
189+
},
190+
};

0 commit comments

Comments
 (0)