@khanacademy/wonder-blocks-clickable 2.1.2
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/LICENSE +21 -0
- package/dist/es/index.js +712 -0
- package/dist/index.js +1056 -0
- package/dist/index.js.flow +2 -0
- package/docs.md +7 -0
- package/package.json +32 -0
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +426 -0
- package/src/__tests__/generated-snapshot.test.js +176 -0
- package/src/components/__tests__/clickable-behavior.test.js +1313 -0
- package/src/components/__tests__/clickable.test.js +500 -0
- package/src/components/clickable-behavior.js +646 -0
- package/src/components/clickable.js +388 -0
- package/src/components/clickable.md +196 -0
- package/src/components/clickable.stories.js +129 -0
- package/src/index.js +15 -0
- package/src/util/__tests__/get-clickable-behavior.test.js +105 -0
- package/src/util/__tests__/is-client-side-url.js.test.js +50 -0
- package/src/util/get-clickable-behavior.js +43 -0
- package/src/util/is-client-side-url.js +16 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {MemoryRouter, Route, Switch} from "react-router-dom";
|
|
4
|
+
import {mount} from "enzyme";
|
|
5
|
+
|
|
6
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
7
|
+
import Clickable from "../clickable.js";
|
|
8
|
+
|
|
9
|
+
const wait = (delay: number = 0) =>
|
|
10
|
+
new Promise((resolve, reject) => {
|
|
11
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
12
|
+
return setTimeout(resolve, delay);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("Clickable", () => {
|
|
16
|
+
test("client-side navigation", () => {
|
|
17
|
+
// Arrange
|
|
18
|
+
const wrapper = mount(
|
|
19
|
+
<MemoryRouter>
|
|
20
|
+
<View>
|
|
21
|
+
<Clickable testId="button" href="/foo">
|
|
22
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
23
|
+
</Clickable>
|
|
24
|
+
<Switch>
|
|
25
|
+
<Route path="/foo">
|
|
26
|
+
<View id="foo">Hello, world!</View>
|
|
27
|
+
</Route>
|
|
28
|
+
</Switch>
|
|
29
|
+
</View>
|
|
30
|
+
</MemoryRouter>,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Act
|
|
34
|
+
const clickableWrapper = wrapper
|
|
35
|
+
.find(`[data-test-id="button"]`)
|
|
36
|
+
.first();
|
|
37
|
+
clickableWrapper.simulate("click", {button: 0});
|
|
38
|
+
|
|
39
|
+
// Assert
|
|
40
|
+
expect(wrapper.find("#foo").exists()).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("client-side navigation with unknown URL fails", () => {
|
|
44
|
+
// Arrange
|
|
45
|
+
const wrapper = mount(
|
|
46
|
+
<MemoryRouter>
|
|
47
|
+
<View>
|
|
48
|
+
<Clickable testId="button" href="/unknown">
|
|
49
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
50
|
+
</Clickable>
|
|
51
|
+
<Switch>
|
|
52
|
+
<Route path="/foo">
|
|
53
|
+
<View id="foo">Hello, world!</View>
|
|
54
|
+
</Route>
|
|
55
|
+
</Switch>
|
|
56
|
+
</View>
|
|
57
|
+
</MemoryRouter>,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Act
|
|
61
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
62
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
63
|
+
|
|
64
|
+
// Assert
|
|
65
|
+
expect(wrapper.find("#foo").exists()).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("client-side navigation with `skipClientNav` set to `true` fails", () => {
|
|
69
|
+
// Arrange
|
|
70
|
+
const wrapper = mount(
|
|
71
|
+
<MemoryRouter>
|
|
72
|
+
<View>
|
|
73
|
+
<Clickable testId="button" href="/foo" skipClientNav>
|
|
74
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
75
|
+
</Clickable>
|
|
76
|
+
<Switch>
|
|
77
|
+
<Route path="/foo">
|
|
78
|
+
<View id="foo">Hello, world!</View>
|
|
79
|
+
</Route>
|
|
80
|
+
</Switch>
|
|
81
|
+
</View>
|
|
82
|
+
</MemoryRouter>,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Act
|
|
86
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
87
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
88
|
+
|
|
89
|
+
// Assert
|
|
90
|
+
expect(wrapper.find("#foo").exists()).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("disallow navigation when href and disabled are both set", () => {
|
|
94
|
+
// Arrange
|
|
95
|
+
const wrapper = mount(
|
|
96
|
+
<MemoryRouter>
|
|
97
|
+
<View>
|
|
98
|
+
<Clickable testId="button" href="/foo" disabled={true}>
|
|
99
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
100
|
+
</Clickable>
|
|
101
|
+
<Switch>
|
|
102
|
+
<Route path="/foo">
|
|
103
|
+
<View id="foo">Hello, world!</View>
|
|
104
|
+
</Route>
|
|
105
|
+
</Switch>
|
|
106
|
+
</View>
|
|
107
|
+
</MemoryRouter>,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Act
|
|
111
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
112
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
113
|
+
|
|
114
|
+
// Assert
|
|
115
|
+
expect(wrapper.find("#foo").exists()).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("should verify if href is passed to Clickablebehavior", () => {
|
|
119
|
+
// Arrange, Act
|
|
120
|
+
const wrapper = mount(
|
|
121
|
+
<Clickable testId="button" href="/foo" skipClientNav={true}>
|
|
122
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
123
|
+
</Clickable>,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Assert
|
|
127
|
+
expect(wrapper.find("ClickableBehavior")).toHaveProp({href: "/foo"});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("should navigate to a specific link using the keyboard", () => {
|
|
131
|
+
// Arrange
|
|
132
|
+
window.location.assign = jest.fn();
|
|
133
|
+
|
|
134
|
+
const wrapper = mount(
|
|
135
|
+
<Clickable testId="button" href="/foo" skipClientNav={true}>
|
|
136
|
+
{(eventState) => <h1>Click Me!</h1>}
|
|
137
|
+
</Clickable>,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Act
|
|
141
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
142
|
+
// simulate Enter
|
|
143
|
+
buttonWrapper.simulate("keyup", {keyCode: 13});
|
|
144
|
+
|
|
145
|
+
// Assert
|
|
146
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("beforeNav rejection blocks client-side navigation", async () => {
|
|
150
|
+
// Arrange
|
|
151
|
+
const wrapper = mount(
|
|
152
|
+
<MemoryRouter>
|
|
153
|
+
<div>
|
|
154
|
+
<Clickable
|
|
155
|
+
testId="button"
|
|
156
|
+
href="/foo"
|
|
157
|
+
beforeNav={(e) => Promise.reject()}
|
|
158
|
+
>
|
|
159
|
+
{() => <span>Click me!</span>}
|
|
160
|
+
</Clickable>
|
|
161
|
+
<Switch>
|
|
162
|
+
<Route path="/foo">
|
|
163
|
+
<div id="foo">Hello, world!</div>
|
|
164
|
+
</Route>
|
|
165
|
+
</Switch>
|
|
166
|
+
</div>
|
|
167
|
+
</MemoryRouter>,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Act
|
|
171
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
172
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
173
|
+
await wait(0);
|
|
174
|
+
buttonWrapper.update();
|
|
175
|
+
|
|
176
|
+
// Assert
|
|
177
|
+
expect(wrapper.find("#foo")).not.toExist();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("beforeNav rejection blocks calling safeWithNav", async () => {
|
|
181
|
+
// Arrange
|
|
182
|
+
const safeWithNavMock = jest.fn();
|
|
183
|
+
const wrapper = mount(
|
|
184
|
+
<MemoryRouter>
|
|
185
|
+
<div>
|
|
186
|
+
<Clickable
|
|
187
|
+
testId="button"
|
|
188
|
+
href="/foo"
|
|
189
|
+
beforeNav={(e) => Promise.reject()}
|
|
190
|
+
safeWithNav={safeWithNavMock}
|
|
191
|
+
>
|
|
192
|
+
{() => <span>Click me!</span>}
|
|
193
|
+
</Clickable>
|
|
194
|
+
<Switch>
|
|
195
|
+
<Route path="/foo">
|
|
196
|
+
<div id="foo">Hello, world!</div>
|
|
197
|
+
</Route>
|
|
198
|
+
</Switch>
|
|
199
|
+
</div>
|
|
200
|
+
</MemoryRouter>,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Act
|
|
204
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
205
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
206
|
+
await wait(0);
|
|
207
|
+
buttonWrapper.update();
|
|
208
|
+
|
|
209
|
+
// Assert
|
|
210
|
+
expect(safeWithNavMock).not.toHaveBeenCalled();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("beforeNav resolution results in client-side navigation", async () => {
|
|
214
|
+
// Arrange
|
|
215
|
+
const wrapper = mount(
|
|
216
|
+
<MemoryRouter>
|
|
217
|
+
<div>
|
|
218
|
+
<Clickable
|
|
219
|
+
testId="button"
|
|
220
|
+
href="/foo"
|
|
221
|
+
beforeNav={(e) => Promise.resolve()}
|
|
222
|
+
>
|
|
223
|
+
{() => <span>Click me!</span>}
|
|
224
|
+
</Clickable>
|
|
225
|
+
<Switch>
|
|
226
|
+
<Route path="/foo">
|
|
227
|
+
<div id="foo">Hello, world!</div>
|
|
228
|
+
</Route>
|
|
229
|
+
</Switch>
|
|
230
|
+
</div>
|
|
231
|
+
</MemoryRouter>,
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Act
|
|
235
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
236
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
237
|
+
await wait(0);
|
|
238
|
+
buttonWrapper.update();
|
|
239
|
+
|
|
240
|
+
// Assert
|
|
241
|
+
expect(wrapper.find("#foo")).toExist();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("beforeNav resolution results in safeWithNav being called", async () => {
|
|
245
|
+
// Arrange
|
|
246
|
+
const safeWithNavMock = jest.fn();
|
|
247
|
+
const wrapper = mount(
|
|
248
|
+
<MemoryRouter>
|
|
249
|
+
<div>
|
|
250
|
+
<Clickable
|
|
251
|
+
testId="button"
|
|
252
|
+
href="/foo"
|
|
253
|
+
beforeNav={(e) => Promise.resolve()}
|
|
254
|
+
safeWithNav={safeWithNavMock}
|
|
255
|
+
>
|
|
256
|
+
{() => <span>Click me!</span>}
|
|
257
|
+
</Clickable>
|
|
258
|
+
<Switch>
|
|
259
|
+
<Route path="/foo">
|
|
260
|
+
<div id="foo">Hello, world!</div>
|
|
261
|
+
</Route>
|
|
262
|
+
</Switch>
|
|
263
|
+
</div>
|
|
264
|
+
</MemoryRouter>,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// Act
|
|
268
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
269
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
270
|
+
await wait(0);
|
|
271
|
+
buttonWrapper.update();
|
|
272
|
+
|
|
273
|
+
// Assert
|
|
274
|
+
expect(safeWithNavMock).toHaveBeenCalled();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("safeWithNav with skipClientNav=true waits for promise resolution", async () => {
|
|
278
|
+
// Arrange
|
|
279
|
+
jest.spyOn(window.location, "assign");
|
|
280
|
+
const wrapper = mount(
|
|
281
|
+
<MemoryRouter>
|
|
282
|
+
<div>
|
|
283
|
+
<Clickable
|
|
284
|
+
testId="button"
|
|
285
|
+
href="/foo"
|
|
286
|
+
safeWithNav={(e) => Promise.resolve()}
|
|
287
|
+
skipClientNav={true}
|
|
288
|
+
>
|
|
289
|
+
{() => <h1>Click me!</h1>}
|
|
290
|
+
</Clickable>
|
|
291
|
+
<Switch>
|
|
292
|
+
<Route path="/foo">
|
|
293
|
+
<div id="foo">Hello, world!</div>
|
|
294
|
+
</Route>
|
|
295
|
+
</Switch>
|
|
296
|
+
</div>
|
|
297
|
+
</MemoryRouter>,
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
// Act
|
|
301
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
302
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
303
|
+
await wait(0);
|
|
304
|
+
buttonWrapper.update();
|
|
305
|
+
|
|
306
|
+
// Assert
|
|
307
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("beforeNav resolution and safeWithNav with skipClientNav=true waits for promise resolution", async () => {
|
|
311
|
+
// Arrange
|
|
312
|
+
jest.spyOn(window.location, "assign");
|
|
313
|
+
const wrapper = mount(
|
|
314
|
+
<MemoryRouter>
|
|
315
|
+
<div>
|
|
316
|
+
<Clickable
|
|
317
|
+
testId="button"
|
|
318
|
+
href="/foo"
|
|
319
|
+
beforeNav={(e) => Promise.resolve()}
|
|
320
|
+
safeWithNav={(e) => Promise.resolve()}
|
|
321
|
+
skipClientNav={true}
|
|
322
|
+
>
|
|
323
|
+
{() => <h1>Click me!</h1>}
|
|
324
|
+
</Clickable>
|
|
325
|
+
<Switch>
|
|
326
|
+
<Route path="/foo">
|
|
327
|
+
<div id="foo">Hello, world!</div>
|
|
328
|
+
</Route>
|
|
329
|
+
</Switch>
|
|
330
|
+
</div>
|
|
331
|
+
</MemoryRouter>,
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
// Act
|
|
335
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
336
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
337
|
+
await wait(0);
|
|
338
|
+
buttonWrapper.update();
|
|
339
|
+
await wait(0);
|
|
340
|
+
buttonWrapper.update();
|
|
341
|
+
|
|
342
|
+
// Assert
|
|
343
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("safeWithNav with skipClientNav=true waits for promise rejection", async () => {
|
|
347
|
+
// Arrange
|
|
348
|
+
jest.spyOn(window.location, "assign");
|
|
349
|
+
const wrapper = mount(
|
|
350
|
+
<MemoryRouter>
|
|
351
|
+
<div>
|
|
352
|
+
<Clickable
|
|
353
|
+
testId="button"
|
|
354
|
+
href="/foo"
|
|
355
|
+
safeWithNav={(e) => Promise.reject()}
|
|
356
|
+
skipClientNav={true}
|
|
357
|
+
>
|
|
358
|
+
{() => <h1>Click me!</h1>}
|
|
359
|
+
</Clickable>
|
|
360
|
+
<Switch>
|
|
361
|
+
<Route path="/foo">
|
|
362
|
+
<div id="foo">Hello, world!</div>
|
|
363
|
+
</Route>
|
|
364
|
+
</Switch>
|
|
365
|
+
</div>
|
|
366
|
+
</MemoryRouter>,
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
// Act
|
|
370
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
371
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
372
|
+
await wait(0);
|
|
373
|
+
buttonWrapper.update();
|
|
374
|
+
|
|
375
|
+
// Assert
|
|
376
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
test("safeWithNav with skipClientNav=false calls safeWithNav but doesn't wait to navigate", async () => {
|
|
380
|
+
// Arrange
|
|
381
|
+
jest.spyOn(window.location, "assign");
|
|
382
|
+
const safeWithNavMock = jest.fn();
|
|
383
|
+
const wrapper = mount(
|
|
384
|
+
<MemoryRouter>
|
|
385
|
+
<div>
|
|
386
|
+
<Clickable
|
|
387
|
+
testId="button"
|
|
388
|
+
href="/foo"
|
|
389
|
+
safeWithNav={safeWithNavMock}
|
|
390
|
+
skipClientNav={false}
|
|
391
|
+
>
|
|
392
|
+
{() => <h1>Click me!</h1>}
|
|
393
|
+
</Clickable>
|
|
394
|
+
<Switch>
|
|
395
|
+
<Route path="/foo">
|
|
396
|
+
<div id="foo">Hello, world!</div>
|
|
397
|
+
</Route>
|
|
398
|
+
</Switch>
|
|
399
|
+
</div>
|
|
400
|
+
</MemoryRouter>,
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
// Act
|
|
404
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
405
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
406
|
+
|
|
407
|
+
// Assert
|
|
408
|
+
expect(safeWithNavMock).toHaveBeenCalled();
|
|
409
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("safeWithNav with beforeNav resolution and skipClientNav=false calls safeWithNav but doesn't wait to navigate", async () => {
|
|
413
|
+
// Arrange
|
|
414
|
+
jest.spyOn(window.location, "assign");
|
|
415
|
+
const safeWithNavMock = jest.fn();
|
|
416
|
+
const wrapper = mount(
|
|
417
|
+
<MemoryRouter>
|
|
418
|
+
<div>
|
|
419
|
+
<Clickable
|
|
420
|
+
testId="button"
|
|
421
|
+
href="/foo"
|
|
422
|
+
beforeNav={() => Promise.resolve()}
|
|
423
|
+
safeWithNav={safeWithNavMock}
|
|
424
|
+
skipClientNav={false}
|
|
425
|
+
>
|
|
426
|
+
{() => <h1>Click me!</h1>}
|
|
427
|
+
</Clickable>
|
|
428
|
+
<Switch>
|
|
429
|
+
<Route path="/foo">
|
|
430
|
+
<div id="foo">Hello, world!</div>
|
|
431
|
+
</Route>
|
|
432
|
+
</Switch>
|
|
433
|
+
</div>
|
|
434
|
+
</MemoryRouter>,
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
// Act
|
|
438
|
+
const buttonWrapper = wrapper.find(`[data-test-id="button"]`).first();
|
|
439
|
+
buttonWrapper.simulate("click", {button: 0});
|
|
440
|
+
await wait(0);
|
|
441
|
+
buttonWrapper.update();
|
|
442
|
+
|
|
443
|
+
// Assert
|
|
444
|
+
expect(safeWithNavMock).toHaveBeenCalled();
|
|
445
|
+
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
describe("raw events", () => {
|
|
449
|
+
/**
|
|
450
|
+
* Clickable expect a function as children so we create a simple wrapper to
|
|
451
|
+
* allow a React.Node to be passed instead.
|
|
452
|
+
*/
|
|
453
|
+
const ClickableWrapper = ({
|
|
454
|
+
children,
|
|
455
|
+
...restProps
|
|
456
|
+
}: {|
|
|
457
|
+
children: React.Node,
|
|
458
|
+
onKeyDown?: (e: SyntheticKeyboardEvent<>) => mixed,
|
|
459
|
+
onKeyUp?: (e: SyntheticKeyboardEvent<>) => mixed,
|
|
460
|
+
|}) => {
|
|
461
|
+
return <Clickable {...restProps}>{() => children}</Clickable>;
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
test("onKeyDown", () => {
|
|
465
|
+
// Arrange
|
|
466
|
+
const keyMock = jest.fn();
|
|
467
|
+
const wrapper = mount(
|
|
468
|
+
<ClickableWrapper onKeyDown={keyMock}>
|
|
469
|
+
Click me!
|
|
470
|
+
</ClickableWrapper>,
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
// Act
|
|
474
|
+
wrapper.find("Clickable").simulate("keydown", {keyCode: 32});
|
|
475
|
+
|
|
476
|
+
// Assert
|
|
477
|
+
expect(keyMock).toHaveBeenCalledWith(
|
|
478
|
+
expect.objectContaining({keyCode: 32}),
|
|
479
|
+
);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test("onKeyUp", () => {
|
|
483
|
+
// Arrange
|
|
484
|
+
const keyMock = jest.fn();
|
|
485
|
+
const wrapper = mount(
|
|
486
|
+
<ClickableWrapper onKeyDown={keyMock}>
|
|
487
|
+
Click me!
|
|
488
|
+
</ClickableWrapper>,
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// Act
|
|
492
|
+
wrapper.find("Clickable").simulate("keydown", {keyCode: 32});
|
|
493
|
+
|
|
494
|
+
// Assert
|
|
495
|
+
expect(keyMock).toHaveBeenCalledWith(
|
|
496
|
+
expect.objectContaining({keyCode: 32}),
|
|
497
|
+
);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
});
|