@khanacademy/wonder-blocks-tooltip 2.4.1 → 2.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/package.json +6 -6
- package/src/components/__tests__/tooltip-anchor.test.tsx +0 -1003
- package/src/components/__tests__/tooltip-bubble.test.tsx +0 -64
- package/src/components/__tests__/tooltip-popper.test.tsx +0 -72
- package/src/components/__tests__/tooltip-tail.test.tsx +0 -135
- package/src/components/__tests__/tooltip.integration.test.tsx +0 -116
- package/src/components/__tests__/tooltip.test.tsx +0 -379
- package/src/components/tooltip-anchor.tsx +0 -341
- package/src/components/tooltip-bubble.tsx +0 -132
- package/src/components/tooltip-content.tsx +0 -96
- package/src/components/tooltip-popper.tsx +0 -265
- package/src/components/tooltip-tail.tsx +0 -445
- package/src/components/tooltip.tsx +0 -306
- package/src/index.ts +0 -10
- package/src/util/__tests__/__snapshots__/active-tracker.test.ts.snap +0 -3
- package/src/util/__tests__/__snapshots__/ref-tracker.test.tsx.snap +0 -3
- package/src/util/__tests__/active-tracker.test.ts +0 -142
- package/src/util/__tests__/ref-tracker.test.tsx +0 -158
- package/src/util/active-tracker.ts +0 -92
- package/src/util/constants.ts +0 -6
- package/src/util/ref-tracker.ts +0 -48
- package/src/util/types.ts +0 -46
- package/tsconfig-build.json +0 -15
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import * as ReactDOM from "react-dom";
|
|
3
|
-
import {render, screen} from "@testing-library/react";
|
|
4
|
-
import {userEvent} from "@testing-library/user-event";
|
|
5
|
-
|
|
6
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
7
|
-
|
|
8
|
-
import Tooltip from "../tooltip";
|
|
9
|
-
|
|
10
|
-
const mockIDENTIFIER = "mock-identifier";
|
|
11
|
-
jest.mock("@khanacademy/wonder-blocks-core", () => {
|
|
12
|
-
const Core = jest.requireActual("@khanacademy/wonder-blocks-core");
|
|
13
|
-
// We want all of Core to be the regular thing except for UniqueIDProvider
|
|
14
|
-
return {
|
|
15
|
-
...Core,
|
|
16
|
-
UniqueIDProvider: (props: any) =>
|
|
17
|
-
// NOTE(kevinb): We aren't actually access the DOM here. The logic
|
|
18
|
-
// used by this lint rule to determine DOM access could be more
|
|
19
|
-
// precise.
|
|
20
|
-
// eslint-disable-next-line testing-library/no-node-access
|
|
21
|
-
props.children({
|
|
22
|
-
get: () => mockIDENTIFIER,
|
|
23
|
-
}),
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("Tooltip", () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
jest.clearAllMocks();
|
|
30
|
-
jest.clearAllTimers();
|
|
31
|
-
jest.useFakeTimers();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe("basic operations", () => {
|
|
35
|
-
it("should not show the tooltip to being with", async () => {
|
|
36
|
-
// Arrange
|
|
37
|
-
render(
|
|
38
|
-
<View>
|
|
39
|
-
<Tooltip title="Title" content="Content">
|
|
40
|
-
<View>Anchor</View>
|
|
41
|
-
</Tooltip>
|
|
42
|
-
</View>,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
// Act
|
|
46
|
-
const tooltip = screen.queryByRole("tooltip");
|
|
47
|
-
|
|
48
|
-
// Assert
|
|
49
|
-
expect(tooltip).not.toBeInTheDocument();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("should show the tooltip on hover", async () => {
|
|
53
|
-
// Arrange
|
|
54
|
-
const ue = userEvent.setup({
|
|
55
|
-
advanceTimers: jest.advanceTimersByTime,
|
|
56
|
-
});
|
|
57
|
-
render(
|
|
58
|
-
<View>
|
|
59
|
-
<Tooltip title="Title" content="Content">
|
|
60
|
-
<View>Anchor</View>
|
|
61
|
-
</Tooltip>
|
|
62
|
-
</View>,
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const node = await screen.findByText("Anchor");
|
|
66
|
-
await ue.hover(node);
|
|
67
|
-
jest.runOnlyPendingTimers();
|
|
68
|
-
|
|
69
|
-
// Act
|
|
70
|
-
const tooltip = await screen.findByRole("tooltip");
|
|
71
|
-
|
|
72
|
-
// Assert
|
|
73
|
-
expect(tooltip).toBeInTheDocument();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it("should hide the tooltip on unhover", async () => {
|
|
77
|
-
// Arrange
|
|
78
|
-
const ue = userEvent.setup({
|
|
79
|
-
advanceTimers: jest.advanceTimersByTime,
|
|
80
|
-
});
|
|
81
|
-
render(
|
|
82
|
-
<View>
|
|
83
|
-
<Tooltip title="Title" content="Content">
|
|
84
|
-
<View>Anchor</View>
|
|
85
|
-
</Tooltip>
|
|
86
|
-
</View>,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const node = await screen.findByText("Anchor");
|
|
90
|
-
await ue.hover(node);
|
|
91
|
-
jest.runOnlyPendingTimers();
|
|
92
|
-
await ue.unhover(node);
|
|
93
|
-
jest.runOnlyPendingTimers();
|
|
94
|
-
|
|
95
|
-
// Act
|
|
96
|
-
const tooltip = screen.queryByRole("tooltip");
|
|
97
|
-
|
|
98
|
-
// Assert
|
|
99
|
-
expect(tooltip).not.toBeInTheDocument();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("should work when the anchor is text", async () => {
|
|
103
|
-
// Arrange
|
|
104
|
-
const ue = userEvent.setup({
|
|
105
|
-
advanceTimers: jest.advanceTimersByTime,
|
|
106
|
-
});
|
|
107
|
-
render(
|
|
108
|
-
<View>
|
|
109
|
-
<Tooltip title="Title" content="Content">
|
|
110
|
-
Anchor
|
|
111
|
-
</Tooltip>
|
|
112
|
-
</View>,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const node = await screen.findByText("Anchor");
|
|
116
|
-
await ue.hover(node);
|
|
117
|
-
jest.runOnlyPendingTimers();
|
|
118
|
-
|
|
119
|
-
// Act
|
|
120
|
-
const tooltip = await screen.findByRole("tooltip");
|
|
121
|
-
|
|
122
|
-
// Assert
|
|
123
|
-
expect(tooltip).toBeInTheDocument();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("should have a background color if one is set", async () => {
|
|
127
|
-
// Arrange
|
|
128
|
-
render(
|
|
129
|
-
<View>
|
|
130
|
-
<Tooltip
|
|
131
|
-
title="Title"
|
|
132
|
-
content="Content"
|
|
133
|
-
backgroundColor="blue"
|
|
134
|
-
opened={true}
|
|
135
|
-
>
|
|
136
|
-
Anchor
|
|
137
|
-
</Tooltip>
|
|
138
|
-
</View>,
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
// Act
|
|
142
|
-
const tooltipContent = await screen.findByRole("tooltip");
|
|
143
|
-
// eslint-disable-next-line testing-library/no-node-access
|
|
144
|
-
const innerTooltipContentView = tooltipContent.firstChild;
|
|
145
|
-
expect(innerTooltipContentView).toBeInTheDocument();
|
|
146
|
-
|
|
147
|
-
// Assert
|
|
148
|
-
expect(innerTooltipContentView).toHaveStyle(
|
|
149
|
-
"background-color: rgb(24, 101, 242)",
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe("accessibility", () => {
|
|
155
|
-
test("no id, sets identifier of TooltipBubble with UniqueIDProvider", async () => {
|
|
156
|
-
// Arrange
|
|
157
|
-
const ue = userEvent.setup({
|
|
158
|
-
advanceTimers: jest.advanceTimersByTime,
|
|
159
|
-
});
|
|
160
|
-
render(
|
|
161
|
-
<View>
|
|
162
|
-
<Tooltip title="Title" content="Content">
|
|
163
|
-
<View>Anchor</View>
|
|
164
|
-
</Tooltip>
|
|
165
|
-
</View>,
|
|
166
|
-
);
|
|
167
|
-
const node = await screen.findByText("Anchor");
|
|
168
|
-
await ue.hover(node);
|
|
169
|
-
jest.runOnlyPendingTimers();
|
|
170
|
-
|
|
171
|
-
// Act
|
|
172
|
-
// eslint-disable-next-line testing-library/no-node-access
|
|
173
|
-
const result = document.querySelector("#" + mockIDENTIFIER);
|
|
174
|
-
|
|
175
|
-
// Assert
|
|
176
|
-
expect(result).toBeInTheDocument();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("custom id, sets identifier of TooltipBubble", async () => {
|
|
180
|
-
// Arrange
|
|
181
|
-
const ue = userEvent.setup({
|
|
182
|
-
advanceTimers: jest.advanceTimersByTime,
|
|
183
|
-
});
|
|
184
|
-
render(
|
|
185
|
-
<View>
|
|
186
|
-
<Tooltip id="tooltip-1" title="Title" content="Content">
|
|
187
|
-
<View>Anchor</View>
|
|
188
|
-
</Tooltip>
|
|
189
|
-
</View>,
|
|
190
|
-
);
|
|
191
|
-
const node = await screen.findByText("Anchor");
|
|
192
|
-
await ue.hover(node);
|
|
193
|
-
jest.runOnlyPendingTimers();
|
|
194
|
-
|
|
195
|
-
// Act
|
|
196
|
-
// eslint-disable-next-line testing-library/no-node-access
|
|
197
|
-
const result = document.querySelector("#tooltip-1");
|
|
198
|
-
|
|
199
|
-
// Assert
|
|
200
|
-
expect(result).toBeInTheDocument();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
describe("text-only anchor", () => {
|
|
204
|
-
test("wraps with element", async () => {
|
|
205
|
-
// Arrange
|
|
206
|
-
render(
|
|
207
|
-
<View>
|
|
208
|
-
<Tooltip content="Content">Anchor</Tooltip>
|
|
209
|
-
</View>,
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
// Act
|
|
213
|
-
const result = await screen.findByText("Anchor");
|
|
214
|
-
|
|
215
|
-
// Assert
|
|
216
|
-
expect(result).toBeInstanceOf(HTMLSpanElement);
|
|
217
|
-
expect(result.innerHTML).toBe("Anchor");
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
test("id provided, does not attach aria-describedby", async () => {
|
|
221
|
-
// Arrange
|
|
222
|
-
render(
|
|
223
|
-
<View>
|
|
224
|
-
<Tooltip id="tooltip-2" content="Content">
|
|
225
|
-
Anchor
|
|
226
|
-
</Tooltip>
|
|
227
|
-
</View>,
|
|
228
|
-
);
|
|
229
|
-
const node = await screen.findByText("Anchor");
|
|
230
|
-
|
|
231
|
-
// Act
|
|
232
|
-
const result = node.getAttribute("aria-describedby");
|
|
233
|
-
|
|
234
|
-
// Assert
|
|
235
|
-
expect(result).toBeNull();
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
test("no id provided, attaches aria-describedby", async () => {
|
|
239
|
-
// Arrange
|
|
240
|
-
render(
|
|
241
|
-
<View>
|
|
242
|
-
<Tooltip content="Content">Anchor</Tooltip>
|
|
243
|
-
</View>,
|
|
244
|
-
);
|
|
245
|
-
const node = await screen.findByText("Anchor");
|
|
246
|
-
|
|
247
|
-
// Act
|
|
248
|
-
|
|
249
|
-
// Assert
|
|
250
|
-
expect(node).toHaveAttribute(
|
|
251
|
-
"aria-describedby",
|
|
252
|
-
mockIDENTIFIER,
|
|
253
|
-
);
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
describe("element anchor", () => {
|
|
258
|
-
test("does not wrap", async () => {
|
|
259
|
-
// Arrange
|
|
260
|
-
const anchor = (
|
|
261
|
-
<View>
|
|
262
|
-
<View>Anchor</View>
|
|
263
|
-
</View>
|
|
264
|
-
);
|
|
265
|
-
const ref = await new Promise((resolve: any) => {
|
|
266
|
-
render(
|
|
267
|
-
<View>
|
|
268
|
-
<Tooltip ref={resolve} content="Content">
|
|
269
|
-
{anchor}
|
|
270
|
-
</Tooltip>
|
|
271
|
-
</View>,
|
|
272
|
-
);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Act
|
|
276
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
|
|
277
|
-
const result = ReactDOM.findDOMNode(ref) as any;
|
|
278
|
-
|
|
279
|
-
// Assert
|
|
280
|
-
expect(result).toBeInstanceOf(HTMLDivElement);
|
|
281
|
-
expect(result.innerHTML).not.toBe("Anchor");
|
|
282
|
-
// eslint-disable-next-line testing-library/no-node-access
|
|
283
|
-
expect(result.children[0].innerHTML).toBe("Anchor");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("id provided, does not attach aria-describedby", async () => {
|
|
287
|
-
// Arrange
|
|
288
|
-
const anchor = (
|
|
289
|
-
<View>
|
|
290
|
-
<View>Anchor</View>
|
|
291
|
-
</View>
|
|
292
|
-
);
|
|
293
|
-
const ref = await new Promise((resolve: any) => {
|
|
294
|
-
render(
|
|
295
|
-
<View>
|
|
296
|
-
<Tooltip
|
|
297
|
-
id="tooltip-3"
|
|
298
|
-
ref={resolve}
|
|
299
|
-
content="Content"
|
|
300
|
-
>
|
|
301
|
-
{anchor}
|
|
302
|
-
</Tooltip>
|
|
303
|
-
</View>,
|
|
304
|
-
);
|
|
305
|
-
});
|
|
306
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
|
|
307
|
-
const node = ReactDOM.findDOMNode(ref) as any;
|
|
308
|
-
|
|
309
|
-
// Act
|
|
310
|
-
const result = node.getAttribute("aria-describedby");
|
|
311
|
-
|
|
312
|
-
// Assert
|
|
313
|
-
expect(result).toBeNull();
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
test("no id provided, attaches aria-describedby", async () => {
|
|
317
|
-
// Arrange
|
|
318
|
-
const anchor = (
|
|
319
|
-
<View>
|
|
320
|
-
<View>Anchor</View>
|
|
321
|
-
</View>
|
|
322
|
-
);
|
|
323
|
-
const ref = await new Promise((resolve: any) => {
|
|
324
|
-
render(
|
|
325
|
-
<View>
|
|
326
|
-
<Tooltip ref={resolve} content="Content">
|
|
327
|
-
{anchor}
|
|
328
|
-
</Tooltip>
|
|
329
|
-
</View>,
|
|
330
|
-
);
|
|
331
|
-
});
|
|
332
|
-
// @ts-expect-error [FEI-5019] - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'ReactInstance | null | undefined'.
|
|
333
|
-
const node = ReactDOM.findDOMNode(ref) as any;
|
|
334
|
-
|
|
335
|
-
// Act
|
|
336
|
-
const result = node.getAttribute("aria-describedby");
|
|
337
|
-
|
|
338
|
-
// Assert
|
|
339
|
-
expect(result).toBe(mockIDENTIFIER);
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
describe("Controlled", () => {
|
|
345
|
-
test("can be opened programmatically", async () => {
|
|
346
|
-
// Arrange
|
|
347
|
-
render(
|
|
348
|
-
<View>
|
|
349
|
-
<Tooltip id="tooltip" content="Content" opened={true}>
|
|
350
|
-
<View>Anchor</View>
|
|
351
|
-
</Tooltip>
|
|
352
|
-
</View>,
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
// Act
|
|
356
|
-
jest.runOnlyPendingTimers();
|
|
357
|
-
|
|
358
|
-
// Assert
|
|
359
|
-
expect(await screen.findByText("Content")).toBeInTheDocument();
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
test("can be closed programmatically", async () => {
|
|
363
|
-
// Arrange
|
|
364
|
-
render(
|
|
365
|
-
<View>
|
|
366
|
-
<Tooltip id="tooltip" content="Content" opened={false}>
|
|
367
|
-
<View>Anchor</View>
|
|
368
|
-
</Tooltip>
|
|
369
|
-
</View>,
|
|
370
|
-
);
|
|
371
|
-
|
|
372
|
-
// Act
|
|
373
|
-
jest.runOnlyPendingTimers();
|
|
374
|
-
|
|
375
|
-
// Assert
|
|
376
|
-
expect(screen.queryByText("Content")).not.toBeInTheDocument();
|
|
377
|
-
});
|
|
378
|
-
});
|
|
379
|
-
});
|