react-dropzone 13.0.0 → 14.1.0

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/src/index.spec.js CHANGED
@@ -1,12 +1,6 @@
1
1
  /* eslint react/prop-types: 0, jsx-a11y/label-has-for: 0 */
2
2
  import React, { createRef } from "react";
3
- import {
4
- act,
5
- cleanup,
6
- fireEvent,
7
- render,
8
- waitFor,
9
- } from "@testing-library/react";
3
+ import { act, cleanup, fireEvent, render } from "@testing-library/react";
10
4
  import { renderHook } from "@testing-library/react-hooks";
11
5
  import { fromEvent } from "file-selector";
12
6
  import * as utils from "./utils";
@@ -54,9 +48,10 @@ describe("useDropzone() hook", () => {
54
48
  </Dropzone>
55
49
  );
56
50
 
57
- const input = container.querySelector("input");
58
-
59
- expect(input).toHaveAttribute("accept", "image/jpeg");
51
+ expect(container.querySelector("input")).toHaveAttribute(
52
+ "accept",
53
+ "image/jpeg"
54
+ );
60
55
  });
61
56
 
62
57
  it("updates {multiple} prop on the <input> when it changes", () => {
@@ -110,8 +105,7 @@ describe("useDropzone() hook", () => {
110
105
  </Dropzone>
111
106
  );
112
107
 
113
- const input = container.querySelector("input");
114
- expect(input).toHaveAttribute("multiple");
108
+ expect(container.querySelector("input")).toHaveAttribute("multiple");
115
109
  });
116
110
 
117
111
  it("updates {multiple} prop on the <input> when it changes", () => {
@@ -152,8 +146,7 @@ describe("useDropzone() hook", () => {
152
146
  </Dropzone>
153
147
  );
154
148
 
155
- const input = container.querySelector("input");
156
- expect(input).toHaveAttribute("name", name);
149
+ expect(container.querySelector("input")).toHaveAttribute("name", name);
157
150
  });
158
151
 
159
152
  it("sets any props passed to the root props getter on the root node", () => {
@@ -168,9 +161,10 @@ describe("useDropzone() hook", () => {
168
161
  </Dropzone>
169
162
  );
170
163
 
171
- const dropzone = container.querySelector("div");
172
-
173
- expect(dropzone).toHaveAttribute("aria-label", ariaLabel);
164
+ expect(container.querySelector("div")).toHaveAttribute(
165
+ "aria-label",
166
+ ariaLabel
167
+ );
174
168
  });
175
169
 
176
170
  it("runs the custom callback handlers provided to the root props getter", async () => {
@@ -187,7 +181,7 @@ describe("useDropzone() hook", () => {
187
181
  onDrop: jest.fn(),
188
182
  };
189
183
 
190
- const ui = (
184
+ const { container } = render(
191
185
  <Dropzone>
192
186
  {({ getRootProps, getInputProps }) => (
193
187
  <div {...getRootProps(rootProps)}>
@@ -197,8 +191,6 @@ describe("useDropzone() hook", () => {
197
191
  </Dropzone>
198
192
  );
199
193
 
200
- const { container, rerender } = render(ui);
201
-
202
194
  const dropzone = container.querySelector("div");
203
195
 
204
196
  fireEvent.click(dropzone);
@@ -212,8 +204,7 @@ describe("useDropzone() hook", () => {
212
204
  fireEvent.blur(dropzone);
213
205
  expect(rootProps.onBlur).toHaveBeenCalled();
214
206
 
215
- fireEvent.dragEnter(dropzone, event);
216
- await flushPromises(rerender, ui);
207
+ await act(() => fireEvent.dragEnter(dropzone, event));
217
208
  expect(rootProps.onDragEnter).toHaveBeenCalled();
218
209
 
219
210
  fireEvent.dragOver(dropzone, event);
@@ -222,8 +213,7 @@ describe("useDropzone() hook", () => {
222
213
  fireEvent.dragLeave(dropzone, event);
223
214
  expect(rootProps.onDragLeave).toHaveBeenCalled();
224
215
 
225
- fireEvent.drop(dropzone, event);
226
- await flushPromises(rerender, ui);
216
+ await act(() => fireEvent.drop(dropzone, event));
227
217
  expect(rootProps.onDrop).toHaveBeenCalled();
228
218
  });
229
219
 
@@ -233,7 +223,7 @@ describe("useDropzone() hook", () => {
233
223
  onChange: jest.fn(),
234
224
  };
235
225
 
236
- const ui = (
226
+ const { container } = render(
237
227
  <Dropzone>
238
228
  {({ getRootProps, getInputProps }) => (
239
229
  <div {...getRootProps()}>
@@ -243,20 +233,16 @@ describe("useDropzone() hook", () => {
243
233
  </Dropzone>
244
234
  );
245
235
 
246
- const { container, rerender } = render(ui);
247
-
248
236
  const input = container.querySelector("input");
249
237
 
250
238
  fireEvent.click(input);
251
- await flushPromises(rerender, ui);
252
239
  expect(inputProps.onClick).toHaveBeenCalled();
253
240
 
254
- fireEvent.change(input);
255
- await flushPromises(rerender, ui);
241
+ await act(async () => fireEvent.change(input, { target: { files: [] } }));
256
242
  expect(inputProps.onChange).toHaveBeenCalled();
257
243
  });
258
244
 
259
- it("runs no callback handlers if {disabled} is true", () => {
245
+ it("runs no callback handlers if {disabled} is true", async () => {
260
246
  const event = createDtWithFiles(files);
261
247
 
262
248
  const rootProps = {
@@ -298,7 +284,7 @@ describe("useDropzone() hook", () => {
298
284
  fireEvent.blur(dropzone);
299
285
  expect(rootProps.onBlur).not.toHaveBeenCalled();
300
286
 
301
- fireEvent.dragEnter(dropzone, event);
287
+ await act(() => fireEvent.dragEnter(dropzone, event));
302
288
  expect(rootProps.onDragEnter).not.toHaveBeenCalled();
303
289
 
304
290
  fireEvent.dragOver(dropzone, event);
@@ -307,7 +293,7 @@ describe("useDropzone() hook", () => {
307
293
  fireEvent.dragLeave(dropzone, event);
308
294
  expect(rootProps.onDragLeave).not.toHaveBeenCalled();
309
295
 
310
- fireEvent.drop(dropzone, event);
296
+ await act(() => fireEvent.drop(dropzone, event));
311
297
  expect(rootProps.onDrop).not.toHaveBeenCalled();
312
298
 
313
299
  const input = container.querySelector("input");
@@ -315,7 +301,7 @@ describe("useDropzone() hook", () => {
315
301
  fireEvent.click(input);
316
302
  expect(inputProps.onClick).not.toHaveBeenCalled();
317
303
 
318
- fireEvent.change(input);
304
+ await act(() => fireEvent.change(input));
319
305
  expect(inputProps.onChange).not.toHaveBeenCalled();
320
306
  });
321
307
 
@@ -535,8 +521,8 @@ describe("useDropzone() hook", () => {
535
521
  const dropzone = container.querySelector("#dropzone");
536
522
 
537
523
  const fn = async () => {
538
- fireDrop(dropzone, data);
539
- await flushPromises(rerender, ui);
524
+ await act(() => fireEvent.drop(dropzone, data));
525
+ rerender(ui);
540
526
  done();
541
527
  };
542
528
 
@@ -561,13 +547,10 @@ describe("useDropzone() hook", () => {
561
547
 
562
548
  const dropzone = container.querySelector("label");
563
549
 
564
- const event = new Event("click", { bubbles: true, cancelable: true });
550
+ fireEvent.click(dropzone, { bubbles: true, cancelable: true });
565
551
 
566
- fireEvent(dropzone, event);
567
-
568
- const ref = activeRef.current;
569
- expect(ref).not.toBeNull();
570
- expect(dropzone).toContainElement(ref);
552
+ expect(activeRef.current).not.toBeNull();
553
+ expect(dropzone).toContainElement(activeRef.current);
571
554
  expect(onClickSpy).toHaveBeenCalledTimes(1);
572
555
  });
573
556
  });
@@ -674,12 +657,11 @@ describe("useDropzone() hook", () => {
674
657
  )}
675
658
  </Dropzone>
676
659
  );
677
- const dropzone = container.querySelector("div");
678
660
 
679
661
  const dropEvt = new Event("drop", { bubbles: true });
680
662
  const dropEvtPreventDefaultSpy = jest.spyOn(dropEvt, "preventDefault");
681
663
 
682
- fireEvent(dropzone, dropEvt);
664
+ fireEvent(container.querySelector("div"), dropEvt);
683
665
  // A call is from the onDrop handler for the dropzone,
684
666
  // but there should be no more than 1
685
667
  expect(dropEvtPreventDefaultSpy).toHaveBeenCalled();
@@ -731,7 +713,7 @@ describe("useDropzone() hook", () => {
731
713
  onDrop: jest.fn(),
732
714
  };
733
715
 
734
- const ui = (
716
+ const { container } = render(
735
717
  <Dropzone {...parentProps}>
736
718
  {({ getRootProps, getInputProps }) => (
737
719
  <div {...getRootProps()}>
@@ -742,25 +724,21 @@ describe("useDropzone() hook", () => {
742
724
  </Dropzone>
743
725
  );
744
726
 
745
- const { container, rerender } = render(ui);
746
-
747
727
  const innerDropzone = container.querySelector("#inner-dropzone");
748
728
 
749
- fireDragEnter(innerDropzone, data);
750
- await flushPromises(rerender, ui);
729
+ await act(() => fireEvent.dragEnter(innerDropzone, data));
751
730
  expect(innerProps.onDragEnter).toHaveBeenCalled();
752
731
  expect(parentProps.onDragEnter).toHaveBeenCalled();
753
732
 
754
- fireDragOver(innerDropzone, data);
733
+ fireEvent.dragOver(innerDropzone, data);
755
734
  expect(innerProps.onDragOver).toHaveBeenCalled();
756
735
  expect(parentProps.onDragOver).toHaveBeenCalled();
757
736
 
758
- fireDragLeave(innerDropzone, data);
737
+ fireEvent.dragLeave(innerDropzone, data);
759
738
  expect(innerProps.onDragLeave).toHaveBeenCalled();
760
739
  expect(parentProps.onDragLeave).toHaveBeenCalled();
761
740
 
762
- fireDrop(innerDropzone, data);
763
- await flushPromises(rerender, ui);
741
+ await act(() => fireEvent.drop(innerDropzone, data));
764
742
  expect(innerProps.onDrop).toHaveBeenCalled();
765
743
  expect(parentProps.onDrop).toHaveBeenCalled();
766
744
  });
@@ -797,7 +775,7 @@ describe("useDropzone() hook", () => {
797
775
  onDrop: jest.fn(),
798
776
  };
799
777
 
800
- const ui = (
778
+ const { container } = render(
801
779
  <Dropzone {...parentProps}>
802
780
  {({ getRootProps, getInputProps }) => (
803
781
  <div {...getRootProps()}>
@@ -808,25 +786,21 @@ describe("useDropzone() hook", () => {
808
786
  </Dropzone>
809
787
  );
810
788
 
811
- const { container, rerender } = render(ui);
812
-
813
789
  const innerDropzone = container.querySelector("#inner-dropzone");
814
790
 
815
- fireDragEnter(innerDropzone, data);
816
- await flushPromises(rerender, ui);
791
+ await act(() => fireEvent.dragEnter(innerDropzone, data));
817
792
  expect(innerProps.onDragEnter).toHaveBeenCalled();
818
793
  expect(parentProps.onDragEnter).not.toHaveBeenCalled();
819
794
 
820
- fireDragOver(innerDropzone, data);
795
+ fireEvent.dragOver(innerDropzone, data);
821
796
  expect(innerProps.onDragOver).toHaveBeenCalled();
822
797
  expect(parentProps.onDragOver).not.toHaveBeenCalled();
823
798
 
824
- fireDragLeave(innerDropzone, data);
799
+ fireEvent.dragLeave(innerDropzone, data);
825
800
  expect(innerProps.onDragLeave).toHaveBeenCalled();
826
801
  expect(parentProps.onDragLeave).not.toHaveBeenCalled();
827
802
 
828
- fireDrop(innerDropzone, data);
829
- await flushPromises(rerender, ui);
803
+ await act(() => fireEvent.drop(innerDropzone, data));
830
804
  expect(innerProps.onDrop).toHaveBeenCalled();
831
805
  expect(parentProps.onDrop).not.toHaveBeenCalled();
832
806
  });
@@ -856,7 +830,7 @@ describe("useDropzone() hook", () => {
856
830
  onDrop: jest.fn(),
857
831
  };
858
832
 
859
- const ui = (
833
+ const { container } = render(
860
834
  <Dropzone {...parentProps}>
861
835
  {({ getRootProps, getInputProps }) => (
862
836
  <div id="outer-dropzone" {...getRootProps()}>
@@ -867,30 +841,25 @@ describe("useDropzone() hook", () => {
867
841
  </Dropzone>
868
842
  );
869
843
 
870
- const { container, rerender } = render(ui);
871
-
872
844
  const outerDropzone = container.querySelector("#outer-dropzone");
873
845
  const innerDropzone = container.querySelector("#inner-dropzone");
874
846
 
875
847
  // Sets drag targets on the outer dropzone
876
- fireDragEnter(outerDropzone, data);
877
- await flushPromises(rerender, ui);
848
+ await act(() => fireEvent.dragEnter(outerDropzone, data));
878
849
 
879
- fireDragEnter(innerDropzone, data);
880
- await flushPromises(rerender, ui);
850
+ await act(() => fireEvent.dragEnter(innerDropzone, data));
881
851
  expect(innerProps.onDragEnter).toHaveBeenCalled();
882
852
  expect(parentProps.onDragEnter).toHaveBeenCalledTimes(1);
883
853
 
884
- fireDragOver(innerDropzone, data);
854
+ fireEvent.dragOver(innerDropzone, data);
885
855
  expect(innerProps.onDragOver).toHaveBeenCalled();
886
856
  expect(parentProps.onDragOver).not.toHaveBeenCalled();
887
857
 
888
- fireDragLeave(innerDropzone, data);
858
+ fireEvent.dragLeave(innerDropzone, data);
889
859
  expect(innerProps.onDragLeave).toHaveBeenCalled();
890
860
  expect(parentProps.onDragLeave).not.toHaveBeenCalled();
891
861
 
892
- fireDrop(innerDropzone, data);
893
- await flushPromises(rerender, ui);
862
+ await act(() => fireEvent.drop(innerDropzone, data));
894
863
  expect(innerProps.onDrop).toHaveBeenCalled();
895
864
  expect(parentProps.onDrop).not.toHaveBeenCalled();
896
865
  });
@@ -908,7 +877,8 @@ describe("useDropzone() hook", () => {
908
877
  );
909
878
 
910
879
  const parentDragLeave = jest.fn();
911
- const ui = (
880
+
881
+ const { container } = render(
912
882
  <Dropzone onDragLeave={parentDragLeave}>
913
883
  {({ getRootProps, getInputProps }) => (
914
884
  <div id="parent-dropzone" {...getRootProps()}>
@@ -919,18 +889,14 @@ describe("useDropzone() hook", () => {
919
889
  </Dropzone>
920
890
  );
921
891
 
922
- const { container, rerender } = render(ui);
923
-
924
892
  const parentDropzone = container.querySelector("#parent-dropzone");
925
893
 
926
- fireDragEnter(parentDropzone, data);
927
- await flushPromises(rerender, ui);
894
+ await act(() => fireEvent.dragEnter(parentDropzone, data));
928
895
 
929
896
  const innerDropzone = container.querySelector("#inner-dropzone");
930
- fireDragEnter(innerDropzone, data);
931
- await flushPromises(rerender, ui);
897
+ await act(() => fireEvent.dragEnter(innerDropzone, data));
932
898
 
933
- fireDragLeave(innerDropzone, data);
899
+ fireEvent.dragLeave(innerDropzone, data);
934
900
  expect(innerDragLeave).toHaveBeenCalled();
935
901
  expect(parentDragLeave).not.toHaveBeenCalled();
936
902
  });
@@ -950,7 +916,7 @@ describe("useDropzone() hook", () => {
950
916
  onDrop: jest.fn(),
951
917
  };
952
918
 
953
- const ui = (
919
+ const { container } = render(
954
920
  <Dropzone {...props}>
955
921
  {({ getRootProps, getInputProps }) => (
956
922
  <div {...getRootProps()}>
@@ -959,23 +925,19 @@ describe("useDropzone() hook", () => {
959
925
  )}
960
926
  </Dropzone>
961
927
  );
962
- const { container, rerender } = render(ui);
963
928
  const dropzone = container.querySelector("div");
964
929
 
965
- fireDragEnter(dropzone, data);
966
- await flushPromises(rerender, ui);
930
+ await act(() => fireEvent.dragEnter(dropzone, data));
967
931
  expect(props.onDragEnter).toHaveBeenCalled();
968
932
 
969
- fireDragOver(dropzone, data);
933
+ fireEvent.dragOver(dropzone, data);
970
934
  expect(props.onDragOver).toHaveBeenCalled();
971
935
 
972
- fireDragLeave(dropzone, data);
936
+ fireEvent.dragLeave(dropzone, data);
973
937
  expect(props.onDragLeave).toHaveBeenCalled();
974
938
 
975
- fireDrop(dropzone, data);
976
- await flushPromises(rerender, ui);
939
+ await act(() => fireEvent.drop(dropzone, data));
977
940
  expect(props.onDrop).toHaveBeenCalled();
978
-
979
941
  expect(props.getFilesFromEvent).toHaveBeenCalledTimes(2);
980
942
  });
981
943
 
@@ -1000,15 +962,13 @@ describe("useDropzone() hook", () => {
1000
962
  )}
1001
963
  </Dropzone>
1002
964
  );
1003
- const { container, rerender } = render(ui);
965
+ const { container } = render(ui);
1004
966
  const dropzone = container.querySelector("div");
1005
967
 
1006
- fireDragEnter(dropzone, data);
1007
- await flushPromises(rerender, ui);
968
+ await act(() => fireEvent.dragEnter(dropzone, data));
1008
969
  expect(props.onDragEnter).not.toHaveBeenCalled();
1009
970
 
1010
- fireDrop(dropzone, data);
1011
- await flushPromises(rerender, ui);
971
+ await act(() => fireEvent.drop(dropzone, data));
1012
972
  expect(props.onDrop).not.toHaveBeenCalled();
1013
973
 
1014
974
  expect(props.getFilesFromEvent).toHaveBeenCalledTimes(2);
@@ -1104,6 +1064,51 @@ describe("useDropzone() hook", () => {
1104
1064
  fireEvent.focus(dropzone);
1105
1065
  expect(dropzone.querySelector("#focus")).not.toBeNull();
1106
1066
  });
1067
+
1068
+ it("{autoFocus} sets the focus state on render", () => {
1069
+ const { container, rerender } = render(
1070
+ <Dropzone>
1071
+ {({ getRootProps, getInputProps, isFocused }) => (
1072
+ <div {...getRootProps()}>
1073
+ <input {...getInputProps()} />
1074
+ {isFocused && <div id="focus" />}
1075
+ </div>
1076
+ )}
1077
+ </Dropzone>
1078
+ );
1079
+
1080
+ const dropzone = container.querySelector("div");
1081
+
1082
+ expect(dropzone.querySelector("#focus")).toBeNull();
1083
+
1084
+ rerender(
1085
+ /* eslint-disable-next-line jsx-a11y/no-autofocus */
1086
+ <Dropzone autoFocus>
1087
+ {({ getRootProps, getInputProps, isFocused }) => (
1088
+ <div {...getRootProps()}>
1089
+ <input {...getInputProps()} />
1090
+ {isFocused && <div id="focus" />}
1091
+ </div>
1092
+ )}
1093
+ </Dropzone>
1094
+ );
1095
+
1096
+ expect(dropzone.querySelector("#focus")).not.toBeNull();
1097
+
1098
+ rerender(
1099
+ /* eslint-disable-next-line jsx-a11y/no-autofocus */
1100
+ <Dropzone autoFocus disabled>
1101
+ {({ getRootProps, getInputProps, isFocused }) => (
1102
+ <div {...getRootProps()}>
1103
+ <input {...getInputProps()} />
1104
+ {isFocused && <div id="focus" />}
1105
+ </div>
1106
+ )}
1107
+ </Dropzone>
1108
+ );
1109
+
1110
+ expect(dropzone.querySelector("#focus")).toBeNull();
1111
+ });
1107
1112
  });
1108
1113
 
1109
1114
  describe("onBlur", () => {
@@ -1263,9 +1268,8 @@ describe("useDropzone() hook", () => {
1263
1268
  const dropzone = container.querySelector("div");
1264
1269
 
1265
1270
  fireEvent.click(dropzone);
1266
- const ref = activeRef.current;
1267
- expect(ref).not.toBeNull();
1268
- expect(dropzone).toContainElement(ref);
1271
+ expect(activeRef.current).not.toBeNull();
1272
+ expect(dropzone).toContainElement(activeRef.current);
1269
1273
  expect(onClickSpy).toHaveBeenCalled();
1270
1274
  });
1271
1275
 
@@ -1283,9 +1287,7 @@ describe("useDropzone() hook", () => {
1283
1287
  </Dropzone>
1284
1288
  );
1285
1289
 
1286
- const dropzone = container.querySelector("div");
1287
-
1288
- fireEvent.click(dropzone);
1290
+ fireEvent.click(container.querySelector("div"));
1289
1291
  expect(onClickSpy).not.toHaveBeenCalled();
1290
1292
  });
1291
1293
 
@@ -1301,9 +1303,7 @@ describe("useDropzone() hook", () => {
1301
1303
  </Dropzone>
1302
1304
  );
1303
1305
 
1304
- const dropzone = container.querySelector("div");
1305
-
1306
- fireEvent.click(dropzone);
1306
+ fireEvent.click(container.querySelector("div"));
1307
1307
  expect(onClickSpy).not.toHaveBeenCalled();
1308
1308
  });
1309
1309
 
@@ -1353,13 +1353,10 @@ describe("useDropzone() hook", () => {
1353
1353
  </Dropzone>
1354
1354
  );
1355
1355
 
1356
- const dropzone = container.querySelector("div");
1357
- const btn = container.querySelector("button");
1358
-
1359
- fireEvent.click(dropzone);
1356
+ fireEvent.click(container.querySelector("div"));
1360
1357
  expect(inputClickSpy).not.toHaveBeenCalled();
1361
1358
 
1362
- fireEvent.click(btn);
1359
+ fireEvent.click(container.querySelector("button"));
1363
1360
  expect(btnClickSpy).toHaveBeenCalled();
1364
1361
  });
1365
1362
 
@@ -1371,7 +1368,7 @@ describe("useDropzone() hook", () => {
1371
1368
  .mockReturnValueOnce(true);
1372
1369
  const onClickSpy = jest.spyOn(HTMLInputElement.prototype, "click");
1373
1370
 
1374
- const ui = (
1371
+ const { container } = render(
1375
1372
  <Dropzone>
1376
1373
  {({ getRootProps, getInputProps }) => (
1377
1374
  <div {...getRootProps()}>
@@ -1381,36 +1378,29 @@ describe("useDropzone() hook", () => {
1381
1378
  </Dropzone>
1382
1379
  );
1383
1380
 
1384
- const { container } = render(ui);
1385
-
1386
- const dropzone = container.querySelector("div");
1387
-
1388
- fireEvent.click(dropzone);
1389
- drainTimers();
1381
+ fireEvent.click(container.querySelector("div"));
1382
+ drainPendingTimers();
1390
1383
 
1391
1384
  expect(onClickSpy).toHaveBeenCalled();
1392
1385
  jest.useRealTimers();
1393
1386
  isIeOrEdgeSpy.mockClear();
1394
1387
  });
1395
1388
 
1396
- it("should not use showOpenFilePicker() if supported and {useFsAccessApi} is not true", async () => {
1389
+ it("should not use showOpenFilePicker() if supported and {useFsAccessApi} is not true", () => {
1397
1390
  jest.useFakeTimers();
1398
1391
 
1399
1392
  const activeRef = createRef();
1400
1393
  const active = <span ref={activeRef}>I am active</span>;
1401
1394
  const onClickSpy = jest.spyOn(HTMLInputElement.prototype, "click");
1402
1395
 
1403
- const handlers = files.map((f) => createFileSystemFileHandle(f));
1404
- const showOpenFilePickerMock = jest
1405
- .fn()
1406
- .mockReturnValue(Promise.resolve(handlers));
1396
+ const showOpenFilePickerMock = jest.fn();
1407
1397
 
1408
1398
  window.showOpenFilePicker = showOpenFilePickerMock;
1409
1399
 
1410
1400
  const onDropSpy = jest.fn();
1411
1401
  const onFileDialogOpenSpy = jest.fn();
1412
1402
 
1413
- const ui = (
1403
+ const { container } = render(
1414
1404
  <Dropzone
1415
1405
  onDrop={onDropSpy}
1416
1406
  onFileDialogOpen={onFileDialogOpenSpy}
@@ -1429,39 +1419,34 @@ describe("useDropzone() hook", () => {
1429
1419
  </Dropzone>
1430
1420
  );
1431
1421
 
1432
- const { container, rerender } = render(ui);
1433
-
1434
1422
  const dropzone = container.querySelector("div");
1435
1423
 
1436
1424
  fireEvent.click(dropzone);
1437
1425
 
1438
- await flushPromises(rerender, ui);
1439
-
1440
- dispatchEvt(document.body, "focus");
1441
- drainTimers();
1442
-
1426
+ expect(showOpenFilePickerMock).not.toHaveBeenCalled();
1427
+ expect(onClickSpy).toHaveBeenCalled();
1443
1428
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
1429
+ expect(activeRef.current).not.toBeNull();
1430
+ expect(dropzone).toContainElement(activeRef.current);
1431
+
1432
+ focusWindow();
1433
+ drainPendingTimers();
1444
1434
 
1445
1435
  expect(activeRef.current).toBeNull();
1446
1436
  expect(dropzone).not.toContainElement(activeRef.current);
1447
- expect(onClickSpy).toHaveBeenCalled();
1448
- expect(showOpenFilePickerMock).not.toHaveBeenCalled();
1449
1437
  expect(onDropSpy).not.toHaveBeenCalled();
1450
1438
 
1451
1439
  jest.useRealTimers();
1452
1440
  });
1453
1441
 
1454
- it("should not use showOpenFilePicker() if supported and {isSecureContext} is not true", async () => {
1442
+ it("should not use showOpenFilePicker() if supported and {isSecureContext} is not true", () => {
1455
1443
  jest.useFakeTimers();
1456
1444
 
1457
1445
  const activeRef = createRef();
1458
1446
  const active = <span ref={activeRef}>I am active</span>;
1459
1447
  const onClickSpy = jest.spyOn(HTMLInputElement.prototype, "click");
1460
1448
 
1461
- const handlers = files.map((f) => createFileSystemFileHandle(f));
1462
- const showOpenFilePickerMock = jest
1463
- .fn()
1464
- .mockReturnValue(Promise.resolve(handlers));
1449
+ const showOpenFilePickerMock = jest.fn();
1465
1450
 
1466
1451
  window.showOpenFilePicker = showOpenFilePickerMock;
1467
1452
  window.isSecureContext = false;
@@ -1469,7 +1454,7 @@ describe("useDropzone() hook", () => {
1469
1454
  const onDropSpy = jest.fn();
1470
1455
  const onFileDialogOpenSpy = jest.fn();
1471
1456
 
1472
- const ui = (
1457
+ const { container } = render(
1473
1458
  <Dropzone
1474
1459
  onDrop={onDropSpy}
1475
1460
  onFileDialogOpen={onFileDialogOpenSpy}
@@ -1487,23 +1472,21 @@ describe("useDropzone() hook", () => {
1487
1472
  </Dropzone>
1488
1473
  );
1489
1474
 
1490
- const { container, rerender } = render(ui);
1491
-
1492
1475
  const dropzone = container.querySelector("div");
1493
1476
 
1494
1477
  fireEvent.click(dropzone);
1495
1478
 
1496
- await flushPromises(rerender, ui);
1497
-
1498
- dispatchEvt(document.body, "focus");
1499
- drainTimers();
1500
-
1479
+ expect(showOpenFilePickerMock).not.toHaveBeenCalled();
1480
+ expect(onClickSpy).toHaveBeenCalled();
1501
1481
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
1482
+ expect(activeRef.current).not.toBeNull();
1483
+ expect(dropzone).toContainElement(activeRef.current);
1484
+
1485
+ focusWindow();
1486
+ drainPendingTimers();
1502
1487
 
1503
1488
  expect(activeRef.current).toBeNull();
1504
1489
  expect(dropzone).not.toContainElement(activeRef.current);
1505
- expect(onClickSpy).toHaveBeenCalled();
1506
- expect(showOpenFilePickerMock).not.toHaveBeenCalled();
1507
1490
  expect(onDropSpy).not.toHaveBeenCalled();
1508
1491
 
1509
1492
  jest.useRealTimers();
@@ -1527,7 +1510,7 @@ describe("useDropzone() hook", () => {
1527
1510
  const onDropSpy = jest.fn();
1528
1511
  const onFileDialogOpenSpy = jest.fn();
1529
1512
 
1530
- const ui = (
1513
+ const { container } = render(
1531
1514
  <Dropzone
1532
1515
  onDrop={onDropSpy}
1533
1516
  onFileDialogOpen={onFileDialogOpenSpy}
@@ -1546,24 +1529,10 @@ describe("useDropzone() hook", () => {
1546
1529
  </Dropzone>
1547
1530
  );
1548
1531
 
1549
- const { container, rerender } = render(ui);
1550
-
1551
1532
  const dropzone = container.querySelector("div");
1552
1533
 
1553
1534
  fireEvent.click(dropzone);
1554
1535
 
1555
- await flushPromises(rerender, ui);
1556
-
1557
- expect(activeRef.current).not.toBeNull();
1558
- expect(dropzone).toContainElement(activeRef.current);
1559
- expect(onFileDialogOpenSpy).toHaveBeenCalled();
1560
-
1561
- thenable.done(handlers);
1562
- await flushPromises(rerender, ui);
1563
-
1564
- expect(activeRef.current).toBeNull(); // We expect the dialog to be closed at this point
1565
- expect(dropzone).not.toContainElement(activeRef.current);
1566
- expect(onClickSpy).not.toHaveBeenCalled();
1567
1536
  expect(showOpenFilePickerMock).toHaveBeenCalledWith({
1568
1537
  multiple: true,
1569
1538
  types: [
@@ -1572,6 +1541,17 @@ describe("useDropzone() hook", () => {
1572
1541
  },
1573
1542
  ],
1574
1543
  });
1544
+ expect(onClickSpy).not.toHaveBeenCalled();
1545
+ expect(onFileDialogOpenSpy).toHaveBeenCalled();
1546
+
1547
+ expect(activeRef.current).not.toBeNull();
1548
+ expect(dropzone).toContainElement(activeRef.current);
1549
+
1550
+ await act(() => thenable.done(handlers));
1551
+
1552
+ expect(activeRef.current).toBeNull();
1553
+ expect(dropzone).not.toContainElement(activeRef.current);
1554
+
1575
1555
  expect(onDropSpy).toHaveBeenCalledWith(files, [], null);
1576
1556
  });
1577
1557
 
@@ -1580,16 +1560,17 @@ describe("useDropzone() hook", () => {
1580
1560
  const active = <span ref={activeRef}>I am active</span>;
1581
1561
 
1582
1562
  const handlers = files.map((f) => createFileSystemFileHandle(f));
1563
+ const thenable = createThenable();
1583
1564
  const showOpenFilePickerMock = jest
1584
1565
  .fn()
1585
- .mockReturnValue(Promise.resolve(handlers));
1566
+ .mockReturnValue(thenable.promise);
1586
1567
 
1587
1568
  window.showOpenFilePicker = showOpenFilePickerMock;
1588
1569
 
1589
1570
  const onDropSpy = jest.fn();
1590
1571
  const onFileDialogOpenSpy = jest.fn();
1591
1572
 
1592
- const ui = (
1573
+ const { container } = render(
1593
1574
  <Dropzone
1594
1575
  onDrop={onDropSpy}
1595
1576
  onFileDialogOpen={onFileDialogOpenSpy}
@@ -1601,36 +1582,35 @@ describe("useDropzone() hook", () => {
1601
1582
  </Dropzone>
1602
1583
  );
1603
1584
 
1604
- const { container, rerender } = render(ui);
1605
-
1606
1585
  const dropzone = container.querySelector("div");
1607
1586
 
1608
1587
  fireEvent.click(dropzone);
1609
- await flushPromises(rerender, ui);
1610
- const ref = activeRef.current;
1611
- expect(ref).toBeNull(); // We expect the dialog to be closed at this point
1612
- expect(dropzone).not.toContainElement(ref);
1588
+
1613
1589
  expect(showOpenFilePickerMock).toHaveBeenCalled();
1614
- expect(onDropSpy).toHaveBeenCalledWith(files, [], null);
1615
1590
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
1591
+
1592
+ await act(() => thenable.done(handlers));
1593
+
1594
+ expect(activeRef.current).toBeNull();
1595
+ expect(dropzone).not.toContainElement(activeRef.current);
1596
+ expect(onDropSpy).toHaveBeenCalledWith(files, [], null);
1616
1597
  });
1617
1598
 
1618
1599
  test("if showOpenFilePicker() is supported and {useFsAccessApi} is true, and the user cancels it should call onFileDialogCancel", async () => {
1619
1600
  const activeRef = createRef();
1620
1601
  const active = <span ref={activeRef}>I am active</span>;
1621
1602
 
1603
+ const thenable = createThenable();
1622
1604
  const showOpenFilePickerMock = jest
1623
1605
  .fn()
1624
- .mockReturnValue(
1625
- Promise.reject(new DOMException("user aborted request", "AbortError"))
1626
- );
1606
+ .mockReturnValue(thenable.promise);
1627
1607
 
1628
1608
  window.showOpenFilePicker = showOpenFilePickerMock;
1629
1609
 
1630
1610
  const onDropSpy = jest.fn();
1631
1611
  const onFileDialogCancelSpy = jest.fn();
1632
1612
 
1633
- const ui = (
1613
+ const { container } = render(
1634
1614
  <Dropzone
1635
1615
  onDrop={onDropSpy}
1636
1616
  onFileDialogCancel={onFileDialogCancelSpy}
@@ -1642,18 +1622,20 @@ describe("useDropzone() hook", () => {
1642
1622
  </Dropzone>
1643
1623
  );
1644
1624
 
1645
- const { container, rerender } = render(ui);
1646
-
1647
1625
  const dropzone = container.querySelector("div");
1648
1626
 
1649
1627
  fireEvent.click(dropzone);
1650
- await flushPromises(rerender, ui);
1651
- const ref = activeRef.current;
1652
- expect(ref).toBeNull(); // We expect the dialog to be closed at this point
1653
- expect(dropzone).not.toContainElement(ref);
1628
+
1654
1629
  expect(showOpenFilePickerMock).toHaveBeenCalled();
1655
- expect(onDropSpy).not.toHaveBeenCalled();
1630
+
1631
+ await act(() =>
1632
+ thenable.cancel(new DOMException("user aborted request", "AbortError"))
1633
+ );
1634
+
1635
+ expect(activeRef.current).toBeNull();
1636
+ expect(dropzone).not.toContainElement(activeRef.current);
1656
1637
  expect(onFileDialogCancelSpy).toHaveBeenCalled();
1638
+ expect(onDropSpy).not.toHaveBeenCalled();
1657
1639
  });
1658
1640
 
1659
1641
  test("window focus evt is not bound if showOpenFilePicker() is supported and {useFsAccessApi} is true", async () => {
@@ -1670,44 +1652,32 @@ describe("useDropzone() hook", () => {
1670
1652
 
1671
1653
  window.showOpenFilePicker = showOpenFilePickerMock;
1672
1654
 
1673
- const ui = (
1674
- <Dropzone
1675
- onFileDialogCancel={onFileDialogCancelSpy}
1676
- noClick
1677
- useFsAccessApi
1678
- >
1679
- {({ getRootProps, isFileDialogActive, open }) => (
1680
- <div {...getRootProps()}>
1681
- {isFileDialogActive && active}
1682
- <button type="button" onClick={open}>
1683
- Open
1684
- </button>
1685
- </div>
1655
+ const { container } = render(
1656
+ <Dropzone onFileDialogCancel={onFileDialogCancelSpy} useFsAccessApi>
1657
+ {({ getRootProps, isFileDialogActive }) => (
1658
+ <div {...getRootProps()}>{isFileDialogActive && active}</div>
1686
1659
  )}
1687
1660
  </Dropzone>
1688
1661
  );
1689
1662
 
1690
- const { container, rerender } = render(ui);
1691
-
1692
1663
  const dropzone = container.querySelector("div");
1693
- const btn = container.querySelector("button");
1694
1664
 
1695
- btn.click();
1696
- drainTimers();
1697
- await flushPromises(rerender, ui);
1665
+ fireEvent.click(dropzone);
1698
1666
 
1699
- const ref = activeRef.current;
1700
- expect(ref).not.toBeNull();
1701
- expect(dropzone).toContainElement(ref);
1667
+ expect(activeRef.current).not.toBeNull();
1668
+ expect(dropzone).toContainElement(activeRef.current);
1702
1669
 
1703
- thenable.cancel(new DOMException("user aborted request", "AbortError"));
1670
+ await act(() =>
1671
+ thenable.cancel(new DOMException("user aborted request", "AbortError"))
1672
+ );
1704
1673
 
1705
- dispatchEvt(document.body, "focus");
1706
- drainTimers();
1707
- await flushPromises(rerender, ui);
1674
+ // Try to focus window and run timers
1675
+ focusWindow();
1676
+ drainPendingTimers();
1708
1677
 
1678
+ expect(activeRef.current).toBeNull();
1679
+ expect(dropzone).not.toContainElement(activeRef.current);
1709
1680
  expect(onFileDialogCancelSpy).toHaveBeenCalledTimes(1);
1710
- expect(dropzone).not.toContainElement(ref);
1711
1681
 
1712
1682
  jest.useRealTimers();
1713
1683
  });
@@ -1727,7 +1697,7 @@ describe("useDropzone() hook", () => {
1727
1697
  const onDropSpy = jest.fn();
1728
1698
  const onFileDialogOpenSpy = jest.fn();
1729
1699
 
1730
- const ui = (
1700
+ const { container } = render(
1731
1701
  <Dropzone
1732
1702
  onDrop={onDropSpy}
1733
1703
  onFileDialogOpen={onFileDialogOpenSpy}
@@ -1746,22 +1716,19 @@ describe("useDropzone() hook", () => {
1746
1716
  </Dropzone>
1747
1717
  );
1748
1718
 
1749
- const { container, rerender } = render(ui);
1750
-
1751
1719
  const dropzone = container.querySelector("div");
1752
1720
 
1753
1721
  fireEvent.click(dropzone);
1754
1722
 
1755
- await flushPromises(rerender, ui);
1756
-
1757
1723
  expect(activeRef.current).not.toBeNull();
1758
1724
  expect(dropzone).toContainElement(activeRef.current);
1759
1725
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
1760
1726
 
1761
- thenable.cancel(
1762
- new DOMException("Cannot use this API cross-origin", "SecurityError")
1727
+ await act(() =>
1728
+ thenable.cancel(
1729
+ new DOMException("Cannot use this API cross-origin", "SecurityError")
1730
+ )
1763
1731
  );
1764
- await flushPromises(rerender, ui);
1765
1732
 
1766
1733
  expect(activeRef.current).not.toBeNull();
1767
1734
  expect(dropzone).toContainElement(activeRef.current);
@@ -1782,7 +1749,7 @@ describe("useDropzone() hook", () => {
1782
1749
 
1783
1750
  window.showOpenFilePicker = showOpenFilePickerMock;
1784
1751
 
1785
- const ui = (
1752
+ const { container } = render(
1786
1753
  <Dropzone onFileDialogCancel={onFileDialogCancelSpy}>
1787
1754
  {({ getRootProps, getInputProps, isFileDialogActive }) => (
1788
1755
  <div {...getRootProps()}>
@@ -1793,31 +1760,24 @@ describe("useDropzone() hook", () => {
1793
1760
  </Dropzone>
1794
1761
  );
1795
1762
 
1796
- const { container, rerender } = render(ui);
1797
-
1798
1763
  const dropzone = container.querySelector("div");
1799
1764
 
1800
1765
  fireEvent.click(dropzone);
1801
1766
 
1802
- drainTimers();
1803
- await flushPromises(rerender, ui);
1804
-
1805
- const ref = activeRef.current;
1806
- expect(ref).not.toBeNull();
1807
- expect(dropzone).toContainElement(ref);
1767
+ expect(activeRef.current).not.toBeNull();
1768
+ expect(dropzone).toContainElement(activeRef.current);
1808
1769
 
1809
- thenable.cancel(
1810
- new DOMException("Cannot use this API cross-origin", "SecurityError")
1770
+ await act(() =>
1771
+ thenable.cancel(
1772
+ new DOMException("Cannot use this API cross-origin", "SecurityError")
1773
+ )
1811
1774
  );
1812
1775
 
1813
- await flushPromises(rerender, ui);
1814
-
1815
- dispatchEvt(document.body, "focus");
1816
- drainTimers();
1817
- await flushPromises(rerender, ui);
1776
+ focusWindow();
1777
+ drainPendingTimers();
1818
1778
 
1819
1779
  expect(onFileDialogCancelSpy).toHaveBeenCalled();
1820
- expect(dropzone).not.toContainElement(ref);
1780
+ expect(dropzone).not.toContainElement(activeRef.current);
1821
1781
 
1822
1782
  jest.useRealTimers();
1823
1783
  });
@@ -1857,22 +1817,18 @@ describe("useDropzone() hook", () => {
1857
1817
  </Dropzone>
1858
1818
  );
1859
1819
 
1860
- const { container, rerender } = render(ui);
1820
+ const { container } = render(ui);
1861
1821
 
1862
1822
  const dropzone = container.querySelector("div");
1863
1823
 
1864
1824
  fireEvent.click(dropzone);
1865
1825
 
1866
- await flushPromises(rerender, ui);
1867
-
1868
1826
  expect(activeRef.current).not.toBeNull();
1869
1827
  expect(dropzone).toContainElement(activeRef.current);
1870
1828
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
1871
1829
 
1872
1830
  const err = new Error("oops :(");
1873
- thenable.cancel(err);
1874
- await flushPromises(rerender, ui);
1875
-
1831
+ await act(() => thenable.cancel(err));
1876
1832
  expect(activeRef.current).not.toBeNull();
1877
1833
  expect(dropzone).toContainElement(activeRef.current);
1878
1834
  expect(onErrorSpy).toHaveBeenCalledWith(err);
@@ -2070,7 +2026,7 @@ describe("useDropzone() hook", () => {
2070
2026
  onDrop: jest.fn(),
2071
2027
  };
2072
2028
 
2073
- const ui = (
2029
+ const { container } = render(
2074
2030
  <Dropzone {...props}>
2075
2031
  {({ getRootProps, getInputProps }) => (
2076
2032
  <div {...getRootProps()}>
@@ -2079,21 +2035,18 @@ describe("useDropzone() hook", () => {
2079
2035
  )}
2080
2036
  </Dropzone>
2081
2037
  );
2082
- const { container, rerender } = render(ui);
2083
2038
  const dropzone = container.querySelector("div");
2084
2039
 
2085
- fireDragEnter(dropzone, data);
2086
- await flushPromises(rerender, ui);
2040
+ await act(() => fireEvent.dragEnter(dropzone, data));
2087
2041
  expect(props.onDragEnter).toHaveBeenCalled();
2088
2042
 
2089
- fireDragOver(dropzone, data);
2043
+ fireEvent.dragOver(dropzone, data);
2090
2044
  expect(props.onDragOver).toHaveBeenCalled();
2091
2045
 
2092
- fireDragLeave(dropzone, data);
2046
+ fireEvent.dragLeave(dropzone, data);
2093
2047
  expect(props.onDragLeave).toHaveBeenCalled();
2094
2048
 
2095
- fireDrop(dropzone, data);
2096
- await flushPromises(rerender, ui);
2049
+ await act(() => fireEvent.drop(dropzone, data));
2097
2050
  expect(props.onDrop).toHaveBeenCalled();
2098
2051
  });
2099
2052
 
@@ -2109,7 +2062,7 @@ describe("useDropzone() hook", () => {
2109
2062
  onDropRejected: jest.fn(),
2110
2063
  };
2111
2064
 
2112
- const ui = (
2065
+ const { container } = render(
2113
2066
  <Dropzone {...props}>
2114
2067
  {({ getRootProps, getInputProps }) => (
2115
2068
  <div {...getRootProps()}>
@@ -2118,22 +2071,19 @@ describe("useDropzone() hook", () => {
2118
2071
  )}
2119
2072
  </Dropzone>
2120
2073
  );
2121
- const { container, rerender } = render(ui);
2122
2074
  const dropzone = container.querySelector("div");
2123
2075
 
2124
- fireDragEnter(dropzone, emptyData);
2125
- await flushPromises(rerender, ui);
2076
+ await act(() => fireEvent.dragEnter(dropzone, emptyData));
2126
2077
  expect(props.onDragEnter).toHaveBeenCalled();
2127
2078
 
2128
- fireDragOver(dropzone, emptyData);
2079
+ fireEvent.dragOver(dropzone, emptyData);
2129
2080
  expect(props.onDragOver).toHaveBeenCalled();
2130
2081
 
2131
- fireDragLeave(dropzone, emptyData);
2082
+ fireEvent.dragLeave(dropzone, emptyData);
2132
2083
  expect(props.onDragLeave).toHaveBeenCalled();
2133
2084
 
2134
2085
  const data = createDtWithFiles(files);
2135
- fireDrop(dropzone, data);
2136
- await flushPromises(rerender, ui);
2086
+ await act(() => fireEvent.drop(dropzone, data));
2137
2087
  expect(props.onDrop).toHaveBeenCalled();
2138
2088
  expect(props.onDropAccepted).toHaveBeenCalledWith(
2139
2089
  files,
@@ -2159,7 +2109,7 @@ describe("useDropzone() hook", () => {
2159
2109
  onDropRejected: jest.fn(),
2160
2110
  };
2161
2111
 
2162
- const ui = (
2112
+ const { container } = render(
2163
2113
  <Dropzone {...props}>
2164
2114
  {({ getRootProps, getInputProps }) => (
2165
2115
  <div {...getRootProps()}>
@@ -2168,21 +2118,18 @@ describe("useDropzone() hook", () => {
2168
2118
  )}
2169
2119
  </Dropzone>
2170
2120
  );
2171
- const { container, rerender } = render(ui);
2172
2121
  const dropzone = container.querySelector("div");
2173
2122
 
2174
- fireDragEnter(dropzone, data);
2175
- await flushPromises(rerender, ui);
2123
+ await act(() => fireEvent.dragEnter(dropzone, data));
2176
2124
  expect(props.onDragEnter).not.toHaveBeenCalled();
2177
2125
 
2178
- fireDragOver(dropzone, data);
2126
+ fireEvent.dragOver(dropzone, data);
2179
2127
  expect(props.onDragOver).not.toHaveBeenCalled();
2180
2128
 
2181
- fireDragLeave(dropzone, data);
2129
+ fireEvent.dragLeave(dropzone, data);
2182
2130
  expect(props.onDragLeave).not.toHaveBeenCalled();
2183
2131
 
2184
- fireDrop(dropzone, data);
2185
- await flushPromises(rerender, ui);
2132
+ await act(() => fireEvent.drop(dropzone, data));
2186
2133
  expect(props.onDrop).not.toHaveBeenCalled();
2187
2134
  expect(props.onDropAccepted).not.toHaveBeenCalled();
2188
2135
  expect(props.onDropRejected).not.toHaveBeenCalled();
@@ -2200,7 +2147,7 @@ describe("useDropzone() hook", () => {
2200
2147
  onDropRejected: jest.fn(),
2201
2148
  };
2202
2149
 
2203
- const ui = (
2150
+ const { container } = render(
2204
2151
  <Dropzone {...props} noDrag>
2205
2152
  {({ getRootProps, getInputProps }) => (
2206
2153
  <div {...getRootProps()}>
@@ -2209,21 +2156,18 @@ describe("useDropzone() hook", () => {
2209
2156
  )}
2210
2157
  </Dropzone>
2211
2158
  );
2212
- const { container, rerender } = render(ui);
2213
2159
  const dropzone = container.querySelector("div");
2214
2160
 
2215
- fireDragEnter(dropzone, data);
2216
- await flushPromises(rerender, ui);
2161
+ await act(() => fireEvent.dragEnter(dropzone, data));
2217
2162
  expect(props.onDragEnter).not.toHaveBeenCalled();
2218
2163
 
2219
- fireDragOver(dropzone, data);
2164
+ fireEvent.dragOver(dropzone, data);
2220
2165
  expect(props.onDragOver).not.toHaveBeenCalled();
2221
2166
 
2222
- fireDragLeave(dropzone, data);
2167
+ fireEvent.dragLeave(dropzone, data);
2223
2168
  expect(props.onDragLeave).not.toHaveBeenCalled();
2224
2169
 
2225
- fireDrop(dropzone, data);
2226
- await flushPromises(rerender, ui);
2170
+ await act(() => fireEvent.drop(dropzone, data));
2227
2171
  expect(props.onDrop).not.toHaveBeenCalled();
2228
2172
  expect(props.onDropAccepted).not.toHaveBeenCalled();
2229
2173
  expect(props.onDropRejected).not.toHaveBeenCalled();
@@ -2239,7 +2183,7 @@ describe("useDropzone() hook", () => {
2239
2183
  onDrop: jest.fn(),
2240
2184
  };
2241
2185
 
2242
- const noDragUi = (
2186
+ const { container, rerender } = render(
2243
2187
  <Dropzone {...props} noDrag>
2244
2188
  {({ getRootProps, getInputProps }) => (
2245
2189
  <div {...getRootProps()}>
@@ -2248,24 +2192,21 @@ describe("useDropzone() hook", () => {
2248
2192
  )}
2249
2193
  </Dropzone>
2250
2194
  );
2251
- const { container, rerender } = render(noDragUi);
2252
2195
  const dropzone = container.querySelector("div");
2253
2196
 
2254
- fireDragEnter(dropzone, data);
2255
- await flushPromises(rerender, noDragUi);
2197
+ await act(() => fireEvent.dragEnter(dropzone, data));
2256
2198
  expect(props.onDragEnter).not.toHaveBeenCalled();
2257
2199
 
2258
- fireDragOver(dropzone, data);
2200
+ fireEvent.dragOver(dropzone, data);
2259
2201
  expect(props.onDragOver).not.toHaveBeenCalled();
2260
2202
 
2261
- fireDragLeave(dropzone, data);
2203
+ fireEvent.dragLeave(dropzone, data);
2262
2204
  expect(props.onDragLeave).not.toHaveBeenCalled();
2263
2205
 
2264
- fireDrop(dropzone, data);
2265
- await flushPromises(rerender, noDragUi);
2206
+ await act(() => fireEvent.drop(dropzone, data));
2266
2207
  expect(props.onDrop).not.toHaveBeenCalled();
2267
2208
 
2268
- const ui = (
2209
+ rerender(
2269
2210
  <Dropzone {...props} noDrag={false}>
2270
2211
  {({ getRootProps, getInputProps }) => (
2271
2212
  <div {...getRootProps()}>
@@ -2274,25 +2215,22 @@ describe("useDropzone() hook", () => {
2274
2215
  )}
2275
2216
  </Dropzone>
2276
2217
  );
2277
- rerender(ui);
2278
2218
 
2279
- fireDragEnter(dropzone, data);
2280
- await flushPromises(rerender, ui);
2219
+ await act(() => fireEvent.dragEnter(dropzone, data));
2281
2220
  expect(props.onDragEnter).toHaveBeenCalled();
2282
2221
 
2283
- fireDragOver(dropzone, data);
2222
+ fireEvent.dragOver(dropzone, data);
2284
2223
  expect(props.onDragOver).toHaveBeenCalled();
2285
2224
 
2286
- fireDragLeave(dropzone, data);
2225
+ fireEvent.dragLeave(dropzone, data);
2287
2226
  expect(props.onDragLeave).toHaveBeenCalled();
2288
2227
 
2289
- fireDrop(dropzone, data);
2290
- await flushPromises(rerender, ui);
2228
+ await act(() => fireEvent.drop(dropzone, data));
2291
2229
  expect(props.onDrop).toHaveBeenCalled();
2292
2230
  });
2293
2231
 
2294
2232
  it("sets {isDragActive} and {isDragAccept} if some files are accepted on dragenter", async () => {
2295
- const ui = (
2233
+ const { container } = render(
2296
2234
  <Dropzone>
2297
2235
  {({
2298
2236
  getRootProps,
@@ -2310,12 +2248,9 @@ describe("useDropzone() hook", () => {
2310
2248
  )}
2311
2249
  </Dropzone>
2312
2250
  );
2313
- const { container, rerender } = render(ui);
2314
2251
  const dropzone = container.querySelector("div");
2315
2252
 
2316
- const data = createDtWithFiles(files);
2317
- fireDragEnter(dropzone, data);
2318
- await flushPromises(rerender, ui);
2253
+ await act(() => fireEvent.dragEnter(dropzone, createDtWithFiles(files)));
2319
2254
 
2320
2255
  expect(dropzone).toHaveTextContent("dragActive");
2321
2256
  expect(dropzone).toHaveTextContent("dragAccept");
@@ -2323,7 +2258,7 @@ describe("useDropzone() hook", () => {
2323
2258
  });
2324
2259
 
2325
2260
  it("sets {isDragActive} and {isDragReject} of some files are not accepted on dragenter", async () => {
2326
- const ui = (
2261
+ const { container } = render(
2327
2262
  <Dropzone
2328
2263
  accept={{
2329
2264
  "image/*": [],
@@ -2345,12 +2280,11 @@ describe("useDropzone() hook", () => {
2345
2280
  )}
2346
2281
  </Dropzone>
2347
2282
  );
2348
- const { container, rerender } = render(ui);
2349
2283
  const dropzone = container.querySelector("div");
2350
2284
 
2351
- const data = createDtWithFiles([...files, ...images]);
2352
- fireDragEnter(dropzone, data);
2353
- await flushPromises(rerender, ui);
2285
+ await act(() =>
2286
+ fireEvent.dragEnter(dropzone, createDtWithFiles([...files, ...images]))
2287
+ );
2354
2288
 
2355
2289
  expect(dropzone).toHaveTextContent("dragActive");
2356
2290
  expect(dropzone).not.toHaveTextContent("dragAccept");
@@ -2358,7 +2292,7 @@ describe("useDropzone() hook", () => {
2358
2292
  });
2359
2293
 
2360
2294
  it("sets {isDragReject} if some files are too large", async () => {
2361
- const ui = (
2295
+ const { container } = render(
2362
2296
  <Dropzone maxSize={0}>
2363
2297
  {({ getRootProps, getInputProps, isDragAccept, isDragReject }) => (
2364
2298
  <div {...getRootProps()}>
@@ -2369,19 +2303,16 @@ describe("useDropzone() hook", () => {
2369
2303
  )}
2370
2304
  </Dropzone>
2371
2305
  );
2372
- const { container, rerender } = render(ui);
2373
2306
  const dropzone = container.querySelector("div");
2374
2307
 
2375
- const data = createDtWithFiles(files);
2376
- fireDragEnter(dropzone, data);
2377
- await flushPromises(rerender, ui);
2308
+ await act(() => fireEvent.dragEnter(dropzone, createDtWithFiles(files)));
2378
2309
 
2379
2310
  expect(dropzone).not.toHaveTextContent("dragAccept");
2380
2311
  expect(dropzone).toHaveTextContent("dragReject");
2381
2312
  });
2382
2313
 
2383
2314
  it("sets {isDragActive, isDragAccept, isDragReject} if any files are rejected and {multiple} is false on dragenter", async () => {
2384
- const ui = (
2315
+ const { container } = render(
2385
2316
  <Dropzone
2386
2317
  accept={{
2387
2318
  "image/*": [],
@@ -2404,12 +2335,9 @@ describe("useDropzone() hook", () => {
2404
2335
  )}
2405
2336
  </Dropzone>
2406
2337
  );
2407
- const { container, rerender } = render(ui);
2408
2338
  const dropzone = container.querySelector("div");
2409
2339
 
2410
- const data = createDtWithFiles(images);
2411
- fireDragEnter(dropzone, data);
2412
- await flushPromises(rerender, ui);
2340
+ await act(() => fireEvent.dragEnter(dropzone, createDtWithFiles(images)));
2413
2341
 
2414
2342
  expect(dropzone).toHaveTextContent("dragActive");
2415
2343
  expect(dropzone).not.toHaveTextContent("dragAccept");
@@ -2418,7 +2346,8 @@ describe("useDropzone() hook", () => {
2418
2346
 
2419
2347
  it("keeps {isDragActive} if dragleave is triggered for some arbitrary node", async () => {
2420
2348
  const { container: overlayContainer } = render(<div />);
2421
- const ui = (
2349
+
2350
+ const { container } = render(
2422
2351
  <Dropzone>
2423
2352
  {({
2424
2353
  getRootProps,
@@ -2436,87 +2365,20 @@ describe("useDropzone() hook", () => {
2436
2365
  )}
2437
2366
  </Dropzone>
2438
2367
  );
2439
- const { container, rerender } = render(ui);
2440
2368
  const dropzone = container.querySelector("div");
2441
2369
 
2442
- const data = createDtWithFiles(files);
2443
- fireDragEnter(dropzone, data);
2444
- await flushPromises(rerender, ui);
2370
+ await act(() => fireEvent.dragEnter(dropzone, createDtWithFiles(files)));
2445
2371
 
2446
- const event = new Event("dragleave", { bubbles: true });
2447
- Object.defineProperty(event, "target", {
2448
- value: overlayContainer.querySelector("div"),
2449
- writable: false,
2372
+ fireEvent.dragLeave(dropzone, {
2373
+ bubbles: true,
2374
+ target: overlayContainer.querySelector("div"),
2450
2375
  });
2451
- fireEvent(dropzone, event);
2452
2376
 
2453
2377
  expect(dropzone).toHaveTextContent("dragActive");
2454
2378
  });
2455
2379
 
2456
- it("updates {isDragActive} if {accept} changes mid-drag", async () => {
2457
- const ui = (
2458
- <Dropzone
2459
- accept={{
2460
- "image/*": [],
2461
- }}
2462
- >
2463
- {({
2464
- getRootProps,
2465
- getInputProps,
2466
- isDragActive,
2467
- isDragAccept,
2468
- isDragReject,
2469
- }) => (
2470
- <div {...getRootProps()}>
2471
- <input {...getInputProps()} />
2472
- {isDragActive && "dragActive"}
2473
- {isDragAccept && "dragAccept"}
2474
- {isDragReject && "dragReject"}
2475
- </div>
2476
- )}
2477
- </Dropzone>
2478
- );
2479
- const { container, rerender } = render(ui);
2480
- const dropzone = container.querySelector("div");
2481
-
2482
- const data = createDtWithFiles(images);
2483
- fireDragEnter(dropzone, data);
2484
- await flushPromises(rerender, ui);
2485
-
2486
- expect(dropzone).toHaveTextContent("dragActive");
2487
- expect(dropzone).toHaveTextContent("dragAccept");
2488
- expect(dropzone).not.toHaveTextContent("dragReject");
2489
-
2490
- rerender(
2491
- <Dropzone
2492
- accept={{
2493
- "text/*": [],
2494
- }}
2495
- >
2496
- {({
2497
- getRootProps,
2498
- getInputProps,
2499
- isDragActive,
2500
- isDragAccept,
2501
- isDragReject,
2502
- }) => (
2503
- <div {...getRootProps()}>
2504
- <input {...getInputProps()} />
2505
- {isDragActive && "dragActive"}
2506
- {isDragAccept && "dragAccept"}
2507
- {isDragReject && "dragReject"}
2508
- </div>
2509
- )}
2510
- </Dropzone>
2511
- );
2512
-
2513
- expect(dropzone).toHaveTextContent("dragActive");
2514
- expect(dropzone).not.toHaveTextContent("dragAccept");
2515
- expect(dropzone).toHaveTextContent("dragReject");
2516
- });
2517
-
2518
2380
  it("resets {isDragActive, isDragAccept, isDragReject} on dragleave", async () => {
2519
- const ui = (
2381
+ const { container } = render(
2520
2382
  <Dropzone
2521
2383
  accept={{
2522
2384
  "image/*": [],
@@ -2545,29 +2407,27 @@ describe("useDropzone() hook", () => {
2545
2407
  )}
2546
2408
  </Dropzone>
2547
2409
  );
2548
- const { container, rerender } = render(ui);
2549
2410
  const dropzone = container.querySelector("div");
2550
2411
 
2551
2412
  const data = createDtWithFiles(images);
2552
2413
 
2553
- fireDragEnter(container.querySelector("#child"), data);
2554
- fireDragEnter(dropzone, data);
2555
- await flushPromises(rerender, ui);
2556
- fireDragEnter(dropzone, data);
2557
- await flushPromises(rerender, ui);
2414
+ await act(() =>
2415
+ fireEvent.dragEnter(container.querySelector("#child"), data)
2416
+ );
2417
+ await act(() => fireEvent.dragEnter(dropzone, data));
2418
+
2419
+ await act(() => fireEvent.dragEnter(dropzone, data));
2558
2420
 
2559
2421
  expect(dropzone).toHaveTextContent("dragActive");
2560
2422
  expect(dropzone).toHaveTextContent("dragAccept");
2561
2423
  expect(dropzone).not.toHaveTextContent("dragReject");
2562
2424
 
2563
- fireDragLeave(dropzone, data);
2564
- await flushPromises(rerender, ui);
2425
+ fireEvent.dragLeave(dropzone, data);
2565
2426
  expect(dropzone).toHaveTextContent("dragActive");
2566
2427
  expect(dropzone).toHaveTextContent("dragAccept");
2567
2428
  expect(dropzone).not.toHaveTextContent("dragReject");
2568
2429
 
2569
- fireDragLeave(dropzone, data);
2570
- await flushPromises(rerender, ui);
2430
+ fireEvent.dragLeave(dropzone, data);
2571
2431
  expect(dropzone).not.toHaveTextContent("dragActive");
2572
2432
  expect(dropzone).not.toHaveTextContent("dragAccept");
2573
2433
  expect(dropzone).not.toHaveTextContent("dragReject");
@@ -2582,7 +2442,7 @@ describe("useDropzone() hook", () => {
2582
2442
  test("callback is invoked when <input> change event occurs", async () => {
2583
2443
  const onDropSpy = jest.fn();
2584
2444
 
2585
- const ui = (
2445
+ const { container } = render(
2586
2446
  <Dropzone onDrop={onDropSpy}>
2587
2447
  {({ getRootProps, getInputProps }) => (
2588
2448
  <div {...getRootProps()}>
@@ -2591,13 +2451,12 @@ describe("useDropzone() hook", () => {
2591
2451
  )}
2592
2452
  </Dropzone>
2593
2453
  );
2594
- const { container, rerender } = render(ui);
2595
- const input = container.querySelector("input");
2596
2454
 
2597
- Object.defineProperty(input, "files", { value: files });
2598
-
2599
- dispatchEvt(input, "change");
2600
- await flushPromises(rerender, ui);
2455
+ await act(async () =>
2456
+ fireEvent.change(container.querySelector("input"), {
2457
+ target: { files },
2458
+ })
2459
+ );
2601
2460
 
2602
2461
  expect(onDropSpy).toHaveBeenCalledWith(files, [], expect.anything());
2603
2462
  });
@@ -2636,6 +2495,7 @@ describe("useDropzone() hook", () => {
2636
2495
  node.querySelectorAll(`[data-type="rejected"]`);
2637
2496
  const getRejectedFilesErrors = (node) =>
2638
2497
  node.querySelectorAll(`[data-type="error"]`);
2498
+
2639
2499
  const matchToFiles = (fileList, files) =>
2640
2500
  Array.from(fileList).every(
2641
2501
  (item) => !!files.find((file) => file.name === item.textContent)
@@ -2643,7 +2503,7 @@ describe("useDropzone() hook", () => {
2643
2503
  const matchToErrorCode = (errorList, code) =>
2644
2504
  Array.from(errorList).every((item) => item.textContent === code);
2645
2505
 
2646
- const ui = (
2506
+ const { container } = render(
2647
2507
  <Dropzone
2648
2508
  accept={{
2649
2509
  "image/*": [],
@@ -2658,17 +2518,16 @@ describe("useDropzone() hook", () => {
2658
2518
  )}
2659
2519
  </Dropzone>
2660
2520
  );
2661
- const { container, rerender } = render(ui);
2662
2521
  const dropzone = container.querySelector("div");
2663
2522
 
2664
- fireDrop(dropzone, createDtWithFiles(images));
2665
- await flushPromises(rerender, ui);
2523
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2524
+
2666
2525
  const acceptedFileList = getAcceptedFiles(dropzone);
2667
2526
  expect(acceptedFileList).toHaveLength(images.length);
2668
2527
  expect(matchToFiles(acceptedFileList, images)).toBe(true);
2669
2528
 
2670
- fireDrop(dropzone, createDtWithFiles(files));
2671
- await flushPromises(rerender, ui);
2529
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
2530
+
2672
2531
  const rejectedFileList = getRejectedFiles(dropzone);
2673
2532
  expect(rejectedFileList).toHaveLength(files.length);
2674
2533
  expect(matchToFiles(rejectedFileList, files)).toBe(true);
@@ -2680,7 +2539,7 @@ describe("useDropzone() hook", () => {
2680
2539
  });
2681
2540
 
2682
2541
  it("resets {isDragActive, isDragAccept, isDragReject}", async () => {
2683
- const ui = (
2542
+ const { container } = render(
2684
2543
  <Dropzone>
2685
2544
  {({
2686
2545
  getRootProps,
@@ -2698,20 +2557,18 @@ describe("useDropzone() hook", () => {
2698
2557
  )}
2699
2558
  </Dropzone>
2700
2559
  );
2701
- const { container, rerender } = render(ui);
2702
2560
  const dropzone = container.querySelector("div");
2703
2561
 
2704
2562
  const data = createDtWithFiles(files);
2705
2563
 
2706
- fireDragEnter(dropzone, data);
2707
- await flushPromises(rerender, ui);
2564
+ await act(() => fireEvent.dragEnter(dropzone, data));
2708
2565
 
2709
2566
  expect(dropzone).toHaveTextContent("dragActive");
2710
2567
  expect(dropzone).toHaveTextContent("dragAccept");
2711
2568
  expect(dropzone).not.toHaveTextContent("dragReject");
2712
2569
 
2713
- fireDrop(dropzone, data);
2714
- await flushPromises(rerender, ui);
2570
+ await act(() => fireEvent.drop(dropzone, data));
2571
+
2715
2572
  expect(dropzone).not.toHaveTextContent("dragActive");
2716
2573
  expect(dropzone).not.toHaveTextContent("dragAccept");
2717
2574
  expect(dropzone).not.toHaveTextContent("dragReject");
@@ -2719,7 +2576,8 @@ describe("useDropzone() hook", () => {
2719
2576
 
2720
2577
  it("rejects all files if {multiple} is false and {accept} criteria is not met", async () => {
2721
2578
  const onDropSpy = jest.fn();
2722
- const ui = (
2579
+
2580
+ const { container } = render(
2723
2581
  <Dropzone
2724
2582
  accept={{
2725
2583
  "image/*": [],
@@ -2734,11 +2592,10 @@ describe("useDropzone() hook", () => {
2734
2592
  )}
2735
2593
  </Dropzone>
2736
2594
  );
2737
- const { container, rerender } = render(ui);
2738
2595
  const dropzone = container.querySelector("div");
2739
2596
 
2740
- fireDrop(dropzone, createDtWithFiles(files));
2741
- await flushPromises(rerender, ui);
2597
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
2598
+
2742
2599
  expect(onDropSpy).toHaveBeenCalledWith(
2743
2600
  [],
2744
2601
  [
@@ -2758,7 +2615,8 @@ describe("useDropzone() hook", () => {
2758
2615
 
2759
2616
  it("rejects all files if {multiple} is false and {accept} criteria is met", async () => {
2760
2617
  const onDropSpy = jest.fn();
2761
- const ui = (
2618
+
2619
+ const { container } = render(
2762
2620
  <Dropzone
2763
2621
  accept={{
2764
2622
  "image/*": [],
@@ -2773,11 +2631,10 @@ describe("useDropzone() hook", () => {
2773
2631
  )}
2774
2632
  </Dropzone>
2775
2633
  );
2776
- const { container, rerender } = render(ui);
2777
2634
  const dropzone = container.querySelector("div");
2778
2635
 
2779
- fireDrop(dropzone, createDtWithFiles(images));
2780
- await flushPromises(rerender, ui);
2636
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2637
+
2781
2638
  expect(onDropSpy).toHaveBeenCalledWith(
2782
2639
  [],
2783
2640
  [
@@ -2807,7 +2664,8 @@ describe("useDropzone() hook", () => {
2807
2664
  it("rejects all files if {multiple} is true and maxFiles is less than files and {accept} criteria is met", async () => {
2808
2665
  const onDropSpy = jest.fn();
2809
2666
  const onDropRejectedSpy = jest.fn();
2810
- const ui = (
2667
+
2668
+ const { container } = render(
2811
2669
  <Dropzone
2812
2670
  accept={{
2813
2671
  "image/*": [],
@@ -2826,13 +2684,14 @@ describe("useDropzone() hook", () => {
2826
2684
  )}
2827
2685
  </Dropzone>
2828
2686
  );
2829
- const { container, rerender } = render(ui);
2830
2687
  const dropzone = container.querySelector("div");
2831
- fireDrop(dropzone, createDtWithFiles(images));
2832
- await flushPromises(rerender, ui);
2688
+
2689
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2690
+
2833
2691
  expect(onDropRejectedSpy).toHaveBeenCalled();
2834
- fireDragEnter(dropzone, createDtWithFiles(images));
2835
- await flushPromises(rerender, ui);
2692
+
2693
+ await act(() => fireEvent.dragEnter(dropzone, createDtWithFiles(images)));
2694
+
2836
2695
  expect(dropzone).toHaveTextContent("dragReject");
2837
2696
  expect(dropzone).not.toHaveTextContent("dragAccept");
2838
2697
  expect(onDropSpy).toHaveBeenCalledWith(
@@ -2884,15 +2743,17 @@ describe("useDropzone() hook", () => {
2884
2743
  const { container, rerender } = render(ui(3));
2885
2744
  const dropzone = container.querySelector("div");
2886
2745
 
2887
- fireDrop(dropzone, createDtWithFiles(images));
2888
- await flushPromises(rerender, ui(3));
2746
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2747
+ rerender(ui(3));
2748
+
2889
2749
  expect(onDropRejectedSpy).not.toHaveBeenCalled();
2890
2750
  expect(onDropSpy).toHaveBeenCalledWith(images, [], expect.anything());
2891
2751
 
2892
2752
  rerender(ui(1));
2893
2753
 
2894
- fireDrop(dropzone, createDtWithFiles(images));
2895
- await flushPromises(rerender, ui(1));
2754
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2755
+ rerender(ui(1));
2756
+
2896
2757
  expect(onDropRejectedSpy).toHaveBeenCalledWith(
2897
2758
  expect.arrayContaining(
2898
2759
  images.map((image) =>
@@ -2906,7 +2767,8 @@ describe("useDropzone() hook", () => {
2906
2767
  it("accepts multiple files if {multiple} is true and {accept} criteria is met", async () => {
2907
2768
  const onDropSpy = jest.fn();
2908
2769
  const onDropRejectedSpy = jest.fn();
2909
- const ui = (
2770
+
2771
+ const { container } = render(
2910
2772
  <Dropzone
2911
2773
  accept={{
2912
2774
  "image/*": [],
@@ -2923,18 +2785,22 @@ describe("useDropzone() hook", () => {
2923
2785
  )}
2924
2786
  </Dropzone>
2925
2787
  );
2926
- const { container, rerender } = render(ui);
2927
- const dropzone = container.querySelector("div");
2928
2788
 
2929
- fireDrop(dropzone, createDtWithFiles(images));
2930
- await flushPromises(rerender, ui);
2789
+ await act(() =>
2790
+ fireEvent.drop(
2791
+ container.querySelector("div"),
2792
+ createDtWithFiles(images)
2793
+ )
2794
+ );
2795
+
2931
2796
  expect(onDropRejectedSpy).not.toHaveBeenCalled();
2932
2797
  expect(onDropSpy).toHaveBeenCalledWith(images, [], expect.anything());
2933
2798
  });
2934
2799
 
2935
2800
  it("accepts a single files if {multiple} is false and {accept} criteria is met", async () => {
2936
2801
  const onDropSpy = jest.fn();
2937
- const ui = (
2802
+
2803
+ const { container } = render(
2938
2804
  <Dropzone
2939
2805
  accept={{
2940
2806
  "image/*": [],
@@ -2949,18 +2815,22 @@ describe("useDropzone() hook", () => {
2949
2815
  )}
2950
2816
  </Dropzone>
2951
2817
  );
2952
- const { container, rerender } = render(ui);
2953
- const dropzone = container.querySelector("div");
2954
2818
 
2955
2819
  const [image] = images;
2956
- fireDrop(dropzone, createDtWithFiles([image]));
2957
- await flushPromises(rerender, ui);
2820
+ await act(() =>
2821
+ fireEvent.drop(
2822
+ container.querySelector("div"),
2823
+ createDtWithFiles([image])
2824
+ )
2825
+ );
2826
+
2958
2827
  expect(onDropSpy).toHaveBeenCalledWith([image], [], expect.anything());
2959
2828
  });
2960
2829
 
2961
2830
  it("accepts all files if {multiple} is true", async () => {
2962
2831
  const onDropSpy = jest.fn();
2963
- const ui = (
2832
+
2833
+ const { container } = render(
2964
2834
  <Dropzone onDrop={onDropSpy}>
2965
2835
  {({ getRootProps, getInputProps }) => (
2966
2836
  <div {...getRootProps()}>
@@ -2969,11 +2839,11 @@ describe("useDropzone() hook", () => {
2969
2839
  )}
2970
2840
  </Dropzone>
2971
2841
  );
2972
- const { container, rerender } = render(ui);
2973
- const dropzone = container.querySelector("div");
2974
2842
 
2975
- fireDrop(dropzone, createDtWithFiles(files));
2976
- await flushPromises(rerender, ui);
2843
+ await act(() =>
2844
+ fireEvent.drop(container.querySelector("div"), createDtWithFiles(files))
2845
+ );
2846
+
2977
2847
  expect(onDropSpy).toHaveBeenCalledWith(files, [], expect.anything());
2978
2848
  });
2979
2849
 
@@ -2982,37 +2852,34 @@ describe("useDropzone() hook", () => {
2982
2852
  const activeRef = createRef();
2983
2853
  const active = <span ref={activeRef}>I am active</span>;
2984
2854
 
2985
- const ui = (
2855
+ const { container } = render(
2986
2856
  <Dropzone onDrop={onDropSpy}>
2987
- {({ getRootProps, getInputProps, isFileDialogActive, open }) => (
2857
+ {({ getRootProps, getInputProps, isFileDialogActive }) => (
2988
2858
  <div {...getRootProps()}>
2989
2859
  <input {...getInputProps()} />
2990
2860
  {isFileDialogActive && active}
2991
- <button type="button" onClick={open}>
2992
- Open
2993
- </button>
2994
2861
  </div>
2995
2862
  )}
2996
2863
  </Dropzone>
2997
2864
  );
2998
- const { container, rerender } = render(ui);
2865
+
2999
2866
  const dropzone = container.querySelector("div");
3000
- const btn = container.querySelector("button");
3001
2867
 
3002
- btn.click();
2868
+ fireEvent.click(dropzone);
3003
2869
 
3004
- const ref = activeRef.current;
3005
- expect(dropzone).toContainElement(ref);
2870
+ expect(activeRef.current).not.toBeNull();
2871
+ expect(dropzone).toContainElement(activeRef.current);
3006
2872
 
3007
- fireDrop(dropzone, createDtWithFiles(files));
3008
- await flushPromises(rerender, ui);
2873
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
3009
2874
 
3010
- expect(dropzone).not.toContainElement(ref);
2875
+ expect(activeRef.current).toBeNull();
2876
+ expect(dropzone).not.toContainElement(activeRef.current);
3011
2877
  });
3012
2878
 
3013
2879
  it("gets invoked with both accepted/rejected files", async () => {
3014
2880
  const onDropSpy = jest.fn();
3015
- const ui = (
2881
+
2882
+ const { container } = render(
3016
2883
  <Dropzone
3017
2884
  accept={{
3018
2885
  "image/*": [],
@@ -3026,11 +2893,10 @@ describe("useDropzone() hook", () => {
3026
2893
  )}
3027
2894
  </Dropzone>
3028
2895
  );
3029
- const { container, rerender } = render(ui);
3030
2896
  const dropzone = container.querySelector("div");
3031
2897
 
3032
- fireDrop(dropzone, createDtWithFiles(files));
3033
- await flushPromises(rerender, ui);
2898
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
2899
+
3034
2900
  expect(onDropSpy).toHaveBeenCalledWith(
3035
2901
  [],
3036
2902
  [
@@ -3048,13 +2914,15 @@ describe("useDropzone() hook", () => {
3048
2914
  );
3049
2915
  onDropSpy.mockClear();
3050
2916
 
3051
- fireDrop(dropzone, createDtWithFiles(images));
3052
- await flushPromises(rerender, ui);
2917
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2918
+
3053
2919
  expect(onDropSpy).toHaveBeenCalledWith(images, [], expect.anything());
3054
2920
  onDropSpy.mockClear();
3055
2921
 
3056
- fireDrop(dropzone, createDtWithFiles([...files, ...images]));
3057
- await flushPromises(rerender, ui);
2922
+ await act(() =>
2923
+ fireEvent.drop(dropzone, createDtWithFiles([...files, ...images]))
2924
+ );
2925
+
3058
2926
  expect(onDropSpy).toHaveBeenCalledWith(
3059
2927
  images,
3060
2928
  [
@@ -3074,7 +2942,8 @@ describe("useDropzone() hook", () => {
3074
2942
 
3075
2943
  test("onDropAccepted callback is invoked if some files are accepted", async () => {
3076
2944
  const onDropAcceptedSpy = jest.fn();
3077
- const ui = (
2945
+
2946
+ const { container } = render(
3078
2947
  <Dropzone
3079
2948
  accept={{
3080
2949
  "image/*": [],
@@ -3088,27 +2957,28 @@ describe("useDropzone() hook", () => {
3088
2957
  )}
3089
2958
  </Dropzone>
3090
2959
  );
3091
- const { container, rerender } = render(ui);
3092
2960
  const dropzone = container.querySelector("div");
3093
2961
 
3094
- fireDrop(dropzone, createDtWithFiles(files));
3095
- await flushPromises(rerender, ui);
2962
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
3096
2963
  expect(onDropAcceptedSpy).not.toHaveBeenCalled();
3097
2964
  onDropAcceptedSpy.mockClear();
3098
2965
 
3099
- fireDrop(dropzone, createDtWithFiles(images));
3100
- await flushPromises(rerender, ui);
2966
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
2967
+
3101
2968
  expect(onDropAcceptedSpy).toHaveBeenCalledWith(images, expect.anything());
3102
2969
  onDropAcceptedSpy.mockClear();
3103
2970
 
3104
- fireDrop(dropzone, createDtWithFiles([...files, ...images]));
3105
- await flushPromises(rerender, ui);
2971
+ await act(() =>
2972
+ fireEvent.drop(dropzone, createDtWithFiles([...files, ...images]))
2973
+ );
2974
+
3106
2975
  expect(onDropAcceptedSpy).toHaveBeenCalledWith(images, expect.anything());
3107
2976
  });
3108
2977
 
3109
2978
  test("onDropRejected callback is invoked if some files are rejected", async () => {
3110
2979
  const onDropRejectedSpy = jest.fn();
3111
- const ui = (
2980
+
2981
+ const { container } = render(
3112
2982
  <Dropzone
3113
2983
  accept={{
3114
2984
  "image/*": [],
@@ -3122,11 +2992,10 @@ describe("useDropzone() hook", () => {
3122
2992
  )}
3123
2993
  </Dropzone>
3124
2994
  );
3125
- const { container, rerender } = render(ui);
3126
2995
  const dropzone = container.querySelector("div");
3127
2996
 
3128
- fireDrop(dropzone, createDtWithFiles(files));
3129
- await flushPromises(rerender, ui);
2997
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
2998
+
3130
2999
  expect(onDropRejectedSpy).toHaveBeenCalledWith(
3131
3000
  [
3132
3001
  {
@@ -3143,13 +3012,15 @@ describe("useDropzone() hook", () => {
3143
3012
  );
3144
3013
  onDropRejectedSpy.mockClear();
3145
3014
 
3146
- fireDrop(dropzone, createDtWithFiles(images));
3147
- await flushPromises(rerender, ui);
3015
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(images)));
3016
+
3148
3017
  expect(onDropRejectedSpy).not.toHaveBeenCalled();
3149
3018
  onDropRejectedSpy.mockClear();
3150
3019
 
3151
- fireDrop(dropzone, createDtWithFiles([...files, ...images]));
3152
- await flushPromises(rerender, ui);
3020
+ await act(() =>
3021
+ fireEvent.drop(dropzone, createDtWithFiles([...files, ...images]))
3022
+ );
3023
+
3153
3024
  expect(onDropRejectedSpy).toHaveBeenCalledWith(
3154
3025
  [
3155
3026
  {
@@ -3168,7 +3039,8 @@ describe("useDropzone() hook", () => {
3168
3039
 
3169
3040
  it("accepts a dropped image when Firefox provides a bogus file type", async () => {
3170
3041
  const onDropSpy = jest.fn();
3171
- const ui = (
3042
+
3043
+ const { container } = render(
3172
3044
  <Dropzone
3173
3045
  accept={{
3174
3046
  "image/*": [],
@@ -3182,19 +3054,22 @@ describe("useDropzone() hook", () => {
3182
3054
  )}
3183
3055
  </Dropzone>
3184
3056
  );
3185
- const { container, rerender } = render(ui);
3186
- const dropzone = container.querySelector("div");
3187
3057
 
3188
3058
  const images = [createFile("bogus.gif", 1234, "application/x-moz-file")];
3189
- fireDrop(dropzone, createDtWithFiles(images));
3190
- await flushPromises(rerender, ui);
3059
+ await act(() =>
3060
+ fireEvent.drop(
3061
+ container.querySelector("div"),
3062
+ createDtWithFiles(images)
3063
+ )
3064
+ );
3191
3065
 
3192
3066
  expect(onDropSpy).toHaveBeenCalledWith(images, [], expect.anything());
3193
3067
  });
3194
3068
 
3195
3069
  it("filters files according to {maxSize}", async () => {
3196
3070
  const onDropSpy = jest.fn();
3197
- const ui = (
3071
+
3072
+ const { container } = render(
3198
3073
  <Dropzone onDrop={onDropSpy} maxSize={1111}>
3199
3074
  {({ getRootProps, getInputProps }) => (
3200
3075
  <div {...getRootProps()}>
@@ -3203,11 +3078,13 @@ describe("useDropzone() hook", () => {
3203
3078
  )}
3204
3079
  </Dropzone>
3205
3080
  );
3206
- const { container, rerender } = render(ui);
3207
- const dropzone = container.querySelector("div");
3208
3081
 
3209
- fireDrop(dropzone, createDtWithFiles(images));
3210
- await flushPromises(rerender, ui);
3082
+ await act(() =>
3083
+ fireEvent.drop(
3084
+ container.querySelector("div"),
3085
+ createDtWithFiles(images)
3086
+ )
3087
+ );
3211
3088
 
3212
3089
  expect(onDropSpy).toHaveBeenCalledWith(
3213
3090
  [],
@@ -3237,7 +3114,8 @@ describe("useDropzone() hook", () => {
3237
3114
 
3238
3115
  it("filters files according to {minSize}", async () => {
3239
3116
  const onDropSpy = jest.fn();
3240
- const ui = (
3117
+
3118
+ const { container } = render(
3241
3119
  <Dropzone onDrop={onDropSpy} minSize={1112}>
3242
3120
  {({ getRootProps, getInputProps }) => (
3243
3121
  <div {...getRootProps()}>
@@ -3246,11 +3124,9 @@ describe("useDropzone() hook", () => {
3246
3124
  )}
3247
3125
  </Dropzone>
3248
3126
  );
3249
- const { container, rerender } = render(ui);
3250
3127
  const dropzone = container.querySelector("div");
3251
3128
 
3252
- fireDrop(dropzone, createDtWithFiles(files));
3253
- await flushPromises(rerender, ui);
3129
+ await act(() => fireEvent.drop(dropzone, createDtWithFiles(files)));
3254
3130
 
3255
3131
  expect(onDropSpy).toHaveBeenCalledWith(
3256
3132
  [],
@@ -3292,8 +3168,8 @@ describe("useDropzone() hook", () => {
3292
3168
  </Dropzone>
3293
3169
  );
3294
3170
 
3295
- dispatchEvt(document.body, "focus");
3296
- drainTimers();
3171
+ focusWindow();
3172
+ drainPendingTimers();
3297
3173
 
3298
3174
  expect(onFileDialogCancelSpy).not.toHaveBeenCalled();
3299
3175
  });
@@ -3305,91 +3181,78 @@ describe("useDropzone() hook", () => {
3305
3181
 
3306
3182
  const { container } = render(
3307
3183
  <Dropzone onFileDialogCancel={onFileDialogCancelSpy}>
3308
- {({ getRootProps, getInputProps, isFileDialogActive, open }) => (
3184
+ {({ getRootProps, getInputProps, isFileDialogActive }) => (
3309
3185
  <div {...getRootProps()}>
3310
3186
  <input {...getInputProps()} />
3311
3187
  {isFileDialogActive && active}
3312
- <button type="button" onClick={open}>
3313
- Open
3314
- </button>
3315
3188
  </div>
3316
3189
  )}
3317
3190
  </Dropzone>
3318
3191
  );
3319
3192
 
3320
3193
  const dropzone = container.querySelector("div");
3321
- const btn = container.querySelector("button");
3322
3194
 
3323
- btn.click();
3324
- drainTimers();
3325
- const ref = activeRef.current;
3326
- expect(ref).not.toBeNull();
3327
- expect(dropzone).toContainElement(ref);
3195
+ fireEvent.click(dropzone);
3328
3196
 
3329
- dispatchEvt(document.body, "focus");
3330
- drainTimers();
3197
+ expect(activeRef.current).not.toBeNull();
3198
+ expect(dropzone).toContainElement(activeRef.current);
3199
+
3200
+ focusWindow();
3201
+ drainPendingTimers();
3331
3202
 
3332
3203
  expect(onFileDialogCancelSpy).toHaveBeenCalled();
3333
- expect(dropzone).not.toContainElement(ref);
3204
+ expect(dropzone).not.toContainElement(activeRef.current);
3334
3205
  });
3335
3206
 
3336
3207
  it("is not invoked if <input> is not rendered", () => {
3337
3208
  const onFileDialogCancelSpy = jest.fn();
3338
3209
  const { container, rerender } = render(
3339
3210
  <Dropzone onFileDialogCancel={onFileDialogCancelSpy}>
3340
- {({ getRootProps, getInputProps, open }) => (
3211
+ {({ getRootProps, getInputProps }) => (
3341
3212
  <div {...getRootProps()}>
3342
3213
  <input {...getInputProps()} />
3343
- <button type="button" onClick={open}>
3344
- Open
3345
- </button>
3346
3214
  </div>
3347
3215
  )}
3348
3216
  </Dropzone>
3349
3217
  );
3350
3218
 
3351
- const btn = container.querySelector("button");
3352
- btn.click();
3353
- drainTimers();
3219
+ fireEvent.click(container.querySelector("div"));
3354
3220
 
3221
+ // Remove the input, then on window focus nothing should happen because we check if the input ref is set
3355
3222
  rerender(
3356
3223
  <Dropzone onFileDialogCancel={onFileDialogCancelSpy}>
3357
3224
  {({ getRootProps }) => <div {...getRootProps()} />}
3358
3225
  </Dropzone>
3359
3226
  );
3360
- drainTimers();
3361
3227
 
3362
- dispatchEvt(document.body, "focus");
3363
- drainTimers();
3228
+ focusWindow();
3229
+ drainPendingTimers();
3364
3230
 
3365
3231
  expect(onFileDialogCancelSpy).not.toHaveBeenCalled();
3366
3232
  });
3367
3233
 
3368
- it("is not invoked if files were selected", () => {
3234
+ it("is not invoked if files were selected", async () => {
3369
3235
  const onFileDialogCancelSpy = jest.fn();
3370
3236
 
3371
3237
  const { container } = render(
3372
3238
  <Dropzone onFileDialogCancel={onFileDialogCancelSpy}>
3373
- {({ getRootProps, getInputProps, open }) => (
3239
+ {({ getRootProps, getInputProps }) => (
3374
3240
  <div {...getRootProps()}>
3375
3241
  <input {...getInputProps()} />
3376
- <button type="button" onClick={open}>
3377
- Open
3378
- </button>
3379
3242
  </div>
3380
3243
  )}
3381
3244
  </Dropzone>
3382
3245
  );
3383
3246
 
3384
- const input = container.querySelector("input");
3385
- Object.defineProperty(input, "files", { value: files });
3386
-
3387
- const btn = container.querySelector("button");
3388
- btn.click();
3389
- drainTimers();
3247
+ await act(async () =>
3248
+ fireEvent.change(container.querySelector("input"), {
3249
+ target: { files },
3250
+ })
3251
+ );
3252
+ fireEvent.click(container.querySelector("div"));
3390
3253
 
3391
- dispatchEvt(document.body, "focus");
3392
- drainTimers();
3254
+ focusWindow();
3255
+ drainPendingTimers();
3393
3256
 
3394
3257
  expect(onFileDialogCancelSpy).not.toHaveBeenCalled();
3395
3258
  });
@@ -3397,24 +3260,19 @@ describe("useDropzone() hook", () => {
3397
3260
  it("does not throw if callback is not provided", () => {
3398
3261
  const { container } = render(
3399
3262
  <Dropzone onFileDialogCancel={null}>
3400
- {({ getRootProps, getInputProps, open }) => (
3263
+ {({ getRootProps, getInputProps }) => (
3401
3264
  <div {...getRootProps()}>
3402
3265
  <input {...getInputProps()} />
3403
- <button type="button" onClick={open}>
3404
- Open
3405
- </button>
3406
3266
  </div>
3407
3267
  )}
3408
3268
  </Dropzone>
3409
3269
  );
3410
3270
 
3411
- const btn = container.querySelector("button");
3412
- btn.click();
3413
- drainTimers();
3271
+ fireEvent.click(container.querySelector("div"));
3414
3272
 
3415
3273
  const fn = () => {
3416
- dispatchEvt(document.body, "focus");
3417
- drainTimers();
3274
+ focusWindow();
3275
+ drainPendingTimers();
3418
3276
  };
3419
3277
  expect(fn).not.toThrow();
3420
3278
  });
@@ -3433,8 +3291,7 @@ describe("useDropzone() hook", () => {
3433
3291
  </Dropzone>
3434
3292
  );
3435
3293
 
3436
- const dropzone = container.querySelector("div");
3437
- fireEvent.click(dropzone);
3294
+ fireEvent.click(container.querySelector("div"));
3438
3295
 
3439
3296
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
3440
3297
  });
@@ -3454,8 +3311,7 @@ describe("useDropzone() hook", () => {
3454
3311
  </Dropzone>
3455
3312
  );
3456
3313
 
3457
- const btn = container.querySelector("button");
3458
- btn.click();
3314
+ fireEvent.click(container.querySelector("button"));
3459
3315
 
3460
3316
  expect(onFileDialogOpenSpy).toHaveBeenCalled();
3461
3317
  });
@@ -3477,9 +3333,7 @@ describe("useDropzone() hook", () => {
3477
3333
  </Dropzone>
3478
3334
  );
3479
3335
 
3480
- const btn = container.querySelector("button");
3481
-
3482
- btn.click();
3336
+ fireEvent.click(container.querySelector("button"));
3483
3337
 
3484
3338
  expect(onClickSpy).toHaveBeenCalled();
3485
3339
  });
@@ -3501,14 +3355,12 @@ describe("useDropzone() hook", () => {
3501
3355
  </Dropzone>
3502
3356
  );
3503
3357
 
3504
- const dropzone = container.querySelector("div");
3505
- const btn = container.querySelector("button");
3506
-
3507
- btn.click();
3358
+ fireEvent.click(container.querySelector("button"));
3508
3359
 
3509
- const ref = activeRef.current;
3510
- expect(ref).not.toBeNull();
3511
- expect(dropzone).toContainElement(ref);
3360
+ expect(activeRef.current).not.toBeNull();
3361
+ expect(container.querySelector("div")).toContainElement(
3362
+ activeRef.current
3363
+ );
3512
3364
  });
3513
3365
 
3514
3366
  it("does nothing if {disabled} is true", () => {
@@ -3526,9 +3378,7 @@ describe("useDropzone() hook", () => {
3526
3378
  </Dropzone>
3527
3379
  );
3528
3380
 
3529
- const btn = container.querySelector("button");
3530
-
3531
- btn.click();
3381
+ fireEvent.click(container.querySelector("button"));
3532
3382
 
3533
3383
  expect(onClickSpy).not.toHaveBeenCalled();
3534
3384
  });
@@ -3546,9 +3396,7 @@ describe("useDropzone() hook", () => {
3546
3396
  </Dropzone>
3547
3397
  );
3548
3398
 
3549
- const btn = container.querySelector("button");
3550
-
3551
- const fn = () => btn.click();
3399
+ const fn = () => fireEvent.click(container.querySelector("button"));
3552
3400
  expect(fn).not.toThrow();
3553
3401
  });
3554
3402
  });
@@ -3564,21 +3412,18 @@ describe("useDropzone() hook", () => {
3564
3412
 
3565
3413
  const onDropSpy = jest.fn();
3566
3414
 
3567
- const ui = (
3415
+ const { container } = render(
3568
3416
  <Dropzone validator={validator} onDrop={onDropSpy} multiple={true}>
3569
- {({ getRootProps, getInputProps }) => (
3570
- <div {...getRootProps()}>
3571
- <input {...getInputProps()} />
3572
- </div>
3573
- )}
3417
+ {({ getRootProps }) => <div {...getRootProps()} />}
3574
3418
  </Dropzone>
3575
3419
  );
3576
3420
 
3577
- const { container, rerender } = render(ui);
3578
- const dropzone = container.querySelector("div");
3579
-
3580
- fireDrop(dropzone, createDtWithFiles(images));
3581
- await flushPromises(rerender, ui);
3421
+ await act(() =>
3422
+ fireEvent.drop(
3423
+ container.querySelector("div"),
3424
+ createDtWithFiles(images)
3425
+ )
3426
+ );
3582
3427
 
3583
3428
  expect(onDropSpy).toHaveBeenCalledWith(
3584
3429
  [images[0]],
@@ -3605,9 +3450,11 @@ describe("useDropzone() hook", () => {
3605
3450
  {({ getRootProps }) => <div id="root" {...getRootProps()} />}
3606
3451
  </Dropzone>
3607
3452
  );
3608
- const root = container.querySelector("#root");
3609
3453
 
3610
- expect(root).toHaveAttribute("role", "button");
3454
+ expect(container.querySelector("#root")).toHaveAttribute(
3455
+ "role",
3456
+ "presentation"
3457
+ );
3611
3458
  });
3612
3459
 
3613
3460
  test("users can override the default role attribute on the root", () => {
@@ -3618,21 +3465,37 @@ describe("useDropzone() hook", () => {
3618
3465
  )}
3619
3466
  </Dropzone>
3620
3467
  );
3621
- const root = container.querySelector("#root");
3622
3468
 
3623
- expect(root).toHaveAttribute("role", "generic");
3469
+ expect(container.querySelector("#root")).toHaveAttribute(
3470
+ "role",
3471
+ "generic"
3472
+ );
3624
3473
  });
3625
3474
  });
3626
3475
  });
3627
3476
 
3628
- async function flushPromises(rerender, ui) {
3629
- await act(() => waitFor(() => rerender(ui)));
3477
+ /**
3478
+ * drainPendingTimers just runs pending timers wrapped in act() to avoid
3479
+ * getting warnings from react about side effects that happen async.
3480
+ *
3481
+ * This can be used whenever a setTimeout(), setInterval() or async operation is used
3482
+ * which triggers a state update.
3483
+ */
3484
+ function drainPendingTimers() {
3485
+ return act(() => jest.runOnlyPendingTimers());
3630
3486
  }
3631
3487
 
3632
- function drainTimers() {
3633
- act(() => jest.runAllTimers());
3488
+ /**
3489
+ * focusWindow triggers focus on the window
3490
+ */
3491
+ function focusWindow() {
3492
+ return fireEvent.focus(document.body, { bubbles: true });
3634
3493
  }
3635
3494
 
3495
+ /**
3496
+ * createDtWithFiles creates a mock data transfer object that can be used for drop events
3497
+ * @param {File[]} files
3498
+ */
3636
3499
  function createDtWithFiles(files = []) {
3637
3500
  return {
3638
3501
  dataTransfer: {
@@ -3648,36 +3511,20 @@ function createDtWithFiles(files = []) {
3648
3511
  };
3649
3512
  }
3650
3513
 
3651
- function fireDragEnter(node, data) {
3652
- dispatchEvt(node, "dragenter", data);
3653
- }
3654
-
3655
- function fireDragOver(node, data) {
3656
- dispatchEvt(node, "dragover", data);
3657
- }
3658
-
3659
- function fireDragLeave(node, data) {
3660
- dispatchEvt(node, "dragleave", data);
3661
- }
3662
-
3663
- function fireDrop(node, data) {
3664
- dispatchEvt(node, "drop", data);
3665
- }
3666
-
3667
- // Using fireEvent.* doesn't work for our use case,
3668
- // we cannot set the event props
3669
- function dispatchEvt(node, type, data) {
3670
- const event = new Event(type, { bubbles: true });
3671
- if (data) {
3672
- Object.assign(event, data);
3673
- }
3674
- fireEvent(node, event);
3675
- }
3676
-
3514
+ /**
3515
+ * createFileSystemFileHandle creates a mock [FileSystemFileHandle](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileHandle)
3516
+ * @param {File} file
3517
+ */
3677
3518
  function createFileSystemFileHandle(file) {
3678
3519
  return { getFile: () => Promise.resolve(file) };
3679
3520
  }
3680
3521
 
3522
+ /**
3523
+ * createFile creates a mock File object
3524
+ * @param {string} name
3525
+ * @param {number} size
3526
+ * @param {string} type
3527
+ */
3681
3528
  function createFile(name, size, type) {
3682
3529
  const file = new File([], name, { type });
3683
3530
  Object.defineProperty(file, "size", {
@@ -3688,6 +3535,9 @@ function createFile(name, size, type) {
3688
3535
  return file;
3689
3536
  }
3690
3537
 
3538
+ /**
3539
+ * createThenable creates a Promise that can be controlled from outside its inner scope
3540
+ */
3691
3541
  function createThenable() {
3692
3542
  let done, cancel;
3693
3543