@khanacademy/wonder-blocks-clickable 4.2.7 → 4.2.8
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 +9 -0
- package/package.json +3 -3
- package/src/components/__tests__/clickable-behavior.test.tsx +0 -1438
- package/src/components/__tests__/clickable-behavior.typestest.tsx +0 -20
- package/src/components/__tests__/clickable.test.tsx +0 -661
- package/src/components/__tests__/clickable.typestest.tsx +0 -64
- package/src/components/clickable-behavior.ts +0 -659
- package/src/components/clickable.tsx +0 -429
- package/src/index.ts +0 -14
- package/src/util/__tests__/get-clickable-behavior.test.tsx +0 -104
- package/src/util/__tests__/is-client-side-url.js.test.ts +0 -49
- package/src/util/get-clickable-behavior.ts +0 -46
- package/src/util/is-client-side-url.ts +0 -15
- package/tsconfig-build.json +0 -12
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,1438 +0,0 @@
|
|
|
1
|
-
/* eslint-disable testing-library/prefer-user-event */
|
|
2
|
-
/* eslint-disable max-lines */
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import {render, screen, fireEvent, waitFor} from "@testing-library/react";
|
|
5
|
-
import {MemoryRouter, Switch, Route} from "react-router-dom";
|
|
6
|
-
import {userEvent} from "@testing-library/user-event";
|
|
7
|
-
|
|
8
|
-
import getClickableBehavior from "../../util/get-clickable-behavior";
|
|
9
|
-
import ClickableBehavior from "../clickable-behavior";
|
|
10
|
-
import type {ClickableState} from "../clickable-behavior";
|
|
11
|
-
|
|
12
|
-
const keyCodes = {
|
|
13
|
-
tab: 9,
|
|
14
|
-
enter: 13,
|
|
15
|
-
space: 32,
|
|
16
|
-
} as const;
|
|
17
|
-
|
|
18
|
-
const labelForState = (state: ClickableState): string => {
|
|
19
|
-
const labels: Array<any> = [];
|
|
20
|
-
if (state.hovered) {
|
|
21
|
-
labels.push("hovered");
|
|
22
|
-
}
|
|
23
|
-
if (state.focused) {
|
|
24
|
-
labels.push("focused");
|
|
25
|
-
}
|
|
26
|
-
if (state.pressed) {
|
|
27
|
-
labels.push("pressed");
|
|
28
|
-
}
|
|
29
|
-
return labels.join(" ");
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
describe("ClickableBehavior", () => {
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
// Note: window.location.assign and window.open need mock functions in
|
|
35
|
-
// the testing environment
|
|
36
|
-
// @ts-expect-error [FEI-5019] - TS2790 - The operand of a 'delete' operator must be optional.
|
|
37
|
-
delete window.location;
|
|
38
|
-
// @ts-expect-error [FEI-5019] - TS2740 - Type '{ assign: Mock<any, any, any>; }' is missing the following properties from type 'Location': ancestorOrigins, hash, host, hostname, and 8 more.
|
|
39
|
-
window.location = {assign: jest.fn()};
|
|
40
|
-
window.open = jest.fn();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
// @ts-expect-error [FEI-5019] - TS2339 - Property 'mockClear' does not exist on type '(url: string | URL) => void'.
|
|
45
|
-
window.location.assign.mockClear();
|
|
46
|
-
// @ts-expect-error [FEI-5019] - TS2339 - Property 'mockClear' does not exist on type '((url?: string | URL | undefined, target?: string | undefined, features?: string | undefined) => Window | null) & ((url?: string | URL | undefined, target?: string | undefined, features?: string | undefined) => Window | null)'.
|
|
47
|
-
window.open.mockClear();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("renders a label", async () => {
|
|
51
|
-
const onClick = jest.fn();
|
|
52
|
-
render(
|
|
53
|
-
<ClickableBehavior
|
|
54
|
-
disabled={false}
|
|
55
|
-
onClick={(e: any) => onClick(e)}
|
|
56
|
-
>
|
|
57
|
-
{(state: any, childrenProps: any) => {
|
|
58
|
-
return <button {...childrenProps}>Label</button>;
|
|
59
|
-
}}
|
|
60
|
-
</ClickableBehavior>,
|
|
61
|
-
);
|
|
62
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
63
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
64
|
-
expect(onClick).toHaveBeenCalled();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("changes hovered state on mouse enter/leave", async () => {
|
|
68
|
-
const onClick = jest.fn();
|
|
69
|
-
render(
|
|
70
|
-
<ClickableBehavior
|
|
71
|
-
disabled={false}
|
|
72
|
-
onClick={(e: any) => onClick(e)}
|
|
73
|
-
>
|
|
74
|
-
{(state: any, childrenProps: any) => {
|
|
75
|
-
const label = labelForState(state);
|
|
76
|
-
return <button {...childrenProps}>{label}</button>;
|
|
77
|
-
}}
|
|
78
|
-
</ClickableBehavior>,
|
|
79
|
-
);
|
|
80
|
-
const button = await screen.findByRole("button");
|
|
81
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
82
|
-
await userEvent.hover(button);
|
|
83
|
-
expect(button).toHaveTextContent("hovered");
|
|
84
|
-
await userEvent.unhover(button);
|
|
85
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("changes hovered state on mouse enter while dragging", async () => {
|
|
89
|
-
const onClick = jest.fn();
|
|
90
|
-
render(
|
|
91
|
-
<ClickableBehavior
|
|
92
|
-
disabled={false}
|
|
93
|
-
onClick={(e: any) => onClick(e)}
|
|
94
|
-
>
|
|
95
|
-
{(state: any, childrenProps: any) => {
|
|
96
|
-
const label = labelForState(state);
|
|
97
|
-
return <button {...childrenProps}>{label}</button>;
|
|
98
|
-
}}
|
|
99
|
-
</ClickableBehavior>,
|
|
100
|
-
);
|
|
101
|
-
const button = await screen.findByRole("button");
|
|
102
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
103
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
104
|
-
|
|
105
|
-
fireEvent.mouseEnter(button, {buttons: 1});
|
|
106
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
107
|
-
expect(button).toHaveTextContent("hovered");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("changes pressed and hover states on mouse leave while dragging", async () => {
|
|
111
|
-
const onClick = jest.fn();
|
|
112
|
-
render(
|
|
113
|
-
<ClickableBehavior
|
|
114
|
-
disabled={false}
|
|
115
|
-
onClick={(e: any) => onClick(e)}
|
|
116
|
-
>
|
|
117
|
-
{(state: any, childrenProps: any) => {
|
|
118
|
-
const label = labelForState(state);
|
|
119
|
-
return <button {...childrenProps}>{label}</button>;
|
|
120
|
-
}}
|
|
121
|
-
</ClickableBehavior>,
|
|
122
|
-
);
|
|
123
|
-
const button = await screen.findByRole("button");
|
|
124
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
125
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
126
|
-
|
|
127
|
-
fireEvent.mouseDown(button);
|
|
128
|
-
expect(button).toHaveTextContent("pressed");
|
|
129
|
-
|
|
130
|
-
fireEvent.mouseLeave(button);
|
|
131
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
132
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("changes pressed state on mouse down/up", async () => {
|
|
136
|
-
const onClick = jest.fn();
|
|
137
|
-
render(
|
|
138
|
-
<ClickableBehavior
|
|
139
|
-
disabled={false}
|
|
140
|
-
onClick={(e: any) => onClick(e)}
|
|
141
|
-
>
|
|
142
|
-
{(state: any, childrenProps: any) => {
|
|
143
|
-
const label = labelForState(state);
|
|
144
|
-
return <button {...childrenProps}>{label}</button>;
|
|
145
|
-
}}
|
|
146
|
-
</ClickableBehavior>,
|
|
147
|
-
);
|
|
148
|
-
const button = await screen.findByRole("button");
|
|
149
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
150
|
-
fireEvent.mouseDown(button);
|
|
151
|
-
expect(button).toHaveTextContent("pressed");
|
|
152
|
-
fireEvent.mouseUp(button);
|
|
153
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it("changes pressed state on touch start/end/cancel", async () => {
|
|
157
|
-
const onClick = jest.fn();
|
|
158
|
-
render(
|
|
159
|
-
<ClickableBehavior
|
|
160
|
-
disabled={false}
|
|
161
|
-
onClick={(e: any) => onClick(e)}
|
|
162
|
-
>
|
|
163
|
-
{(state: any, childrenProps: any) => {
|
|
164
|
-
const label = labelForState(state);
|
|
165
|
-
return <button {...childrenProps}>{label}</button>;
|
|
166
|
-
}}
|
|
167
|
-
</ClickableBehavior>,
|
|
168
|
-
);
|
|
169
|
-
const button = await screen.findByRole("button");
|
|
170
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
171
|
-
fireEvent.touchStart(button);
|
|
172
|
-
expect(button).toHaveTextContent("pressed");
|
|
173
|
-
fireEvent.touchEnd(button);
|
|
174
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
175
|
-
|
|
176
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
177
|
-
fireEvent.touchStart(button);
|
|
178
|
-
expect(button).toHaveTextContent("pressed");
|
|
179
|
-
fireEvent.touchCancel(button);
|
|
180
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it("enters focused state on key press after click", async () => {
|
|
184
|
-
const onClick = jest.fn();
|
|
185
|
-
render(
|
|
186
|
-
<ClickableBehavior
|
|
187
|
-
disabled={false}
|
|
188
|
-
onClick={(e: any) => onClick(e)}
|
|
189
|
-
>
|
|
190
|
-
{(state: any, childrenProps: any) => {
|
|
191
|
-
const label = labelForState(state);
|
|
192
|
-
return <button {...childrenProps}>{label}</button>;
|
|
193
|
-
}}
|
|
194
|
-
</ClickableBehavior>,
|
|
195
|
-
);
|
|
196
|
-
const button = await screen.findByRole("button");
|
|
197
|
-
expect(button).not.toHaveTextContent("focused");
|
|
198
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
199
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
200
|
-
// NOTE(kevinb): await userEvent.click() fires other events that we don't want
|
|
201
|
-
// affecting this test case.
|
|
202
|
-
fireEvent.click(button);
|
|
203
|
-
expect(button).toHaveTextContent("focused");
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it("exits focused state on click after key press", async () => {
|
|
207
|
-
const onClick = jest.fn();
|
|
208
|
-
|
|
209
|
-
render(
|
|
210
|
-
<ClickableBehavior
|
|
211
|
-
disabled={false}
|
|
212
|
-
onClick={(e: any) => onClick(e)}
|
|
213
|
-
>
|
|
214
|
-
{(state: any, childrenProps: any) => {
|
|
215
|
-
const label = labelForState(state);
|
|
216
|
-
return <button {...childrenProps}>{label}</button>;
|
|
217
|
-
}}
|
|
218
|
-
</ClickableBehavior>,
|
|
219
|
-
);
|
|
220
|
-
const button = await screen.findByRole("button");
|
|
221
|
-
expect(button).not.toHaveTextContent("focused");
|
|
222
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
223
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
224
|
-
// NOTE(kevinb): await userEvent.click() fires other events that we don't want
|
|
225
|
-
// affecting this test case.
|
|
226
|
-
fireEvent.click(button);
|
|
227
|
-
expect(button).toHaveTextContent("focused");
|
|
228
|
-
await userEvent.click(button);
|
|
229
|
-
expect(button).not.toHaveTextContent("focused");
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("changes pressed state on space/enter key down/up if <button>", async () => {
|
|
233
|
-
const onClick = jest.fn();
|
|
234
|
-
render(
|
|
235
|
-
<ClickableBehavior
|
|
236
|
-
disabled={false}
|
|
237
|
-
onClick={(e: any) => onClick(e)}
|
|
238
|
-
>
|
|
239
|
-
{(state: any, childrenProps: any) => {
|
|
240
|
-
const label = labelForState(state);
|
|
241
|
-
return <button {...childrenProps}>{label}</button>;
|
|
242
|
-
}}
|
|
243
|
-
</ClickableBehavior>,
|
|
244
|
-
);
|
|
245
|
-
const button = await screen.findByRole("button");
|
|
246
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
247
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
248
|
-
expect(button).toHaveTextContent("pressed");
|
|
249
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
250
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
251
|
-
|
|
252
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
253
|
-
expect(button).toHaveTextContent("pressed");
|
|
254
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
255
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it("changes pressed state on only enter key down/up for a link", async () => {
|
|
259
|
-
const onClick = jest.fn();
|
|
260
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
261
|
-
render(
|
|
262
|
-
<ClickableBehavior
|
|
263
|
-
disabled={false}
|
|
264
|
-
onClick={(e: any) => onClick(e)}
|
|
265
|
-
href="https://www.khanacademy.org"
|
|
266
|
-
role="link"
|
|
267
|
-
>
|
|
268
|
-
{(state: any, childrenProps: any) => {
|
|
269
|
-
const label = labelForState(state);
|
|
270
|
-
return (
|
|
271
|
-
<a
|
|
272
|
-
href="https://www.khanacademy.org"
|
|
273
|
-
{...childrenProps}
|
|
274
|
-
>
|
|
275
|
-
{label}
|
|
276
|
-
</a>
|
|
277
|
-
);
|
|
278
|
-
}}
|
|
279
|
-
</ClickableBehavior>,
|
|
280
|
-
);
|
|
281
|
-
const link = await screen.findByRole("link");
|
|
282
|
-
expect(link).not.toHaveTextContent("pressed");
|
|
283
|
-
fireEvent.keyDown(link, {keyCode: keyCodes.enter});
|
|
284
|
-
expect(link).toHaveTextContent("pressed");
|
|
285
|
-
fireEvent.keyUp(link, {keyCode: keyCodes.enter});
|
|
286
|
-
expect(link).not.toHaveTextContent("pressed");
|
|
287
|
-
|
|
288
|
-
fireEvent.keyDown(link, {keyCode: keyCodes.space});
|
|
289
|
-
expect(link).not.toHaveTextContent("pressed");
|
|
290
|
-
fireEvent.keyUp(link, {keyCode: keyCodes.space});
|
|
291
|
-
expect(link).not.toHaveTextContent("pressed");
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it("gains focused state on focus event", async () => {
|
|
295
|
-
const onClick = jest.fn();
|
|
296
|
-
render(
|
|
297
|
-
<ClickableBehavior
|
|
298
|
-
disabled={false}
|
|
299
|
-
onClick={(e: any) => onClick(e)}
|
|
300
|
-
>
|
|
301
|
-
{(state: any, childrenProps: any) => {
|
|
302
|
-
const label = labelForState(state);
|
|
303
|
-
return <button {...childrenProps}>{label}</button>;
|
|
304
|
-
}}
|
|
305
|
-
</ClickableBehavior>,
|
|
306
|
-
);
|
|
307
|
-
const button = await screen.findByRole("button");
|
|
308
|
-
fireEvent.focus(button);
|
|
309
|
-
expect(button).toHaveTextContent("focused");
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it("changes focused state on blur", async () => {
|
|
313
|
-
const onClick = jest.fn();
|
|
314
|
-
render(
|
|
315
|
-
<ClickableBehavior
|
|
316
|
-
disabled={false}
|
|
317
|
-
onClick={(e: any) => onClick(e)}
|
|
318
|
-
>
|
|
319
|
-
{(state: any, childrenProps: any) => {
|
|
320
|
-
const label = labelForState(state);
|
|
321
|
-
return <button {...childrenProps}>{label}</button>;
|
|
322
|
-
}}
|
|
323
|
-
</ClickableBehavior>,
|
|
324
|
-
);
|
|
325
|
-
const button = await screen.findByRole("button");
|
|
326
|
-
fireEvent.focus(button);
|
|
327
|
-
fireEvent.blur(button);
|
|
328
|
-
expect(button).not.toHaveTextContent("focused");
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
test("should not have a tabIndex if one is not passed in", async () => {
|
|
332
|
-
// Arrange
|
|
333
|
-
// Act
|
|
334
|
-
render(
|
|
335
|
-
<ClickableBehavior disabled={false} onClick={(e: any) => {}}>
|
|
336
|
-
{(state: any, childrenProps: any) => {
|
|
337
|
-
return (
|
|
338
|
-
<button data-testid="test-button-1" {...childrenProps}>
|
|
339
|
-
Label
|
|
340
|
-
</button>
|
|
341
|
-
);
|
|
342
|
-
}}
|
|
343
|
-
</ClickableBehavior>,
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
// Assert
|
|
347
|
-
const button = await screen.findByTestId("test-button-1");
|
|
348
|
-
expect(button).not.toHaveAttribute("tabIndex");
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
test("should have the tabIndex that is passed in", async () => {
|
|
352
|
-
// Arrange
|
|
353
|
-
// Act
|
|
354
|
-
render(
|
|
355
|
-
<ClickableBehavior
|
|
356
|
-
disabled={false}
|
|
357
|
-
onClick={(e: any) => {}}
|
|
358
|
-
tabIndex={1}
|
|
359
|
-
>
|
|
360
|
-
{(state: any, childrenProps: any) => {
|
|
361
|
-
return (
|
|
362
|
-
<button data-testid="test-button-2" {...childrenProps}>
|
|
363
|
-
Label
|
|
364
|
-
</button>
|
|
365
|
-
);
|
|
366
|
-
}}
|
|
367
|
-
</ClickableBehavior>,
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
// Assert
|
|
371
|
-
const button = await screen.findByTestId("test-button-2");
|
|
372
|
-
expect(button).toHaveAttribute("tabIndex", "1");
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
test("should have the tabIndex that is passed in even if disabled", async () => {
|
|
376
|
-
// Arrange
|
|
377
|
-
// Act
|
|
378
|
-
render(
|
|
379
|
-
<ClickableBehavior
|
|
380
|
-
disabled={true}
|
|
381
|
-
onClick={(e: any) => {}}
|
|
382
|
-
tabIndex={1}
|
|
383
|
-
>
|
|
384
|
-
{(state: any, childrenProps: any) => {
|
|
385
|
-
return (
|
|
386
|
-
<button data-testid="test-button-3" {...childrenProps}>
|
|
387
|
-
Label
|
|
388
|
-
</button>
|
|
389
|
-
);
|
|
390
|
-
}}
|
|
391
|
-
</ClickableBehavior>,
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
// Assert
|
|
395
|
-
const button = await screen.findByTestId("test-button-3");
|
|
396
|
-
expect(button).toHaveAttribute("tabIndex", "1");
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
test("should make non-interactive children keyboard focusable if tabIndex 0 is passed", async () => {
|
|
400
|
-
// Arrange
|
|
401
|
-
render(
|
|
402
|
-
<ClickableBehavior
|
|
403
|
-
disabled={false}
|
|
404
|
-
onClick={(e: any) => {}}
|
|
405
|
-
tabIndex={1}
|
|
406
|
-
>
|
|
407
|
-
{(state: any, childrenProps: any) => {
|
|
408
|
-
return (
|
|
409
|
-
<div data-testid="test-div-1" {...childrenProps}>
|
|
410
|
-
Label
|
|
411
|
-
</div>
|
|
412
|
-
);
|
|
413
|
-
}}
|
|
414
|
-
</ClickableBehavior>,
|
|
415
|
-
);
|
|
416
|
-
|
|
417
|
-
// Act
|
|
418
|
-
const button = await screen.findByTestId("test-div-1");
|
|
419
|
-
await userEvent.tab();
|
|
420
|
-
|
|
421
|
-
// Assert
|
|
422
|
-
expect(button).toHaveFocus();
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it("does not change state if disabled", async () => {
|
|
426
|
-
const onClick = jest.fn();
|
|
427
|
-
render(
|
|
428
|
-
<ClickableBehavior disabled={true} onClick={(e: any) => onClick(e)}>
|
|
429
|
-
{(state: any, childrenProps: any) => {
|
|
430
|
-
const label = labelForState(state);
|
|
431
|
-
return <button {...childrenProps}>{label}</button>;
|
|
432
|
-
}}
|
|
433
|
-
</ClickableBehavior>,
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
const button = await screen.findByRole("button");
|
|
437
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
438
|
-
fireEvent.click(button);
|
|
439
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
440
|
-
|
|
441
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
442
|
-
fireEvent.mouseEnter(button);
|
|
443
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
444
|
-
fireEvent.mouseLeave(button);
|
|
445
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
446
|
-
|
|
447
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
448
|
-
fireEvent.mouseDown(button);
|
|
449
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
450
|
-
fireEvent.mouseUp(button);
|
|
451
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
452
|
-
|
|
453
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
454
|
-
fireEvent.touchStart(button);
|
|
455
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
456
|
-
fireEvent.touchEnd(button);
|
|
457
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
458
|
-
|
|
459
|
-
fireEvent.touchStart(button);
|
|
460
|
-
fireEvent.touchCancel(button);
|
|
461
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
462
|
-
|
|
463
|
-
expect(button).not.toHaveTextContent("focused");
|
|
464
|
-
fireEvent.keyUp(button, {
|
|
465
|
-
keyCode: keyCodes.tab,
|
|
466
|
-
});
|
|
467
|
-
expect(button).not.toHaveTextContent("focused");
|
|
468
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.tab});
|
|
469
|
-
expect(button).not.toHaveTextContent("focused");
|
|
470
|
-
|
|
471
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
472
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
473
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
474
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
475
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
476
|
-
|
|
477
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
478
|
-
fireEvent.blur(button);
|
|
479
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
480
|
-
|
|
481
|
-
fireEvent.focus(button);
|
|
482
|
-
expect(button).toHaveTextContent("focused");
|
|
483
|
-
|
|
484
|
-
render(
|
|
485
|
-
<ClickableBehavior
|
|
486
|
-
disabled={true}
|
|
487
|
-
href="https://www.khanacademy.org"
|
|
488
|
-
>
|
|
489
|
-
{(state: any, childrenProps: any) => {
|
|
490
|
-
return (
|
|
491
|
-
<a
|
|
492
|
-
href="https://www.khanacademy.org"
|
|
493
|
-
{...childrenProps}
|
|
494
|
-
>
|
|
495
|
-
Label
|
|
496
|
-
</a>
|
|
497
|
-
);
|
|
498
|
-
}}
|
|
499
|
-
</ClickableBehavior>,
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
const anchor = await screen.findByRole("link");
|
|
503
|
-
expect(anchor).not.toHaveTextContent("pressed");
|
|
504
|
-
fireEvent.keyDown(anchor, {keyCode: keyCodes.enter});
|
|
505
|
-
expect(anchor).not.toHaveTextContent("pressed");
|
|
506
|
-
fireEvent.keyUp(anchor, {keyCode: keyCodes.enter});
|
|
507
|
-
expect(anchor).not.toHaveTextContent("pressed");
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
it("has onClick triggered just once per click by various means", async () => {
|
|
511
|
-
const onClick = jest.fn();
|
|
512
|
-
render(
|
|
513
|
-
<ClickableBehavior
|
|
514
|
-
disabled={false}
|
|
515
|
-
onClick={(e: any) => onClick(e)}
|
|
516
|
-
>
|
|
517
|
-
{(state: any, childrenProps: any) => {
|
|
518
|
-
return <button {...childrenProps}>Label</button>;
|
|
519
|
-
}}
|
|
520
|
-
</ClickableBehavior>,
|
|
521
|
-
);
|
|
522
|
-
const button = await screen.findByRole("button");
|
|
523
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
524
|
-
|
|
525
|
-
await userEvent.click(button);
|
|
526
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
527
|
-
|
|
528
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
529
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
530
|
-
expect(onClick).toHaveBeenCalledTimes(2);
|
|
531
|
-
|
|
532
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
533
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
534
|
-
expect(onClick).toHaveBeenCalledTimes(3);
|
|
535
|
-
|
|
536
|
-
fireEvent.touchStart(button, {keyCode: keyCodes.space});
|
|
537
|
-
fireEvent.touchEnd(button, {keyCode: keyCodes.space});
|
|
538
|
-
fireEvent.click(button);
|
|
539
|
-
expect(onClick).toHaveBeenCalledTimes(4);
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
it("resets state when set to disabled", async () => {
|
|
543
|
-
const onClick = jest.fn();
|
|
544
|
-
const {rerender} = render(
|
|
545
|
-
<ClickableBehavior
|
|
546
|
-
disabled={false}
|
|
547
|
-
onClick={(e: any) => onClick(e)}
|
|
548
|
-
>
|
|
549
|
-
{(state: any, childrenProps: any) => {
|
|
550
|
-
const label = labelForState(state);
|
|
551
|
-
return <button {...childrenProps}>{label}</button>;
|
|
552
|
-
}}
|
|
553
|
-
</ClickableBehavior>,
|
|
554
|
-
);
|
|
555
|
-
const button = await screen.findByRole("button");
|
|
556
|
-
await userEvent.tab(); // focus
|
|
557
|
-
await userEvent.hover(button);
|
|
558
|
-
|
|
559
|
-
rerender(
|
|
560
|
-
<ClickableBehavior disabled={true} onClick={(e: any) => onClick(e)}>
|
|
561
|
-
{(state: any, childrenProps: any) => {
|
|
562
|
-
const label = labelForState(state);
|
|
563
|
-
return <button {...childrenProps}>{label}</button>;
|
|
564
|
-
}}
|
|
565
|
-
</ClickableBehavior>,
|
|
566
|
-
);
|
|
567
|
-
|
|
568
|
-
expect(button).not.toHaveTextContent("pressed");
|
|
569
|
-
expect(button).not.toHaveTextContent("hovered");
|
|
570
|
-
|
|
571
|
-
// The button remains focused even after it's been disabled
|
|
572
|
-
expect(button).toHaveTextContent("focused");
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
describe("full page load navigation", () => {
|
|
576
|
-
it("both navigates and calls onClick for an anchor link", async () => {
|
|
577
|
-
const onClick = jest.fn();
|
|
578
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
579
|
-
render(
|
|
580
|
-
<ClickableBehavior
|
|
581
|
-
href="https://khanacademy.org/"
|
|
582
|
-
onClick={(e: any) => onClick(e)}
|
|
583
|
-
role="link"
|
|
584
|
-
>
|
|
585
|
-
{(state: any, childrenProps: any) => {
|
|
586
|
-
// The base element here doesn't matter in this testing
|
|
587
|
-
// environment, but the simulated events in the test are in
|
|
588
|
-
// line with what browsers do for this element.
|
|
589
|
-
return (
|
|
590
|
-
<a
|
|
591
|
-
href="https://khanacademy.org/"
|
|
592
|
-
{...childrenProps}
|
|
593
|
-
>
|
|
594
|
-
Label
|
|
595
|
-
</a>
|
|
596
|
-
);
|
|
597
|
-
}}
|
|
598
|
-
</ClickableBehavior>,
|
|
599
|
-
);
|
|
600
|
-
const link = await screen.findByRole("link");
|
|
601
|
-
|
|
602
|
-
// Space press should not trigger the onClick
|
|
603
|
-
fireEvent.keyDown(link, {keyCode: keyCodes.space});
|
|
604
|
-
fireEvent.keyUp(link, {keyCode: keyCodes.space});
|
|
605
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
606
|
-
|
|
607
|
-
// Navigation didn't happen with space
|
|
608
|
-
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
|
609
|
-
|
|
610
|
-
// Enter press should trigger the onClick after keyup
|
|
611
|
-
fireEvent.keyDown(link, {keyCode: keyCodes.enter});
|
|
612
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
613
|
-
|
|
614
|
-
// Navigation doesn't happen until after enter is released
|
|
615
|
-
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
|
616
|
-
|
|
617
|
-
fireEvent.keyUp(link, {keyCode: keyCodes.enter});
|
|
618
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
619
|
-
|
|
620
|
-
// Navigation happened after enter click
|
|
621
|
-
expect(window.location.assign).toHaveBeenCalledTimes(1);
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
it("waits for safeWithNav to resolve before navigation", async () => {
|
|
625
|
-
// Arrange
|
|
626
|
-
render(
|
|
627
|
-
<ClickableBehavior
|
|
628
|
-
href="https://khanacademy.org/"
|
|
629
|
-
safeWithNav={() => Promise.resolve()}
|
|
630
|
-
role="link"
|
|
631
|
-
>
|
|
632
|
-
{(state: any, childrenProps: any) => {
|
|
633
|
-
// The base element here doesn't matter in this testing
|
|
634
|
-
// environment, but the simulated events in the test are in
|
|
635
|
-
// line with what browsers do for this element.
|
|
636
|
-
return (
|
|
637
|
-
<a
|
|
638
|
-
href="https://khanacademy.org/"
|
|
639
|
-
{...childrenProps}
|
|
640
|
-
>
|
|
641
|
-
Label
|
|
642
|
-
</a>
|
|
643
|
-
);
|
|
644
|
-
}}
|
|
645
|
-
</ClickableBehavior>,
|
|
646
|
-
);
|
|
647
|
-
|
|
648
|
-
// Act
|
|
649
|
-
const link = await screen.findByRole("link");
|
|
650
|
-
await userEvent.click(link);
|
|
651
|
-
|
|
652
|
-
// Assert
|
|
653
|
-
await waitFor(() => {
|
|
654
|
-
expect(window.location.assign).toHaveBeenCalledTimes(1);
|
|
655
|
-
});
|
|
656
|
-
});
|
|
657
|
-
|
|
658
|
-
it("should show waiting UI before safeWithNav resolves", async () => {
|
|
659
|
-
// Arrange
|
|
660
|
-
render(
|
|
661
|
-
<ClickableBehavior
|
|
662
|
-
href="https://khanacademy.org/"
|
|
663
|
-
safeWithNav={() => Promise.resolve()}
|
|
664
|
-
role="link"
|
|
665
|
-
>
|
|
666
|
-
{(state: any, childrenProps: any) => {
|
|
667
|
-
// The base element here doesn't matter in this testing
|
|
668
|
-
// environment, but the simulated events in the test are in
|
|
669
|
-
// line with what browsers do for this element.
|
|
670
|
-
return (
|
|
671
|
-
<a
|
|
672
|
-
href="https://khanacademy.org/"
|
|
673
|
-
{...childrenProps}
|
|
674
|
-
>
|
|
675
|
-
{state.waiting ? "waiting" : "Label"}
|
|
676
|
-
</a>
|
|
677
|
-
);
|
|
678
|
-
}}
|
|
679
|
-
</ClickableBehavior>,
|
|
680
|
-
);
|
|
681
|
-
|
|
682
|
-
// Act
|
|
683
|
-
const link = await screen.findByRole("link");
|
|
684
|
-
await userEvent.click(link);
|
|
685
|
-
|
|
686
|
-
// Assert
|
|
687
|
-
expect(link).toHaveTextContent("waiting");
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
it("If onClick calls e.preventDefault() then we won't navigate", async () => {
|
|
691
|
-
// Arrange
|
|
692
|
-
render(
|
|
693
|
-
<ClickableBehavior
|
|
694
|
-
href="/foo"
|
|
695
|
-
onClick={(e: any) => e.preventDefault()}
|
|
696
|
-
role="checkbox"
|
|
697
|
-
>
|
|
698
|
-
{(state: any, childrenProps: any) => {
|
|
699
|
-
// The base element here doesn't matter in this testing
|
|
700
|
-
// environment, but the simulated events in the test are in
|
|
701
|
-
// line with what browsers do for this element.
|
|
702
|
-
return <button {...childrenProps}>label</button>;
|
|
703
|
-
}}
|
|
704
|
-
</ClickableBehavior>,
|
|
705
|
-
);
|
|
706
|
-
|
|
707
|
-
// Act
|
|
708
|
-
const button = await screen.findByRole("button");
|
|
709
|
-
await userEvent.click(button);
|
|
710
|
-
|
|
711
|
-
// Assert
|
|
712
|
-
expect(window.location.assign).not.toHaveBeenCalled();
|
|
713
|
-
});
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
it("calls onClick correctly for a component that doesn't respond to enter", async () => {
|
|
717
|
-
const onClick = jest.fn();
|
|
718
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
719
|
-
render(
|
|
720
|
-
// triggerOnEnter may be false for some elements e.g. checkboxes
|
|
721
|
-
<ClickableBehavior onClick={(e: any) => onClick(e)} role="checkbox">
|
|
722
|
-
{(state: any, childrenProps: any) => {
|
|
723
|
-
// The base element here doesn't matter in this testing
|
|
724
|
-
// environment, but the simulated events in the test are in
|
|
725
|
-
// line with what browsers do for this element.
|
|
726
|
-
return <input type="checkbox" {...childrenProps} />;
|
|
727
|
-
}}
|
|
728
|
-
</ClickableBehavior>,
|
|
729
|
-
);
|
|
730
|
-
|
|
731
|
-
// Enter press should not do anything
|
|
732
|
-
const checkbox = await screen.findByRole("checkbox");
|
|
733
|
-
fireEvent.keyDown(checkbox, {keyCode: keyCodes.enter});
|
|
734
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
735
|
-
fireEvent.keyUp(checkbox, {keyCode: keyCodes.enter});
|
|
736
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
737
|
-
|
|
738
|
-
// Space press should trigger the onClick
|
|
739
|
-
fireEvent.keyDown(checkbox, {keyCode: keyCodes.space});
|
|
740
|
-
fireEvent.keyUp(checkbox, {keyCode: keyCodes.space});
|
|
741
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
it("calls onClick for a button component on both enter/space", async () => {
|
|
745
|
-
const onClick = jest.fn();
|
|
746
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
747
|
-
render(
|
|
748
|
-
<ClickableBehavior onClick={(e: any) => onClick(e)}>
|
|
749
|
-
{(state: any, childrenProps: any) => {
|
|
750
|
-
// The base element here doesn't matter in this testing
|
|
751
|
-
// environment, but the simulated events in the test are in
|
|
752
|
-
// line with what browsers do for this element.
|
|
753
|
-
return <button {...childrenProps}>Label</button>;
|
|
754
|
-
}}
|
|
755
|
-
</ClickableBehavior>,
|
|
756
|
-
);
|
|
757
|
-
|
|
758
|
-
// Enter press
|
|
759
|
-
const button = await screen.findByRole("button");
|
|
760
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
761
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
762
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
763
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
764
|
-
|
|
765
|
-
// Space press
|
|
766
|
-
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
767
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
768
|
-
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
769
|
-
expect(onClick).toHaveBeenCalledTimes(2);
|
|
770
|
-
});
|
|
771
|
-
|
|
772
|
-
// This tests the case where we attach the childrenProps to an element that is
|
|
773
|
-
// not canonically clickable (like a div). The browser doesn't naturally
|
|
774
|
-
// trigger keyboard click events for such an element.
|
|
775
|
-
it("calls onClick listener on space/enter with a non-usually clickable element", async () => {
|
|
776
|
-
const onClick = jest.fn();
|
|
777
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
778
|
-
const {container} = render(
|
|
779
|
-
<ClickableBehavior onClick={(e: any) => onClick(e)}>
|
|
780
|
-
{(state: any, childrenProps: any) => {
|
|
781
|
-
// The base element here doesn't matter in this testing
|
|
782
|
-
// environment, but the simulated events in the test are in
|
|
783
|
-
// line with what browsers do for this element.
|
|
784
|
-
return <div {...childrenProps}>Label</div>;
|
|
785
|
-
}}
|
|
786
|
-
</ClickableBehavior>,
|
|
787
|
-
);
|
|
788
|
-
|
|
789
|
-
let expectedNumberTimesCalled = 0;
|
|
790
|
-
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container
|
|
791
|
-
const clickableDiv = container.querySelector("div");
|
|
792
|
-
if (!clickableDiv) {
|
|
793
|
-
throw new Error("couldn't find clickable div");
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Enter press on a div
|
|
797
|
-
fireEvent.keyDown(clickableDiv, {keyCode: keyCodes.enter});
|
|
798
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
799
|
-
fireEvent.keyUp(clickableDiv, {
|
|
800
|
-
keyCode: keyCodes.enter,
|
|
801
|
-
});
|
|
802
|
-
expectedNumberTimesCalled += 1;
|
|
803
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
804
|
-
|
|
805
|
-
// Simulate a mouse click.
|
|
806
|
-
await userEvent.click(clickableDiv);
|
|
807
|
-
expectedNumberTimesCalled += 1;
|
|
808
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
809
|
-
|
|
810
|
-
// Space press on a div
|
|
811
|
-
fireEvent.keyDown(clickableDiv, {keyCode: keyCodes.space});
|
|
812
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
813
|
-
fireEvent.keyUp(clickableDiv, {keyCode: keyCodes.space});
|
|
814
|
-
expectedNumberTimesCalled += 1;
|
|
815
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
816
|
-
|
|
817
|
-
// Simulate another mouse click.
|
|
818
|
-
await userEvent.click(clickableDiv);
|
|
819
|
-
expectedNumberTimesCalled += 1;
|
|
820
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
821
|
-
});
|
|
822
|
-
|
|
823
|
-
// The following two tests involve click behavior when dragging.
|
|
824
|
-
// Here are some notable related actions that cannot be tested using
|
|
825
|
-
// existing jest/RTL events since these click types are handled
|
|
826
|
-
// by browsers but aren't registered as clicks by RTL/jest:
|
|
827
|
-
// 1. Mousedown in the button, drag within the button, and mouseup
|
|
828
|
-
// in the button (mouse doesn't leave the button at any point).
|
|
829
|
-
// This should result in a successful click.
|
|
830
|
-
// 2. Mouse down in the button, drag out of the button (don't let go),
|
|
831
|
-
// drag back into the button, and mouseup inside the button.
|
|
832
|
-
// This should result in a successful click.
|
|
833
|
-
it("does not call onClick on mouseup when the mouse presses inside and drags away", async () => {
|
|
834
|
-
const onClick = jest.fn();
|
|
835
|
-
render(
|
|
836
|
-
<ClickableBehavior
|
|
837
|
-
disabled={false}
|
|
838
|
-
onClick={(e: any) => onClick(e)}
|
|
839
|
-
>
|
|
840
|
-
{(state: any, childrenProps: any) => {
|
|
841
|
-
return <button {...childrenProps}>Label</button>;
|
|
842
|
-
}}
|
|
843
|
-
</ClickableBehavior>,
|
|
844
|
-
);
|
|
845
|
-
|
|
846
|
-
const button = await screen.findByRole("button");
|
|
847
|
-
fireEvent.mouseDown(button);
|
|
848
|
-
fireEvent.mouseLeave(button);
|
|
849
|
-
fireEvent.mouseUp(button);
|
|
850
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
851
|
-
});
|
|
852
|
-
|
|
853
|
-
it("does not call onClick on mouseup when the mouse presses outside and drags in", async () => {
|
|
854
|
-
const onClick = jest.fn();
|
|
855
|
-
render(
|
|
856
|
-
<ClickableBehavior
|
|
857
|
-
disabled={false}
|
|
858
|
-
onClick={(e: any) => onClick(e)}
|
|
859
|
-
>
|
|
860
|
-
{(state: any, childrenProps: any) => {
|
|
861
|
-
return <button {...childrenProps}>Label</button>;
|
|
862
|
-
}}
|
|
863
|
-
</ClickableBehavior>,
|
|
864
|
-
);
|
|
865
|
-
|
|
866
|
-
const button = await screen.findByRole("button");
|
|
867
|
-
fireEvent.mouseEnter(button, {buttons: 1});
|
|
868
|
-
fireEvent.mouseUp(button);
|
|
869
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
870
|
-
});
|
|
871
|
-
|
|
872
|
-
it("doesn't trigger enter key when browser doesn't stop the click", async () => {
|
|
873
|
-
const onClick = jest.fn();
|
|
874
|
-
// Use mount instead of a shallow render to trigger event defaults
|
|
875
|
-
render(
|
|
876
|
-
<ClickableBehavior onClick={(e: any) => onClick(e)} role="checkbox">
|
|
877
|
-
{(state: any, childrenProps: any) => {
|
|
878
|
-
// The base element here doesn't matter in this testing
|
|
879
|
-
// environment, but the simulated events in the test are in
|
|
880
|
-
// line with what browsers do for this element.
|
|
881
|
-
return <input type="checkbox" {...childrenProps} />;
|
|
882
|
-
}}
|
|
883
|
-
</ClickableBehavior>,
|
|
884
|
-
);
|
|
885
|
-
|
|
886
|
-
const checkbox = await screen.findByRole("checkbox");
|
|
887
|
-
// Enter press should not do anything
|
|
888
|
-
fireEvent.keyDown(checkbox, {keyCode: keyCodes.enter});
|
|
889
|
-
// This element still wants to have a click on enter press
|
|
890
|
-
fireEvent.click(checkbox);
|
|
891
|
-
fireEvent.keyUp(checkbox, {keyCode: keyCodes.enter});
|
|
892
|
-
expect(onClick).toHaveBeenCalledTimes(0);
|
|
893
|
-
});
|
|
894
|
-
|
|
895
|
-
describe("client-side navgiation", () => {
|
|
896
|
-
const ClickableBehaviorWithRouter = getClickableBehavior(
|
|
897
|
-
"/foo",
|
|
898
|
-
false,
|
|
899
|
-
true, // router
|
|
900
|
-
);
|
|
901
|
-
|
|
902
|
-
it("handles client-side navigation when there's a router context", async () => {
|
|
903
|
-
// Arrange
|
|
904
|
-
render(
|
|
905
|
-
<MemoryRouter>
|
|
906
|
-
<div>
|
|
907
|
-
<ClickableBehaviorWithRouter
|
|
908
|
-
href="/foo"
|
|
909
|
-
onClick={(e: any) => {}}
|
|
910
|
-
role="checkbox"
|
|
911
|
-
>
|
|
912
|
-
{(state: any, childrenProps: any) => {
|
|
913
|
-
// The base element here doesn't matter in this testing
|
|
914
|
-
// environment, but the simulated events in the test are in
|
|
915
|
-
// line with what browsers do for this element.
|
|
916
|
-
return (
|
|
917
|
-
<button {...childrenProps}>label</button>
|
|
918
|
-
);
|
|
919
|
-
}}
|
|
920
|
-
</ClickableBehaviorWithRouter>
|
|
921
|
-
<Switch>
|
|
922
|
-
<Route path="/foo">
|
|
923
|
-
<div>Hello, world!</div>
|
|
924
|
-
</Route>
|
|
925
|
-
</Switch>
|
|
926
|
-
</div>
|
|
927
|
-
</MemoryRouter>,
|
|
928
|
-
);
|
|
929
|
-
|
|
930
|
-
// Act
|
|
931
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
932
|
-
|
|
933
|
-
// Assert
|
|
934
|
-
expect(
|
|
935
|
-
await screen.findByText("Hello, world!"),
|
|
936
|
-
).toBeInTheDocument();
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
describe("beforeNav", () => {
|
|
940
|
-
it("waits for beforeNav to resolve before client-side navigating", async () => {
|
|
941
|
-
// Arrange
|
|
942
|
-
render(
|
|
943
|
-
<MemoryRouter>
|
|
944
|
-
<div>
|
|
945
|
-
<ClickableBehaviorWithRouter
|
|
946
|
-
href="/foo"
|
|
947
|
-
onClick={(e: any) => {}}
|
|
948
|
-
role="checkbox"
|
|
949
|
-
beforeNav={() => Promise.resolve()}
|
|
950
|
-
>
|
|
951
|
-
{(state: any, childrenProps: any) => {
|
|
952
|
-
// The base element here doesn't matter in this testing
|
|
953
|
-
// environment, but the simulated events in the test are in
|
|
954
|
-
// line with what browsers do for this element.
|
|
955
|
-
return (
|
|
956
|
-
<button {...childrenProps}>
|
|
957
|
-
{state.waiting
|
|
958
|
-
? "waiting"
|
|
959
|
-
: "label"}
|
|
960
|
-
</button>
|
|
961
|
-
);
|
|
962
|
-
}}
|
|
963
|
-
</ClickableBehaviorWithRouter>
|
|
964
|
-
<Switch>
|
|
965
|
-
<Route path="/foo">
|
|
966
|
-
<div>Hello, world!</div>
|
|
967
|
-
</Route>
|
|
968
|
-
</Switch>
|
|
969
|
-
</div>
|
|
970
|
-
</MemoryRouter>,
|
|
971
|
-
);
|
|
972
|
-
|
|
973
|
-
// Act
|
|
974
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
975
|
-
|
|
976
|
-
// Assert
|
|
977
|
-
await waitFor(async () => {
|
|
978
|
-
expect(
|
|
979
|
-
await screen.findByText("Hello, world!"),
|
|
980
|
-
).toBeInTheDocument();
|
|
981
|
-
});
|
|
982
|
-
});
|
|
983
|
-
|
|
984
|
-
// NOTE(john): This no longer works after upgrading to user-event v14.
|
|
985
|
-
// The wait state is resolved before we can confirm that it's rendered.
|
|
986
|
-
it.skip("shows waiting state before navigating", async () => {
|
|
987
|
-
// Arrange
|
|
988
|
-
render(
|
|
989
|
-
<MemoryRouter>
|
|
990
|
-
<div>
|
|
991
|
-
<ClickableBehaviorWithRouter
|
|
992
|
-
href="/foo"
|
|
993
|
-
onClick={(e: any) => {}}
|
|
994
|
-
role="checkbox"
|
|
995
|
-
beforeNav={() => Promise.resolve()}
|
|
996
|
-
>
|
|
997
|
-
{(state: any, childrenProps: any) => {
|
|
998
|
-
// The base element here doesn't matter in this testing
|
|
999
|
-
// environment, but the simulated events in the test are in
|
|
1000
|
-
// line with what browsers do for this element.
|
|
1001
|
-
return (
|
|
1002
|
-
<button {...childrenProps}>
|
|
1003
|
-
{state.waiting
|
|
1004
|
-
? "waiting"
|
|
1005
|
-
: "label"}
|
|
1006
|
-
</button>
|
|
1007
|
-
);
|
|
1008
|
-
}}
|
|
1009
|
-
</ClickableBehaviorWithRouter>
|
|
1010
|
-
<Switch>
|
|
1011
|
-
<Route path="/foo">
|
|
1012
|
-
<div>Hello, world!</div>
|
|
1013
|
-
</Route>
|
|
1014
|
-
</Switch>
|
|
1015
|
-
</div>
|
|
1016
|
-
</MemoryRouter>,
|
|
1017
|
-
);
|
|
1018
|
-
|
|
1019
|
-
// Act
|
|
1020
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
1021
|
-
|
|
1022
|
-
// Assert
|
|
1023
|
-
expect(await screen.findByText("waiting")).toBeInTheDocument();
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
it("does not navigate if beforeNav rejects", async () => {
|
|
1027
|
-
// Arrange
|
|
1028
|
-
render(
|
|
1029
|
-
<MemoryRouter>
|
|
1030
|
-
<div>
|
|
1031
|
-
<ClickableBehaviorWithRouter
|
|
1032
|
-
href="/foo"
|
|
1033
|
-
onClick={(e: any) => {}}
|
|
1034
|
-
role="checkbox"
|
|
1035
|
-
beforeNav={() => Promise.reject()}
|
|
1036
|
-
>
|
|
1037
|
-
{(state: any, childrenProps: any) => {
|
|
1038
|
-
// The base element here doesn't matter in this testing
|
|
1039
|
-
// environment, but the simulated events in the test are in
|
|
1040
|
-
// line with what browsers do for this element.
|
|
1041
|
-
return (
|
|
1042
|
-
<button {...childrenProps}>
|
|
1043
|
-
label
|
|
1044
|
-
</button>
|
|
1045
|
-
);
|
|
1046
|
-
}}
|
|
1047
|
-
</ClickableBehaviorWithRouter>
|
|
1048
|
-
<Switch>
|
|
1049
|
-
<Route path="/foo">
|
|
1050
|
-
<div>Hello, world!</div>
|
|
1051
|
-
</Route>
|
|
1052
|
-
</Switch>
|
|
1053
|
-
</div>
|
|
1054
|
-
</MemoryRouter>,
|
|
1055
|
-
);
|
|
1056
|
-
|
|
1057
|
-
// Act
|
|
1058
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
1059
|
-
|
|
1060
|
-
// Assert
|
|
1061
|
-
expect(
|
|
1062
|
-
screen.queryByText("Hello, world!"),
|
|
1063
|
-
).not.toBeInTheDocument();
|
|
1064
|
-
});
|
|
1065
|
-
|
|
1066
|
-
it("calls safeWithNav if provided if beforeNav resolves", async () => {
|
|
1067
|
-
// Arrange
|
|
1068
|
-
const safeWithNavMock = jest.fn();
|
|
1069
|
-
render(
|
|
1070
|
-
<MemoryRouter>
|
|
1071
|
-
<div>
|
|
1072
|
-
<ClickableBehaviorWithRouter
|
|
1073
|
-
href="/foo"
|
|
1074
|
-
onClick={(e: any) => {}}
|
|
1075
|
-
role="checkbox"
|
|
1076
|
-
beforeNav={() => Promise.resolve()}
|
|
1077
|
-
safeWithNav={safeWithNavMock}
|
|
1078
|
-
>
|
|
1079
|
-
{(state: any, childrenProps: any) => {
|
|
1080
|
-
// The base element here doesn't matter in this testing
|
|
1081
|
-
// environment, but the simulated events in the test are in
|
|
1082
|
-
// line with what browsers do for this element.
|
|
1083
|
-
return (
|
|
1084
|
-
<button {...childrenProps}>
|
|
1085
|
-
{state.waiting
|
|
1086
|
-
? "waiting"
|
|
1087
|
-
: "label"}
|
|
1088
|
-
</button>
|
|
1089
|
-
);
|
|
1090
|
-
}}
|
|
1091
|
-
</ClickableBehaviorWithRouter>
|
|
1092
|
-
<Switch>
|
|
1093
|
-
<Route path="/foo">
|
|
1094
|
-
<div>Hello, world!</div>
|
|
1095
|
-
</Route>
|
|
1096
|
-
</Switch>
|
|
1097
|
-
</div>
|
|
1098
|
-
</MemoryRouter>,
|
|
1099
|
-
);
|
|
1100
|
-
|
|
1101
|
-
// Act
|
|
1102
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
1103
|
-
|
|
1104
|
-
// Assert
|
|
1105
|
-
await waitFor(() => {
|
|
1106
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
1107
|
-
});
|
|
1108
|
-
});
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
it("doesn't wait for safeWithNav to resolve before client-side navigating", async () => {
|
|
1112
|
-
// Arrange
|
|
1113
|
-
render(
|
|
1114
|
-
<MemoryRouter>
|
|
1115
|
-
<div>
|
|
1116
|
-
<ClickableBehaviorWithRouter
|
|
1117
|
-
href="/foo"
|
|
1118
|
-
onClick={(e: any) => {}}
|
|
1119
|
-
role="checkbox"
|
|
1120
|
-
safeWithNav={() => Promise.resolve()}
|
|
1121
|
-
>
|
|
1122
|
-
{(state: any, childrenProps: any) => {
|
|
1123
|
-
// The base element here doesn't matter in this testing
|
|
1124
|
-
// environment, but the simulated events in the test are in
|
|
1125
|
-
// line with what browsers do for this element.
|
|
1126
|
-
return (
|
|
1127
|
-
<button {...childrenProps}>label</button>
|
|
1128
|
-
);
|
|
1129
|
-
}}
|
|
1130
|
-
</ClickableBehaviorWithRouter>
|
|
1131
|
-
<Switch>
|
|
1132
|
-
<Route path="/foo">
|
|
1133
|
-
<div>Hello, world!</div>
|
|
1134
|
-
</Route>
|
|
1135
|
-
</Switch>
|
|
1136
|
-
</div>
|
|
1137
|
-
</MemoryRouter>,
|
|
1138
|
-
);
|
|
1139
|
-
|
|
1140
|
-
// Act
|
|
1141
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
1142
|
-
|
|
1143
|
-
// Assert
|
|
1144
|
-
expect(
|
|
1145
|
-
await screen.findByText("Hello, world!"),
|
|
1146
|
-
).toBeInTheDocument();
|
|
1147
|
-
});
|
|
1148
|
-
|
|
1149
|
-
it("If onClick calls e.preventDefault() then we won't navigate", async () => {
|
|
1150
|
-
// Arrange
|
|
1151
|
-
render(
|
|
1152
|
-
<MemoryRouter>
|
|
1153
|
-
<div>
|
|
1154
|
-
<ClickableBehaviorWithRouter
|
|
1155
|
-
href="/foo"
|
|
1156
|
-
onClick={(e: any) => e.preventDefault()}
|
|
1157
|
-
role="checkbox"
|
|
1158
|
-
>
|
|
1159
|
-
{(state: any, childrenProps: any) => {
|
|
1160
|
-
// The base element here doesn't matter in this testing
|
|
1161
|
-
// environment, but the simulated events in the test are in
|
|
1162
|
-
// line with what browsers do for this element.
|
|
1163
|
-
return (
|
|
1164
|
-
<button {...childrenProps}>label</button>
|
|
1165
|
-
);
|
|
1166
|
-
}}
|
|
1167
|
-
</ClickableBehaviorWithRouter>
|
|
1168
|
-
<Switch>
|
|
1169
|
-
<Route path="/foo">
|
|
1170
|
-
<div>Hello, world!</div>
|
|
1171
|
-
</Route>
|
|
1172
|
-
</Switch>
|
|
1173
|
-
</div>
|
|
1174
|
-
</MemoryRouter>,
|
|
1175
|
-
);
|
|
1176
|
-
|
|
1177
|
-
// Act
|
|
1178
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
1179
|
-
|
|
1180
|
-
// Assert
|
|
1181
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
1182
|
-
});
|
|
1183
|
-
});
|
|
1184
|
-
|
|
1185
|
-
describe("target='_blank'", () => {
|
|
1186
|
-
it("opens a new tab", async () => {
|
|
1187
|
-
// Arrange
|
|
1188
|
-
render(
|
|
1189
|
-
<ClickableBehavior
|
|
1190
|
-
disabled={false}
|
|
1191
|
-
href="https://www.khanacademy.org"
|
|
1192
|
-
role="link"
|
|
1193
|
-
target="_blank"
|
|
1194
|
-
>
|
|
1195
|
-
{(state: any, childrenProps: any) => {
|
|
1196
|
-
return (
|
|
1197
|
-
<a
|
|
1198
|
-
href="https://www.khanacademy.org"
|
|
1199
|
-
{...childrenProps}
|
|
1200
|
-
>
|
|
1201
|
-
Label
|
|
1202
|
-
</a>
|
|
1203
|
-
);
|
|
1204
|
-
}}
|
|
1205
|
-
</ClickableBehavior>,
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
// Act
|
|
1209
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1210
|
-
|
|
1211
|
-
// Assert
|
|
1212
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
1213
|
-
"https://www.khanacademy.org",
|
|
1214
|
-
"_blank",
|
|
1215
|
-
);
|
|
1216
|
-
});
|
|
1217
|
-
|
|
1218
|
-
it("opens a new tab when using 'safeWithNav'", async () => {
|
|
1219
|
-
// Arrange
|
|
1220
|
-
// @ts-expect-error [FEI-5019] - TS2554 - Expected 1 arguments, but got 0.
|
|
1221
|
-
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1222
|
-
render(
|
|
1223
|
-
<ClickableBehavior
|
|
1224
|
-
disabled={false}
|
|
1225
|
-
href="https://www.khanacademy.org"
|
|
1226
|
-
role="link"
|
|
1227
|
-
target="_blank"
|
|
1228
|
-
safeWithNav={safeWithNavMock}
|
|
1229
|
-
>
|
|
1230
|
-
{(state: any, childrenProps: any) => {
|
|
1231
|
-
return (
|
|
1232
|
-
<a
|
|
1233
|
-
href="https://www.khanacademy.org"
|
|
1234
|
-
{...childrenProps}
|
|
1235
|
-
>
|
|
1236
|
-
Label
|
|
1237
|
-
</a>
|
|
1238
|
-
);
|
|
1239
|
-
}}
|
|
1240
|
-
</ClickableBehavior>,
|
|
1241
|
-
);
|
|
1242
|
-
|
|
1243
|
-
// Act
|
|
1244
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1245
|
-
|
|
1246
|
-
// Assert
|
|
1247
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
1248
|
-
"https://www.khanacademy.org",
|
|
1249
|
-
"_blank",
|
|
1250
|
-
);
|
|
1251
|
-
});
|
|
1252
|
-
|
|
1253
|
-
it("calls 'safeWithNav'", async () => {
|
|
1254
|
-
// Arrange
|
|
1255
|
-
// @ts-expect-error [FEI-5019] - TS2554 - Expected 1 arguments, but got 0.
|
|
1256
|
-
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1257
|
-
render(
|
|
1258
|
-
<ClickableBehavior
|
|
1259
|
-
disabled={false}
|
|
1260
|
-
href="https://www.khanacademy.org"
|
|
1261
|
-
role="link"
|
|
1262
|
-
target="_blank"
|
|
1263
|
-
safeWithNav={safeWithNavMock}
|
|
1264
|
-
>
|
|
1265
|
-
{(state: any, childrenProps: any) => {
|
|
1266
|
-
return (
|
|
1267
|
-
<a
|
|
1268
|
-
href="https://www.khanacademy.org"
|
|
1269
|
-
{...childrenProps}
|
|
1270
|
-
>
|
|
1271
|
-
Label
|
|
1272
|
-
</a>
|
|
1273
|
-
);
|
|
1274
|
-
}}
|
|
1275
|
-
</ClickableBehavior>,
|
|
1276
|
-
);
|
|
1277
|
-
|
|
1278
|
-
// Act
|
|
1279
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1280
|
-
|
|
1281
|
-
// Assert
|
|
1282
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
1283
|
-
});
|
|
1284
|
-
|
|
1285
|
-
it("opens a new tab when inside a router", async () => {
|
|
1286
|
-
// Arrange
|
|
1287
|
-
render(
|
|
1288
|
-
<MemoryRouter initialEntries={["/"]}>
|
|
1289
|
-
<ClickableBehavior
|
|
1290
|
-
disabled={false}
|
|
1291
|
-
href="https://www.khanacademy.org"
|
|
1292
|
-
role="link"
|
|
1293
|
-
target="_blank"
|
|
1294
|
-
>
|
|
1295
|
-
{(state: any, childrenProps: any) => {
|
|
1296
|
-
return (
|
|
1297
|
-
<a
|
|
1298
|
-
href="https://www.khanacademy.org"
|
|
1299
|
-
{...childrenProps}
|
|
1300
|
-
>
|
|
1301
|
-
Label
|
|
1302
|
-
</a>
|
|
1303
|
-
);
|
|
1304
|
-
}}
|
|
1305
|
-
</ClickableBehavior>
|
|
1306
|
-
</MemoryRouter>,
|
|
1307
|
-
);
|
|
1308
|
-
|
|
1309
|
-
// Act
|
|
1310
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1311
|
-
|
|
1312
|
-
// Assert
|
|
1313
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
1314
|
-
"https://www.khanacademy.org",
|
|
1315
|
-
"_blank",
|
|
1316
|
-
);
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
|
-
it("opens a new tab when using 'safeWithNav' inside a router", async () => {
|
|
1320
|
-
// Arrange
|
|
1321
|
-
// @ts-expect-error [FEI-5019] - TS2554 - Expected 1 arguments, but got 0.
|
|
1322
|
-
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1323
|
-
render(
|
|
1324
|
-
<MemoryRouter initialEntries={["/"]}>
|
|
1325
|
-
<ClickableBehavior
|
|
1326
|
-
disabled={false}
|
|
1327
|
-
href="https://www.khanacademy.org"
|
|
1328
|
-
role="link"
|
|
1329
|
-
target="_blank"
|
|
1330
|
-
safeWithNav={safeWithNavMock}
|
|
1331
|
-
>
|
|
1332
|
-
{(state: any, childrenProps: any) => {
|
|
1333
|
-
return (
|
|
1334
|
-
<a
|
|
1335
|
-
href="https://www.khanacademy.org"
|
|
1336
|
-
{...childrenProps}
|
|
1337
|
-
>
|
|
1338
|
-
Label
|
|
1339
|
-
</a>
|
|
1340
|
-
);
|
|
1341
|
-
}}
|
|
1342
|
-
</ClickableBehavior>
|
|
1343
|
-
</MemoryRouter>,
|
|
1344
|
-
);
|
|
1345
|
-
|
|
1346
|
-
// Act
|
|
1347
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1348
|
-
|
|
1349
|
-
// Assert
|
|
1350
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
1351
|
-
"https://www.khanacademy.org",
|
|
1352
|
-
"_blank",
|
|
1353
|
-
);
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
it("calls 'safeWithNav' inside a router", async () => {
|
|
1357
|
-
// Arrange
|
|
1358
|
-
// @ts-expect-error [FEI-5019] - TS2554 - Expected 1 arguments, but got 0.
|
|
1359
|
-
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1360
|
-
render(
|
|
1361
|
-
<MemoryRouter initialEntries={["/"]}>
|
|
1362
|
-
<ClickableBehavior
|
|
1363
|
-
disabled={false}
|
|
1364
|
-
href="https://www.khanacademy.org"
|
|
1365
|
-
role="link"
|
|
1366
|
-
target="_blank"
|
|
1367
|
-
safeWithNav={safeWithNavMock}
|
|
1368
|
-
>
|
|
1369
|
-
{(state: any, childrenProps: any) => {
|
|
1370
|
-
return (
|
|
1371
|
-
<a
|
|
1372
|
-
href="https://www.khanacademy.org"
|
|
1373
|
-
{...childrenProps}
|
|
1374
|
-
>
|
|
1375
|
-
Label
|
|
1376
|
-
</a>
|
|
1377
|
-
);
|
|
1378
|
-
}}
|
|
1379
|
-
</ClickableBehavior>
|
|
1380
|
-
</MemoryRouter>,
|
|
1381
|
-
);
|
|
1382
|
-
|
|
1383
|
-
// Act
|
|
1384
|
-
await userEvent.click(await screen.findByRole("link"));
|
|
1385
|
-
|
|
1386
|
-
// Assert
|
|
1387
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
1388
|
-
});
|
|
1389
|
-
});
|
|
1390
|
-
|
|
1391
|
-
describe("rel", () => {
|
|
1392
|
-
it("should use the 'rel' that was passed in", async () => {
|
|
1393
|
-
// Arrange
|
|
1394
|
-
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1395
|
-
render(
|
|
1396
|
-
<ClickableBehavior
|
|
1397
|
-
href="https://www.khanacademy.org"
|
|
1398
|
-
rel="something_else"
|
|
1399
|
-
target="_blank"
|
|
1400
|
-
>
|
|
1401
|
-
{childrenMock}
|
|
1402
|
-
</ClickableBehavior>,
|
|
1403
|
-
);
|
|
1404
|
-
|
|
1405
|
-
const childrenProps = childrenMock.mock.calls[0][1];
|
|
1406
|
-
expect(childrenProps.rel).toEqual("something_else");
|
|
1407
|
-
});
|
|
1408
|
-
|
|
1409
|
-
it("should use 'noopener noreferrer' as a default when target='_blank'", async () => {
|
|
1410
|
-
// Arrange
|
|
1411
|
-
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1412
|
-
render(
|
|
1413
|
-
<ClickableBehavior
|
|
1414
|
-
href="https://www.khanacademy.org"
|
|
1415
|
-
target="_blank"
|
|
1416
|
-
>
|
|
1417
|
-
{childrenMock}
|
|
1418
|
-
</ClickableBehavior>,
|
|
1419
|
-
);
|
|
1420
|
-
|
|
1421
|
-
const childrenProps = childrenMock.mock.calls[0][1];
|
|
1422
|
-
expect(childrenProps.rel).toEqual("noopener noreferrer");
|
|
1423
|
-
});
|
|
1424
|
-
|
|
1425
|
-
it("should not use the default if target != '_blank'", async () => {
|
|
1426
|
-
// Arrange
|
|
1427
|
-
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1428
|
-
render(
|
|
1429
|
-
<ClickableBehavior href="https://www.khanacademy.org">
|
|
1430
|
-
{childrenMock}
|
|
1431
|
-
</ClickableBehavior>,
|
|
1432
|
-
);
|
|
1433
|
-
|
|
1434
|
-
const childrenProps = childrenMock.mock.calls[0][1];
|
|
1435
|
-
expect(childrenProps.rel).toBeUndefined();
|
|
1436
|
-
});
|
|
1437
|
-
});
|
|
1438
|
-
});
|