@khanacademy/wonder-blocks-clickable 2.3.1 → 2.3.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 +13 -0
- package/dist/es/index.js +1 -2
- package/dist/index.js +1 -2
- package/docs.md +4 -6
- package/package.json +2 -2
- package/src/components/__tests__/clickable-behavior.test.js +312 -374
- package/src/components/__tests__/clickable.test.js +113 -103
- package/src/components/clickable.js +0 -2
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -426
- package/src/__tests__/generated-snapshot.test.js +0 -176
- package/src/components/clickable.md +0 -203
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
/* eslint-disable testing-library/prefer-user-event */
|
|
1
2
|
/* eslint-disable max-lines */
|
|
2
3
|
// @flow
|
|
3
4
|
import * as React from "react";
|
|
4
|
-
import {render, screen} from "@testing-library/react";
|
|
5
|
+
import {render, screen, fireEvent} from "@testing-library/react";
|
|
5
6
|
import {MemoryRouter, Switch, Route} from "react-router-dom";
|
|
6
|
-
import
|
|
7
|
-
import "jest-enzyme";
|
|
7
|
+
import userEvent from "@testing-library/user-event";
|
|
8
8
|
|
|
9
9
|
import getClickableBehavior from "../../util/get-clickable-behavior.js";
|
|
10
10
|
import ClickableBehavior from "../clickable-behavior.js";
|
|
11
|
+
import type {ClickableState} from "../clickable-behavior";
|
|
11
12
|
|
|
12
13
|
const keyCodes = {
|
|
13
14
|
tab: 9,
|
|
@@ -21,6 +22,20 @@ const wait = (delay: number = 0) =>
|
|
|
21
22
|
return setTimeout(resolve, delay);
|
|
22
23
|
});
|
|
23
24
|
|
|
25
|
+
const labelForState = (state: ClickableState): string => {
|
|
26
|
+
const labels = [];
|
|
27
|
+
if (state.hovered) {
|
|
28
|
+
labels.push("hovered");
|
|
29
|
+
}
|
|
30
|
+
if (state.focused) {
|
|
31
|
+
labels.push("focused");
|
|
32
|
+
}
|
|
33
|
+
if (state.pressed) {
|
|
34
|
+
labels.push("pressed");
|
|
35
|
+
}
|
|
36
|
+
return labels.join(" ");
|
|
37
|
+
};
|
|
38
|
+
|
|
24
39
|
describe("ClickableBehavior", () => {
|
|
25
40
|
beforeEach(() => {
|
|
26
41
|
// Note: window.location.assign and window.open need mock functions in
|
|
@@ -37,7 +52,7 @@ describe("ClickableBehavior", () => {
|
|
|
37
52
|
|
|
38
53
|
it("renders a label", () => {
|
|
39
54
|
const onClick = jest.fn();
|
|
40
|
-
|
|
55
|
+
render(
|
|
41
56
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
42
57
|
{(state, childrenProps) => {
|
|
43
58
|
return <button {...childrenProps}>Label</button>;
|
|
@@ -45,176 +60,165 @@ describe("ClickableBehavior", () => {
|
|
|
45
60
|
</ClickableBehavior>,
|
|
46
61
|
);
|
|
47
62
|
expect(onClick).not.toHaveBeenCalled();
|
|
48
|
-
|
|
63
|
+
userEvent.click(screen.getByRole("button"));
|
|
49
64
|
expect(onClick).toHaveBeenCalled();
|
|
50
65
|
});
|
|
51
66
|
|
|
52
67
|
it("changes only hovered state on mouse enter/leave", () => {
|
|
53
68
|
const onClick = jest.fn();
|
|
54
|
-
|
|
69
|
+
render(
|
|
55
70
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
56
71
|
{(state, childrenProps) => {
|
|
57
|
-
|
|
72
|
+
const label = labelForState(state);
|
|
73
|
+
return <button {...childrenProps}>{label}</button>;
|
|
58
74
|
}}
|
|
59
75
|
</ClickableBehavior>,
|
|
60
76
|
);
|
|
61
|
-
|
|
62
|
-
button.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
button.
|
|
67
|
-
expect(button.state("hovered")).toEqual(false);
|
|
77
|
+
const button = screen.getByRole("button");
|
|
78
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
79
|
+
userEvent.hover(button);
|
|
80
|
+
expect(button).toHaveTextContent("hovered");
|
|
81
|
+
userEvent.unhover(button);
|
|
82
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
68
83
|
});
|
|
69
84
|
|
|
70
85
|
it("changes only pressed state on mouse enter/leave while dragging", () => {
|
|
71
86
|
const onClick = jest.fn();
|
|
72
|
-
|
|
87
|
+
render(
|
|
73
88
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
74
89
|
{(state, childrenProps) => {
|
|
75
|
-
|
|
90
|
+
const label = labelForState(state);
|
|
91
|
+
return <button {...childrenProps}>{label}</button>;
|
|
76
92
|
}}
|
|
77
93
|
</ClickableBehavior>,
|
|
78
94
|
);
|
|
79
|
-
|
|
95
|
+
const button = screen.getByRole("button");
|
|
96
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
80
97
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
fireEvent.mouseDown(button);
|
|
99
|
+
fireEvent.dragStart(button);
|
|
100
|
+
fireEvent.mouseMove(button);
|
|
101
|
+
expect(button).toHaveTextContent("pressed");
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
expect(button.
|
|
103
|
+
fireEvent.mouseLeave(button);
|
|
104
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
87
105
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
});
|
|
91
|
-
expect(button.state("pressed")).toEqual(true);
|
|
106
|
+
fireEvent.mouseEnter(button, {buttons: 1});
|
|
107
|
+
expect(button).toHaveTextContent("pressed");
|
|
92
108
|
});
|
|
93
109
|
|
|
94
110
|
it("changes pressed state on mouse down/up", () => {
|
|
95
111
|
const onClick = jest.fn();
|
|
96
|
-
|
|
112
|
+
render(
|
|
97
113
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
98
114
|
{(state, childrenProps) => {
|
|
99
|
-
|
|
115
|
+
const label = labelForState(state);
|
|
116
|
+
return <button {...childrenProps}>{label}</button>;
|
|
100
117
|
}}
|
|
101
118
|
</ClickableBehavior>,
|
|
102
119
|
);
|
|
103
|
-
|
|
104
|
-
button.
|
|
105
|
-
|
|
106
|
-
button.
|
|
107
|
-
|
|
120
|
+
const button = screen.getByRole("button");
|
|
121
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
122
|
+
fireEvent.mouseDown(button);
|
|
123
|
+
expect(button).toHaveTextContent("pressed");
|
|
124
|
+
fireEvent.mouseUp(button);
|
|
125
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
108
126
|
});
|
|
109
127
|
|
|
110
128
|
it("changes pressed state on touch start/end/cancel", () => {
|
|
111
129
|
const onClick = jest.fn();
|
|
112
|
-
|
|
130
|
+
render(
|
|
113
131
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
114
132
|
{(state, childrenProps) => {
|
|
115
|
-
|
|
133
|
+
const label = labelForState(state);
|
|
134
|
+
return <button {...childrenProps}>{label}</button>;
|
|
116
135
|
}}
|
|
117
136
|
</ClickableBehavior>,
|
|
118
137
|
);
|
|
119
|
-
|
|
120
|
-
button.
|
|
121
|
-
|
|
122
|
-
button.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
button.
|
|
127
|
-
|
|
128
|
-
button.
|
|
129
|
-
|
|
138
|
+
const button = screen.getByRole("button");
|
|
139
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
140
|
+
fireEvent.touchStart(button);
|
|
141
|
+
expect(button).toHaveTextContent("pressed");
|
|
142
|
+
fireEvent.touchEnd(button);
|
|
143
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
144
|
+
|
|
145
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
146
|
+
fireEvent.touchStart(button);
|
|
147
|
+
expect(button).toHaveTextContent("pressed");
|
|
148
|
+
fireEvent.touchCancel(button);
|
|
149
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
130
150
|
});
|
|
131
151
|
|
|
132
152
|
it("enters focused state on key press after click", () => {
|
|
133
153
|
const onClick = jest.fn();
|
|
134
|
-
|
|
154
|
+
render(
|
|
135
155
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
136
156
|
{(state, childrenProps) => {
|
|
137
|
-
|
|
157
|
+
const label = labelForState(state);
|
|
158
|
+
return <button {...childrenProps}>{label}</button>;
|
|
138
159
|
}}
|
|
139
160
|
</ClickableBehavior>,
|
|
140
161
|
);
|
|
141
|
-
|
|
142
|
-
button.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
151
|
-
expect(button.state("focused")).toEqual(true);
|
|
162
|
+
const button = screen.getByRole("button");
|
|
163
|
+
expect(button).not.toHaveTextContent("focused");
|
|
164
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
165
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
166
|
+
// NOTE(kevinb): userEvent.click() fires other events that we don't want
|
|
167
|
+
// affecting this test case.
|
|
168
|
+
fireEvent.click(button);
|
|
169
|
+
expect(button).toHaveTextContent("focused");
|
|
152
170
|
});
|
|
153
171
|
|
|
154
172
|
it("exits focused state on click after key press", () => {
|
|
155
173
|
const onClick = jest.fn();
|
|
156
174
|
|
|
157
|
-
|
|
175
|
+
render(
|
|
158
176
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
159
177
|
{(state, childrenProps) => {
|
|
160
|
-
|
|
178
|
+
const label = labelForState(state);
|
|
179
|
+
return <button {...childrenProps}>{label}</button>;
|
|
161
180
|
}}
|
|
162
181
|
</ClickableBehavior>,
|
|
163
182
|
);
|
|
164
|
-
|
|
165
|
-
button.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
button.
|
|
174
|
-
expect(button.state("focused")).toEqual(true);
|
|
175
|
-
button.simulate("mousedown");
|
|
176
|
-
button.simulate("mouseup");
|
|
177
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
178
|
-
expect(button.state("focused")).toEqual(false);
|
|
183
|
+
const button = screen.getByRole("button");
|
|
184
|
+
expect(button).not.toHaveTextContent("focused");
|
|
185
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
186
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
187
|
+
// NOTE(kevinb): userEvent.click() fires other events that we don't want
|
|
188
|
+
// affecting this test case.
|
|
189
|
+
fireEvent.click(button);
|
|
190
|
+
expect(button).toHaveTextContent("focused");
|
|
191
|
+
userEvent.click(button);
|
|
192
|
+
expect(button).not.toHaveTextContent("focused");
|
|
179
193
|
});
|
|
180
194
|
|
|
181
195
|
it("changes pressed state on space/enter key down/up if <button>", () => {
|
|
182
196
|
const onClick = jest.fn();
|
|
183
|
-
|
|
197
|
+
render(
|
|
184
198
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
185
199
|
{(state, childrenProps) => {
|
|
186
|
-
|
|
200
|
+
const label = labelForState(state);
|
|
201
|
+
return <button {...childrenProps}>{label}</button>;
|
|
187
202
|
}}
|
|
188
203
|
</ClickableBehavior>,
|
|
189
204
|
);
|
|
190
|
-
|
|
191
|
-
button.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
});
|
|
195
|
-
expect(button.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
});
|
|
200
|
-
expect(button.
|
|
201
|
-
|
|
202
|
-
button.simulate("keydown", {
|
|
203
|
-
keyCode: keyCodes.enter,
|
|
204
|
-
preventDefault: jest.fn(),
|
|
205
|
-
});
|
|
206
|
-
expect(button.state("pressed")).toEqual(true);
|
|
207
|
-
button.simulate("keyup", {
|
|
208
|
-
preventDefault: jest.fn(),
|
|
209
|
-
keyCode: keyCodes.enter,
|
|
210
|
-
});
|
|
211
|
-
expect(button.state("pressed")).toEqual(false);
|
|
205
|
+
const button = screen.getByRole("button");
|
|
206
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
207
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
208
|
+
expect(button).toHaveTextContent("pressed");
|
|
209
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
210
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
211
|
+
|
|
212
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
213
|
+
expect(button).toHaveTextContent("pressed");
|
|
214
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
215
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
212
216
|
});
|
|
213
217
|
|
|
214
218
|
it("changes pressed state on only enter key down/up for a link", () => {
|
|
215
219
|
const onClick = jest.fn();
|
|
216
220
|
// Use mount instead of a shallow render to trigger event defaults
|
|
217
|
-
|
|
221
|
+
render(
|
|
218
222
|
<ClickableBehavior
|
|
219
223
|
disabled={false}
|
|
220
224
|
onClick={(e) => onClick(e)}
|
|
@@ -222,59 +226,60 @@ describe("ClickableBehavior", () => {
|
|
|
222
226
|
role="link"
|
|
223
227
|
>
|
|
224
228
|
{(state, childrenProps) => {
|
|
229
|
+
const label = labelForState(state);
|
|
225
230
|
return (
|
|
226
231
|
<a
|
|
227
232
|
href="https://www.khanacademy.org"
|
|
228
233
|
{...childrenProps}
|
|
229
234
|
>
|
|
230
|
-
|
|
235
|
+
{label}
|
|
231
236
|
</a>
|
|
232
237
|
);
|
|
233
238
|
}}
|
|
234
239
|
</ClickableBehavior>,
|
|
235
240
|
);
|
|
236
|
-
|
|
237
|
-
link.
|
|
238
|
-
|
|
239
|
-
link.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
expect(link.
|
|
247
|
-
link.simulate("keyup", {
|
|
248
|
-
preventDefault: jest.fn(),
|
|
249
|
-
keyCode: keyCodes.space,
|
|
250
|
-
});
|
|
251
|
-
expect(link.state("pressed")).toEqual(false);
|
|
241
|
+
const link = screen.getByRole("link");
|
|
242
|
+
expect(link).not.toHaveTextContent("pressed");
|
|
243
|
+
fireEvent.keyDown(link, {keyCode: keyCodes.enter});
|
|
244
|
+
expect(link).toHaveTextContent("pressed");
|
|
245
|
+
fireEvent.keyUp(link, {keyCode: keyCodes.enter});
|
|
246
|
+
expect(link).not.toHaveTextContent("pressed");
|
|
247
|
+
|
|
248
|
+
fireEvent.keyDown(link, {keyCode: keyCodes.space});
|
|
249
|
+
expect(link).not.toHaveTextContent("pressed");
|
|
250
|
+
fireEvent.keyUp(link, {keyCode: keyCodes.space});
|
|
251
|
+
expect(link).not.toHaveTextContent("pressed");
|
|
252
252
|
});
|
|
253
253
|
|
|
254
254
|
it("gains focused state on focus event", () => {
|
|
255
255
|
const onClick = jest.fn();
|
|
256
|
-
|
|
256
|
+
render(
|
|
257
257
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
258
258
|
{(state, childrenProps) => {
|
|
259
|
-
|
|
259
|
+
const label = labelForState(state);
|
|
260
|
+
return <button {...childrenProps}>{label}</button>;
|
|
260
261
|
}}
|
|
261
262
|
</ClickableBehavior>,
|
|
262
263
|
);
|
|
263
|
-
button.
|
|
264
|
-
|
|
264
|
+
const button = screen.getByRole("button");
|
|
265
|
+
fireEvent.focus(button);
|
|
266
|
+
expect(button).toHaveTextContent("focused");
|
|
265
267
|
});
|
|
266
268
|
|
|
267
269
|
it("changes focused state on blur", () => {
|
|
268
270
|
const onClick = jest.fn();
|
|
269
|
-
|
|
271
|
+
render(
|
|
270
272
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
271
273
|
{(state, childrenProps) => {
|
|
272
|
-
|
|
274
|
+
const label = labelForState(state);
|
|
275
|
+
return <button {...childrenProps}>{label}</button>;
|
|
273
276
|
}}
|
|
274
277
|
</ClickableBehavior>,
|
|
275
278
|
);
|
|
276
|
-
button.
|
|
277
|
-
|
|
279
|
+
const button = screen.getByRole("button");
|
|
280
|
+
fireEvent.focus(button);
|
|
281
|
+
fireEvent.blur(button);
|
|
282
|
+
expect(button).not.toHaveTextContent("focused");
|
|
278
283
|
});
|
|
279
284
|
|
|
280
285
|
test("tabIndex should be 0", () => {
|
|
@@ -319,68 +324,64 @@ describe("ClickableBehavior", () => {
|
|
|
319
324
|
|
|
320
325
|
it("does not change state if disabled", () => {
|
|
321
326
|
const onClick = jest.fn();
|
|
322
|
-
|
|
327
|
+
render(
|
|
323
328
|
<ClickableBehavior disabled={true} onClick={(e) => onClick(e)}>
|
|
324
329
|
{(state, childrenProps) => {
|
|
325
|
-
|
|
330
|
+
const label = labelForState(state);
|
|
331
|
+
return <button {...childrenProps}>{label}</button>;
|
|
326
332
|
}}
|
|
327
333
|
</ClickableBehavior>,
|
|
328
334
|
);
|
|
329
335
|
|
|
336
|
+
const button = screen.getByRole("button");
|
|
330
337
|
expect(onClick).not.toHaveBeenCalled();
|
|
331
|
-
|
|
338
|
+
fireEvent.click(button);
|
|
332
339
|
expect(onClick).not.toHaveBeenCalled();
|
|
333
340
|
|
|
334
|
-
expect(button.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
expect(button.
|
|
339
|
-
|
|
340
|
-
expect(button.
|
|
341
|
-
|
|
342
|
-
expect(button.
|
|
343
|
-
|
|
344
|
-
expect(button.
|
|
345
|
-
|
|
346
|
-
expect(button.
|
|
347
|
-
|
|
348
|
-
expect(button.
|
|
349
|
-
|
|
350
|
-
expect(button.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
button.
|
|
355
|
-
|
|
356
|
-
expect(button.
|
|
357
|
-
|
|
358
|
-
expect(button.state("focused")).toEqual(false);
|
|
359
|
-
button.simulate("keyup", {
|
|
360
|
-
preventDefault: jest.fn(),
|
|
341
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
342
|
+
fireEvent.mouseEnter(button);
|
|
343
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
344
|
+
fireEvent.mouseLeave(button);
|
|
345
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
346
|
+
|
|
347
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
348
|
+
fireEvent.mouseDown(button);
|
|
349
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
350
|
+
fireEvent.mouseUp(button);
|
|
351
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
352
|
+
|
|
353
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
354
|
+
fireEvent.touchStart(button);
|
|
355
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
356
|
+
fireEvent.touchEnd(button);
|
|
357
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
358
|
+
|
|
359
|
+
fireEvent.touchStart(button);
|
|
360
|
+
fireEvent.touchCancel(button);
|
|
361
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
362
|
+
|
|
363
|
+
expect(button).not.toHaveTextContent("focused");
|
|
364
|
+
fireEvent.keyUp(button, {
|
|
361
365
|
keyCode: keyCodes.tab,
|
|
362
366
|
});
|
|
363
|
-
expect(button.
|
|
364
|
-
|
|
365
|
-
expect(button.
|
|
366
|
-
|
|
367
|
-
expect(button.state("pressed")).toEqual(false);
|
|
368
|
-
button.simulate("keydown", {keyCode: keyCodes.space});
|
|
369
|
-
expect(button.state("pressed")).toEqual(false);
|
|
370
|
-
button.simulate("keyup", {
|
|
371
|
-
preventDefault: jest.fn(),
|
|
372
|
-
keyCode: keyCodes.space,
|
|
373
|
-
});
|
|
374
|
-
expect(button.state("pressed")).toEqual(false);
|
|
367
|
+
expect(button).not.toHaveTextContent("focused");
|
|
368
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.tab});
|
|
369
|
+
expect(button).not.toHaveTextContent("focused");
|
|
375
370
|
|
|
376
|
-
button.
|
|
377
|
-
button.
|
|
378
|
-
expect(button.
|
|
371
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
372
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
373
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
374
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
375
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
379
376
|
|
|
380
|
-
button.
|
|
381
|
-
|
|
377
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
378
|
+
fireEvent.blur(button);
|
|
379
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
382
380
|
|
|
383
|
-
|
|
381
|
+
fireEvent.focus(button);
|
|
382
|
+
expect(button).toHaveTextContent("focused");
|
|
383
|
+
|
|
384
|
+
render(
|
|
384
385
|
<ClickableBehavior
|
|
385
386
|
disabled={true}
|
|
386
387
|
href="https://www.khanacademy.org"
|
|
@@ -398,80 +399,78 @@ describe("ClickableBehavior", () => {
|
|
|
398
399
|
</ClickableBehavior>,
|
|
399
400
|
);
|
|
400
401
|
|
|
401
|
-
|
|
402
|
-
anchor.
|
|
403
|
-
|
|
404
|
-
anchor.
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
});
|
|
408
|
-
expect(anchor.state("pressed")).toEqual(false);
|
|
402
|
+
const anchor = screen.getByRole("link");
|
|
403
|
+
expect(anchor).not.toHaveTextContent("pressed");
|
|
404
|
+
fireEvent.keyDown(anchor, {keyCode: keyCodes.enter});
|
|
405
|
+
expect(anchor).not.toHaveTextContent("pressed");
|
|
406
|
+
fireEvent.keyUp(anchor, {keyCode: keyCodes.enter});
|
|
407
|
+
expect(anchor).not.toHaveTextContent("pressed");
|
|
409
408
|
});
|
|
410
409
|
|
|
411
410
|
it("has onClick triggered just once per click by various means", () => {
|
|
412
411
|
const onClick = jest.fn();
|
|
413
|
-
|
|
412
|
+
render(
|
|
414
413
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
415
414
|
{(state, childrenProps) => {
|
|
416
415
|
return <button {...childrenProps}>Label</button>;
|
|
417
416
|
}}
|
|
418
417
|
</ClickableBehavior>,
|
|
419
418
|
);
|
|
419
|
+
const button = screen.getByRole("button");
|
|
420
420
|
expect(onClick).not.toHaveBeenCalled();
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
button.simulate("mouseup");
|
|
424
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
422
|
+
userEvent.click(button);
|
|
425
423
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
426
424
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
preventDefault: jest.fn(),
|
|
430
|
-
});
|
|
431
|
-
button.simulate("keyup", {
|
|
432
|
-
keyCode: keyCodes.space,
|
|
433
|
-
preventDefault: jest.fn(),
|
|
434
|
-
});
|
|
425
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
426
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
435
427
|
expect(onClick).toHaveBeenCalledTimes(2);
|
|
436
428
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
preventDefault: jest.fn(),
|
|
440
|
-
});
|
|
441
|
-
button.simulate("keyup", {
|
|
442
|
-
preventDefault: jest.fn(),
|
|
443
|
-
keyCode: keyCodes.enter,
|
|
444
|
-
});
|
|
429
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
430
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
445
431
|
expect(onClick).toHaveBeenCalledTimes(3);
|
|
446
432
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
433
|
+
fireEvent.touchStart(button, {keyCode: keyCodes.space});
|
|
434
|
+
fireEvent.touchEnd(button, {keyCode: keyCodes.space});
|
|
435
|
+
fireEvent.click(button);
|
|
450
436
|
expect(onClick).toHaveBeenCalledTimes(4);
|
|
451
437
|
});
|
|
452
438
|
|
|
453
439
|
it("resets state when set to disabled", () => {
|
|
454
440
|
const onClick = jest.fn();
|
|
455
|
-
const
|
|
441
|
+
const {rerender} = render(
|
|
456
442
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
457
443
|
{(state, childrenProps) => {
|
|
458
|
-
|
|
444
|
+
const label = labelForState(state);
|
|
445
|
+
return <button {...childrenProps}>{label}</button>;
|
|
459
446
|
}}
|
|
460
447
|
</ClickableBehavior>,
|
|
461
448
|
);
|
|
462
|
-
button.
|
|
463
|
-
|
|
449
|
+
const button = screen.getByRole("button");
|
|
450
|
+
userEvent.tab(); // focus
|
|
451
|
+
userEvent.hover(button);
|
|
464
452
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
453
|
+
rerender(
|
|
454
|
+
<ClickableBehavior disabled={true} onClick={(e) => onClick(e)}>
|
|
455
|
+
{(state, childrenProps) => {
|
|
456
|
+
const label = labelForState(state);
|
|
457
|
+
return <button {...childrenProps}>{label}</button>;
|
|
458
|
+
}}
|
|
459
|
+
</ClickableBehavior>,
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
expect(button).not.toHaveTextContent("pressed");
|
|
463
|
+
expect(button).not.toHaveTextContent("hovered");
|
|
464
|
+
|
|
465
|
+
// The button remains focused even after it's been disabled
|
|
466
|
+
expect(button).toHaveTextContent("focused");
|
|
468
467
|
});
|
|
469
468
|
|
|
470
469
|
describe("full page load navigation", () => {
|
|
471
470
|
it("both navigates and calls onClick for an anchor link", () => {
|
|
472
471
|
const onClick = jest.fn();
|
|
473
472
|
// Use mount instead of a shallow render to trigger event defaults
|
|
474
|
-
|
|
473
|
+
render(
|
|
475
474
|
<ClickableBehavior
|
|
476
475
|
href="https://khanacademy.org/"
|
|
477
476
|
onClick={(e) => onClick(e)}
|
|
@@ -492,29 +491,24 @@ describe("ClickableBehavior", () => {
|
|
|
492
491
|
}}
|
|
493
492
|
</ClickableBehavior>,
|
|
494
493
|
);
|
|
494
|
+
const link = screen.getByRole("link");
|
|
495
495
|
|
|
496
496
|
// Space press should not trigger the onClick
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
preventDefault: jest.fn(),
|
|
500
|
-
keyCode: keyCodes.space,
|
|
501
|
-
});
|
|
497
|
+
fireEvent.keyDown(link, {keyCode: keyCodes.space});
|
|
498
|
+
fireEvent.keyUp(link, {keyCode: keyCodes.space});
|
|
502
499
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
503
500
|
|
|
504
501
|
// Navigation didn't happen with space
|
|
505
502
|
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
|
506
503
|
|
|
507
504
|
// Enter press should trigger the onClick after keyup
|
|
508
|
-
|
|
505
|
+
fireEvent.keyDown(link, {keyCode: keyCodes.enter});
|
|
509
506
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
510
507
|
|
|
511
508
|
// Navigation doesn't happen until after enter is released
|
|
512
509
|
expect(window.location.assign).toHaveBeenCalledTimes(0);
|
|
513
510
|
|
|
514
|
-
|
|
515
|
-
preventDefault: jest.fn(),
|
|
516
|
-
keyCode: keyCodes.enter,
|
|
517
|
-
});
|
|
511
|
+
fireEvent.keyUp(link, {keyCode: keyCodes.enter});
|
|
518
512
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
519
513
|
|
|
520
514
|
// Navigation happened after enter click
|
|
@@ -523,7 +517,7 @@ describe("ClickableBehavior", () => {
|
|
|
523
517
|
|
|
524
518
|
it("waits for safeWithNav to resolve before navigation", async () => {
|
|
525
519
|
// Arrange
|
|
526
|
-
|
|
520
|
+
render(
|
|
527
521
|
<ClickableBehavior
|
|
528
522
|
href="https://khanacademy.org/"
|
|
529
523
|
safeWithNav={() => Promise.resolve()}
|
|
@@ -546,7 +540,8 @@ describe("ClickableBehavior", () => {
|
|
|
546
540
|
);
|
|
547
541
|
|
|
548
542
|
// Act
|
|
549
|
-
link.
|
|
543
|
+
const link = screen.getByRole("link");
|
|
544
|
+
userEvent.click(link);
|
|
550
545
|
await wait(0);
|
|
551
546
|
|
|
552
547
|
// Assert
|
|
@@ -555,7 +550,7 @@ describe("ClickableBehavior", () => {
|
|
|
555
550
|
|
|
556
551
|
it("should show waiting UI before safeWithNav resolves", async () => {
|
|
557
552
|
// Arrange
|
|
558
|
-
|
|
553
|
+
render(
|
|
559
554
|
<ClickableBehavior
|
|
560
555
|
href="https://khanacademy.org/"
|
|
561
556
|
safeWithNav={() => Promise.resolve()}
|
|
@@ -578,15 +573,16 @@ describe("ClickableBehavior", () => {
|
|
|
578
573
|
);
|
|
579
574
|
|
|
580
575
|
// Act
|
|
581
|
-
link.
|
|
576
|
+
const link = screen.getByRole("link");
|
|
577
|
+
userEvent.click(link);
|
|
582
578
|
|
|
583
579
|
// Assert
|
|
584
|
-
expect(link).
|
|
580
|
+
expect(link).toHaveTextContent("waiting");
|
|
585
581
|
});
|
|
586
582
|
|
|
587
583
|
it("If onClick calls e.preventDefault() then we won't navigate", () => {
|
|
588
584
|
// Arrange
|
|
589
|
-
|
|
585
|
+
render(
|
|
590
586
|
<ClickableBehavior
|
|
591
587
|
href="/foo"
|
|
592
588
|
onClick={(e) => e.preventDefault()}
|
|
@@ -596,23 +592,14 @@ describe("ClickableBehavior", () => {
|
|
|
596
592
|
// The base element here doesn't matter in this testing
|
|
597
593
|
// environment, but the simulated events in the test are in
|
|
598
594
|
// line with what browsers do for this element.
|
|
599
|
-
return
|
|
600
|
-
<button id="test-button" {...childrenProps}>
|
|
601
|
-
label
|
|
602
|
-
</button>
|
|
603
|
-
);
|
|
595
|
+
return <button {...childrenProps}>label</button>;
|
|
604
596
|
}}
|
|
605
597
|
</ClickableBehavior>,
|
|
606
598
|
);
|
|
607
599
|
|
|
608
600
|
// Act
|
|
609
|
-
const button =
|
|
610
|
-
|
|
611
|
-
preventDefault() {
|
|
612
|
-
// $FlowIgnore[object-this-reference]
|
|
613
|
-
this.defaultPrevented = true;
|
|
614
|
-
},
|
|
615
|
-
});
|
|
601
|
+
const button = screen.getByRole("button");
|
|
602
|
+
userEvent.click(button);
|
|
616
603
|
|
|
617
604
|
// Assert
|
|
618
605
|
expect(window.location.assign).not.toHaveBeenCalled();
|
|
@@ -622,7 +609,7 @@ describe("ClickableBehavior", () => {
|
|
|
622
609
|
it("calls onClick correctly for a component that doesn't respond to enter", () => {
|
|
623
610
|
const onClick = jest.fn();
|
|
624
611
|
// Use mount instead of a shallow render to trigger event defaults
|
|
625
|
-
|
|
612
|
+
render(
|
|
626
613
|
// triggerOnEnter may be false for some elements e.g. checkboxes
|
|
627
614
|
<ClickableBehavior onClick={(e) => onClick(e)} role="checkbox">
|
|
628
615
|
{(state, childrenProps) => {
|
|
@@ -635,27 +622,22 @@ describe("ClickableBehavior", () => {
|
|
|
635
622
|
);
|
|
636
623
|
|
|
637
624
|
// Enter press should not do anything
|
|
638
|
-
checkbox.
|
|
625
|
+
const checkbox = screen.getByRole("checkbox");
|
|
626
|
+
fireEvent.keyDown(checkbox, {keyCode: keyCodes.enter});
|
|
639
627
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
640
|
-
|
|
641
|
-
preventDefault: jest.fn(),
|
|
642
|
-
keyCode: keyCodes.enter,
|
|
643
|
-
});
|
|
628
|
+
fireEvent.keyUp(checkbox, {keyCode: keyCodes.enter});
|
|
644
629
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
645
630
|
|
|
646
631
|
// Space press should trigger the onClick
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
preventDefault: jest.fn(),
|
|
650
|
-
keyCode: keyCodes.space,
|
|
651
|
-
});
|
|
632
|
+
fireEvent.keyDown(checkbox, {keyCode: keyCodes.space});
|
|
633
|
+
fireEvent.keyUp(checkbox, {keyCode: keyCodes.space});
|
|
652
634
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
653
635
|
});
|
|
654
636
|
|
|
655
637
|
it("calls onClick for a button component on both enter/space", () => {
|
|
656
638
|
const onClick = jest.fn();
|
|
657
639
|
// Use mount instead of a shallow render to trigger event defaults
|
|
658
|
-
|
|
640
|
+
render(
|
|
659
641
|
<ClickableBehavior onClick={(e) => onClick(e)}>
|
|
660
642
|
{(state, childrenProps) => {
|
|
661
643
|
// The base element here doesn't matter in this testing
|
|
@@ -667,21 +649,16 @@ describe("ClickableBehavior", () => {
|
|
|
667
649
|
);
|
|
668
650
|
|
|
669
651
|
// Enter press
|
|
670
|
-
button.
|
|
652
|
+
const button = screen.getByRole("button");
|
|
653
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.enter});
|
|
671
654
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
672
|
-
|
|
673
|
-
preventDefault: jest.fn(),
|
|
674
|
-
keyCode: keyCodes.enter,
|
|
675
|
-
});
|
|
655
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.enter});
|
|
676
656
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
677
657
|
|
|
678
658
|
// Space press
|
|
679
|
-
|
|
659
|
+
fireEvent.keyDown(button, {keyCode: keyCodes.space});
|
|
680
660
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
681
|
-
|
|
682
|
-
preventDefault: jest.fn(),
|
|
683
|
-
keyCode: keyCodes.space,
|
|
684
|
-
});
|
|
661
|
+
fireEvent.keyUp(button, {keyCode: keyCodes.space});
|
|
685
662
|
expect(onClick).toHaveBeenCalledTimes(2);
|
|
686
663
|
});
|
|
687
664
|
|
|
@@ -691,7 +668,7 @@ describe("ClickableBehavior", () => {
|
|
|
691
668
|
it("calls onClick listener on space/enter with a non-usually clickable element", () => {
|
|
692
669
|
const onClick = jest.fn();
|
|
693
670
|
// Use mount instead of a shallow render to trigger event defaults
|
|
694
|
-
const
|
|
671
|
+
const {container} = render(
|
|
695
672
|
<ClickableBehavior onClick={(e) => onClick(e)}>
|
|
696
673
|
{(state, childrenProps) => {
|
|
697
674
|
// The base element here doesn't matter in this testing
|
|
@@ -703,50 +680,42 @@ describe("ClickableBehavior", () => {
|
|
|
703
680
|
);
|
|
704
681
|
|
|
705
682
|
let expectedNumberTimesCalled = 0;
|
|
706
|
-
|
|
683
|
+
// eslint-disable-next-line testing-library/no-node-access, testing-library/no-container
|
|
684
|
+
const clickableDiv = container.querySelector("div");
|
|
685
|
+
if (!clickableDiv) {
|
|
686
|
+
throw new Error("couldn't find clickable div");
|
|
687
|
+
}
|
|
707
688
|
|
|
708
689
|
// Enter press on a div
|
|
709
|
-
|
|
690
|
+
fireEvent.keyDown(clickableDiv, {keyCode: keyCodes.enter});
|
|
710
691
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
711
|
-
|
|
712
|
-
preventDefault: jest.fn(),
|
|
692
|
+
fireEvent.keyUp(clickableDiv, {
|
|
713
693
|
keyCode: keyCodes.enter,
|
|
714
694
|
});
|
|
715
695
|
expectedNumberTimesCalled += 1;
|
|
716
696
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
717
697
|
|
|
718
698
|
// Simulate a mouse click.
|
|
719
|
-
|
|
720
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
721
|
-
clickableDiv.simulate("mouseup");
|
|
722
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
723
|
-
clickableDiv.simulate("click", {preventDefault: jest.fn()});
|
|
699
|
+
userEvent.click(clickableDiv);
|
|
724
700
|
expectedNumberTimesCalled += 1;
|
|
725
701
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
726
702
|
|
|
727
703
|
// Space press on a div
|
|
728
|
-
|
|
704
|
+
fireEvent.keyDown(clickableDiv, {keyCode: keyCodes.space});
|
|
729
705
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
730
|
-
|
|
731
|
-
preventDefault: jest.fn(),
|
|
732
|
-
keyCode: keyCodes.space,
|
|
733
|
-
});
|
|
706
|
+
fireEvent.keyUp(clickableDiv, {keyCode: keyCodes.space});
|
|
734
707
|
expectedNumberTimesCalled += 1;
|
|
735
708
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
736
709
|
|
|
737
710
|
// Simulate another mouse click.
|
|
738
|
-
|
|
739
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
740
|
-
clickableDiv.simulate("mouseup");
|
|
741
|
-
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
742
|
-
clickableDiv.simulate("click", {preventDefault: jest.fn()});
|
|
711
|
+
userEvent.click(clickableDiv);
|
|
743
712
|
expectedNumberTimesCalled += 1;
|
|
744
713
|
expect(onClick).toHaveBeenCalledTimes(expectedNumberTimesCalled);
|
|
745
714
|
});
|
|
746
715
|
|
|
747
716
|
it("calls onClick on mouseup when the mouse was dragging", () => {
|
|
748
717
|
const onClick = jest.fn();
|
|
749
|
-
|
|
718
|
+
render(
|
|
750
719
|
<ClickableBehavior disabled={false} onClick={(e) => onClick(e)}>
|
|
751
720
|
{(state, childrenProps) => {
|
|
752
721
|
return <button {...childrenProps}>Label</button>;
|
|
@@ -754,28 +723,27 @@ describe("ClickableBehavior", () => {
|
|
|
754
723
|
</ClickableBehavior>,
|
|
755
724
|
);
|
|
756
725
|
|
|
757
|
-
button.
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
726
|
+
const button = screen.getByRole("button");
|
|
727
|
+
fireEvent.mouseDown(button);
|
|
728
|
+
fireEvent.dragStart(button);
|
|
729
|
+
fireEvent.mouseLeave(button);
|
|
730
|
+
fireEvent.mouseUp(button);
|
|
761
731
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
762
732
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
733
|
+
fireEvent.mouseDown(button);
|
|
734
|
+
fireEvent.dragStart(button);
|
|
735
|
+
fireEvent.mouseUp(button);
|
|
766
736
|
expect(onClick).toHaveBeenCalledTimes(1);
|
|
767
737
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
});
|
|
771
|
-
button.simulate("mouseup", {preventDefault: jest.fn()});
|
|
738
|
+
fireEvent.mouseEnter(button, {buttons: 1});
|
|
739
|
+
fireEvent.mouseUp(button);
|
|
772
740
|
expect(onClick).toHaveBeenCalledTimes(2);
|
|
773
741
|
});
|
|
774
742
|
|
|
775
743
|
it("doesn't trigger enter key when browser doesn't stop the click", () => {
|
|
776
744
|
const onClick = jest.fn();
|
|
777
745
|
// Use mount instead of a shallow render to trigger event defaults
|
|
778
|
-
|
|
746
|
+
render(
|
|
779
747
|
<ClickableBehavior onClick={(e) => onClick(e)} role="checkbox">
|
|
780
748
|
{(state, childrenProps) => {
|
|
781
749
|
// The base element here doesn't matter in this testing
|
|
@@ -786,14 +754,12 @@ describe("ClickableBehavior", () => {
|
|
|
786
754
|
</ClickableBehavior>,
|
|
787
755
|
);
|
|
788
756
|
|
|
757
|
+
const checkbox = screen.getByRole("checkbox");
|
|
789
758
|
// Enter press should not do anything
|
|
790
|
-
|
|
759
|
+
fireEvent.keyDown(checkbox, {keyCode: keyCodes.enter});
|
|
791
760
|
// This element still wants to have a click on enter press
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
preventDefault: jest.fn(),
|
|
795
|
-
keyCode: keyCodes.enter,
|
|
796
|
-
});
|
|
761
|
+
fireEvent.click(checkbox);
|
|
762
|
+
fireEvent.keyUp(checkbox, {keyCode: keyCodes.enter});
|
|
797
763
|
expect(onClick).toHaveBeenCalledTimes(0);
|
|
798
764
|
});
|
|
799
765
|
|
|
@@ -806,7 +772,7 @@ describe("ClickableBehavior", () => {
|
|
|
806
772
|
|
|
807
773
|
it("handles client-side navigation when there's a router context", () => {
|
|
808
774
|
// Arrange
|
|
809
|
-
|
|
775
|
+
render(
|
|
810
776
|
<MemoryRouter>
|
|
811
777
|
<div>
|
|
812
778
|
<ClickableBehaviorWithRouter
|
|
@@ -819,9 +785,7 @@ describe("ClickableBehavior", () => {
|
|
|
819
785
|
// environment, but the simulated events in the test are in
|
|
820
786
|
// line with what browsers do for this element.
|
|
821
787
|
return (
|
|
822
|
-
<button
|
|
823
|
-
label
|
|
824
|
-
</button>
|
|
788
|
+
<button {...childrenProps}>label</button>
|
|
825
789
|
);
|
|
826
790
|
}}
|
|
827
791
|
</ClickableBehaviorWithRouter>
|
|
@@ -835,17 +799,16 @@ describe("ClickableBehavior", () => {
|
|
|
835
799
|
);
|
|
836
800
|
|
|
837
801
|
// Act
|
|
838
|
-
|
|
839
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
802
|
+
userEvent.click(screen.getByRole("button"));
|
|
840
803
|
|
|
841
804
|
// Assert
|
|
842
|
-
expect(
|
|
805
|
+
expect(screen.getByText("Hello, world!")).toBeInTheDocument();
|
|
843
806
|
});
|
|
844
807
|
|
|
845
808
|
describe("beforeNav", () => {
|
|
846
809
|
it("waits for beforeNav to resolve before client-side navigating", async () => {
|
|
847
810
|
// Arrange
|
|
848
|
-
|
|
811
|
+
render(
|
|
849
812
|
<MemoryRouter>
|
|
850
813
|
<div>
|
|
851
814
|
<ClickableBehaviorWithRouter
|
|
@@ -859,10 +822,7 @@ describe("ClickableBehavior", () => {
|
|
|
859
822
|
// environment, but the simulated events in the test are in
|
|
860
823
|
// line with what browsers do for this element.
|
|
861
824
|
return (
|
|
862
|
-
<button
|
|
863
|
-
id="test-button"
|
|
864
|
-
{...childrenProps}
|
|
865
|
-
>
|
|
825
|
+
<button {...childrenProps}>
|
|
866
826
|
{state.waiting
|
|
867
827
|
? "waiting"
|
|
868
828
|
: "label"}
|
|
@@ -880,17 +840,16 @@ describe("ClickableBehavior", () => {
|
|
|
880
840
|
);
|
|
881
841
|
|
|
882
842
|
// Act
|
|
883
|
-
|
|
884
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
843
|
+
userEvent.click(screen.getByRole("button"));
|
|
885
844
|
await wait(0);
|
|
886
845
|
|
|
887
846
|
// Assert
|
|
888
|
-
expect(
|
|
847
|
+
expect(screen.getByText("Hello, world!")).toBeInTheDocument();
|
|
889
848
|
});
|
|
890
849
|
|
|
891
850
|
it("shows waiting state before navigating", async () => {
|
|
892
851
|
// Arrange
|
|
893
|
-
|
|
852
|
+
render(
|
|
894
853
|
<MemoryRouter>
|
|
895
854
|
<div>
|
|
896
855
|
<ClickableBehaviorWithRouter
|
|
@@ -904,10 +863,7 @@ describe("ClickableBehavior", () => {
|
|
|
904
863
|
// environment, but the simulated events in the test are in
|
|
905
864
|
// line with what browsers do for this element.
|
|
906
865
|
return (
|
|
907
|
-
<button
|
|
908
|
-
id="test-button"
|
|
909
|
-
{...childrenProps}
|
|
910
|
-
>
|
|
866
|
+
<button {...childrenProps}>
|
|
911
867
|
{state.waiting
|
|
912
868
|
? "waiting"
|
|
913
869
|
: "label"}
|
|
@@ -925,16 +881,15 @@ describe("ClickableBehavior", () => {
|
|
|
925
881
|
);
|
|
926
882
|
|
|
927
883
|
// Act
|
|
928
|
-
|
|
929
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
884
|
+
userEvent.click(screen.getByRole("button"));
|
|
930
885
|
|
|
931
886
|
// Assert
|
|
932
|
-
expect(
|
|
887
|
+
expect(screen.getByText("waiting")).toBeInTheDocument();
|
|
933
888
|
});
|
|
934
889
|
|
|
935
890
|
it("does not navigate if beforeNav rejects", async () => {
|
|
936
891
|
// Arrange
|
|
937
|
-
|
|
892
|
+
render(
|
|
938
893
|
<MemoryRouter>
|
|
939
894
|
<div>
|
|
940
895
|
<ClickableBehaviorWithRouter
|
|
@@ -948,10 +903,7 @@ describe("ClickableBehavior", () => {
|
|
|
948
903
|
// environment, but the simulated events in the test are in
|
|
949
904
|
// line with what browsers do for this element.
|
|
950
905
|
return (
|
|
951
|
-
<button
|
|
952
|
-
id="test-button"
|
|
953
|
-
{...childrenProps}
|
|
954
|
-
>
|
|
906
|
+
<button {...childrenProps}>
|
|
955
907
|
label
|
|
956
908
|
</button>
|
|
957
909
|
);
|
|
@@ -967,18 +919,19 @@ describe("ClickableBehavior", () => {
|
|
|
967
919
|
);
|
|
968
920
|
|
|
969
921
|
// Act
|
|
970
|
-
|
|
971
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
922
|
+
userEvent.click(screen.getByRole("button"));
|
|
972
923
|
await wait(0);
|
|
973
924
|
|
|
974
925
|
// Assert
|
|
975
|
-
expect(
|
|
926
|
+
expect(
|
|
927
|
+
screen.queryByText("Hello, world!"),
|
|
928
|
+
).not.toBeInTheDocument();
|
|
976
929
|
});
|
|
977
930
|
|
|
978
931
|
it("calls safeWithNav if provided if beforeNav resolves", async () => {
|
|
979
932
|
// Arrange
|
|
980
933
|
const safeWithNavMock = jest.fn();
|
|
981
|
-
|
|
934
|
+
render(
|
|
982
935
|
<MemoryRouter>
|
|
983
936
|
<div>
|
|
984
937
|
<ClickableBehaviorWithRouter
|
|
@@ -993,10 +946,7 @@ describe("ClickableBehavior", () => {
|
|
|
993
946
|
// environment, but the simulated events in the test are in
|
|
994
947
|
// line with what browsers do for this element.
|
|
995
948
|
return (
|
|
996
|
-
<button
|
|
997
|
-
id="test-button"
|
|
998
|
-
{...childrenProps}
|
|
999
|
-
>
|
|
949
|
+
<button {...childrenProps}>
|
|
1000
950
|
{state.waiting
|
|
1001
951
|
? "waiting"
|
|
1002
952
|
: "label"}
|
|
@@ -1014,8 +964,7 @@ describe("ClickableBehavior", () => {
|
|
|
1014
964
|
);
|
|
1015
965
|
|
|
1016
966
|
// Act
|
|
1017
|
-
|
|
1018
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
967
|
+
userEvent.click(screen.getByRole("button"));
|
|
1019
968
|
await wait(0);
|
|
1020
969
|
|
|
1021
970
|
// Assert
|
|
@@ -1025,7 +974,7 @@ describe("ClickableBehavior", () => {
|
|
|
1025
974
|
|
|
1026
975
|
it("doesn't wait for safeWithNav to resolve before client-side navigating", async () => {
|
|
1027
976
|
// Arrange
|
|
1028
|
-
|
|
977
|
+
render(
|
|
1029
978
|
<MemoryRouter>
|
|
1030
979
|
<div>
|
|
1031
980
|
<ClickableBehaviorWithRouter
|
|
@@ -1039,9 +988,7 @@ describe("ClickableBehavior", () => {
|
|
|
1039
988
|
// environment, but the simulated events in the test are in
|
|
1040
989
|
// line with what browsers do for this element.
|
|
1041
990
|
return (
|
|
1042
|
-
<button
|
|
1043
|
-
label
|
|
1044
|
-
</button>
|
|
991
|
+
<button {...childrenProps}>label</button>
|
|
1045
992
|
);
|
|
1046
993
|
}}
|
|
1047
994
|
</ClickableBehaviorWithRouter>
|
|
@@ -1055,16 +1002,15 @@ describe("ClickableBehavior", () => {
|
|
|
1055
1002
|
);
|
|
1056
1003
|
|
|
1057
1004
|
// Act
|
|
1058
|
-
|
|
1059
|
-
button.simulate("click", {preventDefault: jest.fn()});
|
|
1005
|
+
userEvent.click(screen.getByRole("button"));
|
|
1060
1006
|
|
|
1061
1007
|
// Assert
|
|
1062
|
-
expect(
|
|
1008
|
+
expect(screen.getByText("Hello, world!")).toBeInTheDocument();
|
|
1063
1009
|
});
|
|
1064
1010
|
|
|
1065
1011
|
it("If onClick calls e.preventDefault() then we won't navigate", () => {
|
|
1066
1012
|
// Arrange
|
|
1067
|
-
|
|
1013
|
+
render(
|
|
1068
1014
|
<MemoryRouter>
|
|
1069
1015
|
<div>
|
|
1070
1016
|
<ClickableBehaviorWithRouter
|
|
@@ -1077,9 +1023,7 @@ describe("ClickableBehavior", () => {
|
|
|
1077
1023
|
// environment, but the simulated events in the test are in
|
|
1078
1024
|
// line with what browsers do for this element.
|
|
1079
1025
|
return (
|
|
1080
|
-
<button
|
|
1081
|
-
label
|
|
1082
|
-
</button>
|
|
1026
|
+
<button {...childrenProps}>label</button>
|
|
1083
1027
|
);
|
|
1084
1028
|
}}
|
|
1085
1029
|
</ClickableBehaviorWithRouter>
|
|
@@ -1093,23 +1037,17 @@ describe("ClickableBehavior", () => {
|
|
|
1093
1037
|
);
|
|
1094
1038
|
|
|
1095
1039
|
// Act
|
|
1096
|
-
|
|
1097
|
-
button.simulate("click", {
|
|
1098
|
-
preventDefault() {
|
|
1099
|
-
// $FlowIgnore[object-this-reference]
|
|
1100
|
-
this.defaultPrevented = true;
|
|
1101
|
-
},
|
|
1102
|
-
});
|
|
1040
|
+
userEvent.click(screen.getByRole("button"));
|
|
1103
1041
|
|
|
1104
1042
|
// Assert
|
|
1105
|
-
expect(
|
|
1043
|
+
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
1106
1044
|
});
|
|
1107
1045
|
});
|
|
1108
1046
|
|
|
1109
1047
|
describe("target='_blank'", () => {
|
|
1110
1048
|
it("opens a new tab", () => {
|
|
1111
1049
|
// Arrange
|
|
1112
|
-
|
|
1050
|
+
render(
|
|
1113
1051
|
<ClickableBehavior
|
|
1114
1052
|
disabled={false}
|
|
1115
1053
|
href="https://www.khanacademy.org"
|
|
@@ -1130,7 +1068,7 @@ describe("ClickableBehavior", () => {
|
|
|
1130
1068
|
);
|
|
1131
1069
|
|
|
1132
1070
|
// Act
|
|
1133
|
-
|
|
1071
|
+
userEvent.click(screen.getByRole("link"));
|
|
1134
1072
|
|
|
1135
1073
|
// Assert
|
|
1136
1074
|
expect(window.open).toHaveBeenCalledWith(
|
|
@@ -1142,7 +1080,7 @@ describe("ClickableBehavior", () => {
|
|
|
1142
1080
|
it("opens a new tab when using 'safeWithNav'", () => {
|
|
1143
1081
|
// Arrange
|
|
1144
1082
|
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1145
|
-
|
|
1083
|
+
render(
|
|
1146
1084
|
<ClickableBehavior
|
|
1147
1085
|
disabled={false}
|
|
1148
1086
|
href="https://www.khanacademy.org"
|
|
@@ -1164,7 +1102,7 @@ describe("ClickableBehavior", () => {
|
|
|
1164
1102
|
);
|
|
1165
1103
|
|
|
1166
1104
|
// Act
|
|
1167
|
-
|
|
1105
|
+
userEvent.click(screen.getByRole("link"));
|
|
1168
1106
|
|
|
1169
1107
|
// Assert
|
|
1170
1108
|
expect(window.open).toHaveBeenCalledWith(
|
|
@@ -1176,7 +1114,7 @@ describe("ClickableBehavior", () => {
|
|
|
1176
1114
|
it("calls 'safeWithNav'", () => {
|
|
1177
1115
|
// Arrange
|
|
1178
1116
|
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1179
|
-
|
|
1117
|
+
render(
|
|
1180
1118
|
<ClickableBehavior
|
|
1181
1119
|
disabled={false}
|
|
1182
1120
|
href="https://www.khanacademy.org"
|
|
@@ -1198,7 +1136,7 @@ describe("ClickableBehavior", () => {
|
|
|
1198
1136
|
);
|
|
1199
1137
|
|
|
1200
1138
|
// Act
|
|
1201
|
-
|
|
1139
|
+
userEvent.click(screen.getByRole("link"));
|
|
1202
1140
|
|
|
1203
1141
|
// Assert
|
|
1204
1142
|
expect(safeWithNavMock).toHaveBeenCalled();
|
|
@@ -1206,7 +1144,7 @@ describe("ClickableBehavior", () => {
|
|
|
1206
1144
|
|
|
1207
1145
|
it("opens a new tab when inside a router", () => {
|
|
1208
1146
|
// Arrange
|
|
1209
|
-
|
|
1147
|
+
render(
|
|
1210
1148
|
<MemoryRouter initialEntries={["/"]}>
|
|
1211
1149
|
<ClickableBehavior
|
|
1212
1150
|
disabled={false}
|
|
@@ -1229,7 +1167,7 @@ describe("ClickableBehavior", () => {
|
|
|
1229
1167
|
);
|
|
1230
1168
|
|
|
1231
1169
|
// Act
|
|
1232
|
-
|
|
1170
|
+
userEvent.click(screen.getByRole("link"));
|
|
1233
1171
|
|
|
1234
1172
|
// Assert
|
|
1235
1173
|
expect(window.open).toHaveBeenCalledWith(
|
|
@@ -1241,7 +1179,7 @@ describe("ClickableBehavior", () => {
|
|
|
1241
1179
|
it("opens a new tab when using 'safeWithNav' inside a router", () => {
|
|
1242
1180
|
// Arrange
|
|
1243
1181
|
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1244
|
-
|
|
1182
|
+
render(
|
|
1245
1183
|
<MemoryRouter initialEntries={["/"]}>
|
|
1246
1184
|
<ClickableBehavior
|
|
1247
1185
|
disabled={false}
|
|
@@ -1265,7 +1203,7 @@ describe("ClickableBehavior", () => {
|
|
|
1265
1203
|
);
|
|
1266
1204
|
|
|
1267
1205
|
// Act
|
|
1268
|
-
|
|
1206
|
+
userEvent.click(screen.getByRole("link"));
|
|
1269
1207
|
|
|
1270
1208
|
// Assert
|
|
1271
1209
|
expect(window.open).toHaveBeenCalledWith(
|
|
@@ -1277,7 +1215,7 @@ describe("ClickableBehavior", () => {
|
|
|
1277
1215
|
it("calls 'safeWithNav' inside a router", () => {
|
|
1278
1216
|
// Arrange
|
|
1279
1217
|
const safeWithNavMock = jest.fn().mockResolvedValue();
|
|
1280
|
-
|
|
1218
|
+
render(
|
|
1281
1219
|
<MemoryRouter initialEntries={["/"]}>
|
|
1282
1220
|
<ClickableBehavior
|
|
1283
1221
|
disabled={false}
|
|
@@ -1301,7 +1239,7 @@ describe("ClickableBehavior", () => {
|
|
|
1301
1239
|
);
|
|
1302
1240
|
|
|
1303
1241
|
// Act
|
|
1304
|
-
|
|
1242
|
+
userEvent.click(screen.getByRole("link"));
|
|
1305
1243
|
|
|
1306
1244
|
// Assert
|
|
1307
1245
|
expect(safeWithNavMock).toHaveBeenCalled();
|
|
@@ -1312,7 +1250,7 @@ describe("ClickableBehavior", () => {
|
|
|
1312
1250
|
it("should use the 'rel' that was passed in", () => {
|
|
1313
1251
|
// Arrange
|
|
1314
1252
|
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1315
|
-
|
|
1253
|
+
render(
|
|
1316
1254
|
<ClickableBehavior
|
|
1317
1255
|
href="https://www.khanacademy.org"
|
|
1318
1256
|
rel="something_else"
|
|
@@ -1329,7 +1267,7 @@ describe("ClickableBehavior", () => {
|
|
|
1329
1267
|
it("should use 'noopener noreferrer' as a default when target='_blank'", () => {
|
|
1330
1268
|
// Arrange
|
|
1331
1269
|
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1332
|
-
|
|
1270
|
+
render(
|
|
1333
1271
|
<ClickableBehavior
|
|
1334
1272
|
href="https://www.khanacademy.org"
|
|
1335
1273
|
target="_blank"
|
|
@@ -1345,7 +1283,7 @@ describe("ClickableBehavior", () => {
|
|
|
1345
1283
|
it("should not use the default if target != '_blank'", () => {
|
|
1346
1284
|
// Arrange
|
|
1347
1285
|
const childrenMock = jest.fn().mockImplementation(() => null);
|
|
1348
|
-
|
|
1286
|
+
render(
|
|
1349
1287
|
<ClickableBehavior href="https://www.khanacademy.org">
|
|
1350
1288
|
{childrenMock}
|
|
1351
1289
|
</ClickableBehavior>,
|