@@ -13,12 +13,12 @@ it('should return an empty array if the passed event is not a DragEvent', async
13
13
expect ( files ) . toHaveLength ( 0 ) ;
14
14
} ) ;
15
15
16
- it ( 'should return the DataTransfer { files} if the passed event is a DragEvent ' , async ( ) => {
16
+ it ( 'should return the evt {target} { files} if the passed event is an input evt ' , async ( ) => {
17
17
const name = 'test.json' ;
18
18
const mockFile = createFile ( name , { ping : true } , {
19
19
type : 'application/json'
20
20
} ) ;
21
- const evt = dragEvtFromFiles ( mockFile ) ;
21
+ const evt = inputEvtFromFiles ( mockFile ) ;
22
22
23
23
const files = await fromEvent ( evt ) ;
24
24
expect ( files ) . toHaveLength ( 1 ) ;
@@ -33,27 +33,13 @@ it('should return the DataTransfer {files} if the passed event is a DragEvent',
33
33
expect ( file . path ) . toBe ( name ) ;
34
34
} ) ;
35
35
36
- it ( 'should return the evt {target} {files} if the passed event is an input evt' , async ( ) => {
37
- const name = 'test.json' ;
38
- const mockFile = createFile ( name , { ping : true } , {
39
- type : 'application/json'
40
- } ) ;
41
- const evt = inputEvtFromFiles ( mockFile ) ;
42
-
36
+ it ( 'should return an empty array if the evt {target} has no {files} prop' , async ( ) => {
37
+ const evt = inputEvtFromFiles ( ) ;
43
38
const files = await fromEvent ( evt ) ;
44
- expect ( files ) . toHaveLength ( 1 ) ;
45
- expect ( files . every ( file => file instanceof File ) ) . toBe ( true ) ;
46
-
47
- const [ file ] = files as FileWithPath [ ] ;
48
-
49
- expect ( file . name ) . toBe ( mockFile . name ) ;
50
- expect ( file . type ) . toBe ( mockFile . type ) ;
51
- expect ( file . size ) . toBe ( mockFile . size ) ;
52
- expect ( file . lastModified ) . toBe ( mockFile . lastModified ) ;
53
- expect ( file . path ) . toBe ( name ) ;
39
+ expect ( files ) . toHaveLength ( 0 ) ;
54
40
} ) ;
55
41
56
- it ( 'uses the DataTransfer {items} instead of {files} if it exists ' , async ( ) => {
42
+ it ( 'should return files from DataTransfer {items} if the passed event is a DragEvent ' , async ( ) => {
57
43
const name = 'test.json' ;
58
44
const mockFile = createFile ( name , { ping : true } , {
59
45
type : 'application/json'
@@ -74,25 +60,6 @@ it('uses the DataTransfer {items} instead of {files} if it exists', async () =>
74
60
expect ( file . path ) . toBe ( name ) ;
75
61
} ) ;
76
62
77
- it ( 'uses the DataTransfer {files} if {items} is empty' , async ( ) => {
78
- const name = 'test.json' ;
79
- const mockFile = createFile ( name , { ping : true } , {
80
- type : 'application/json'
81
- } ) ;
82
- const evt = dragEvtFromFilesAndItems ( [ mockFile ] , [ ] ) ;
83
-
84
- const files = await fromEvent ( evt ) ;
85
- expect ( files . every ( file => file instanceof File ) ) . toBe ( true ) ;
86
-
87
- const [ file ] = files as FileWithPath [ ] ;
88
-
89
- expect ( file . name ) . toBe ( mockFile . name ) ;
90
- expect ( file . type ) . toBe ( mockFile . type ) ;
91
- expect ( file . size ) . toBe ( mockFile . size ) ;
92
- expect ( file . lastModified ) . toBe ( mockFile . lastModified ) ;
93
- expect ( file . path ) . toBe ( name ) ;
94
- } ) ;
95
-
96
63
it ( 'skips DataTransfer {items} that are of kind "string"' , async ( ) => {
97
64
const name = 'test.json' ;
98
65
const mockFile = createFile ( name , { ping : true } , {
@@ -128,22 +95,20 @@ it('can read a tree of directories recursively and return a flat list of FileWit
128
95
createFile ( '.DS_Store' , { macOs : true } ) ,
129
96
createFile ( 'Thumbs.db' , { windows : true } )
130
97
] ;
131
- const entries = [
132
- fileSystemFileEntryFromFile ( f1 ) ,
133
- fileSystemFileEntryFromFile ( f2 ) ,
134
- fileSystemDirEntryFromFile ( [
98
+ const evt = dragEvtFromItems ( [
99
+ dataTransferItemFromEntry ( fileSystemFileEntryFromFile ( f1 ) , f1 ) ,
100
+ dataTransferItemFromEntry ( fileSystemFileEntryFromFile ( f2 ) , f2 ) ,
101
+ dataTransferItemFromEntry ( fileSystemDirEntryFromFile ( [
135
102
fileSystemFileEntryFromFile ( f3 ) ,
136
103
fileSystemDirEntryFromFile ( [
137
104
fileSystemFileEntryFromFile ( f4 )
138
105
] ) ,
139
106
fileSystemFileEntryFromFile ( f5 )
140
- ] , 2 ) ,
141
- fileSystemFileEntryFromFile ( f6 ) ,
142
- fileSystemFileEntryFromFile ( f7 ) ,
143
- fileSystemFileEntryFromFile ( f8 )
144
- ] ;
145
-
146
- const evt = dragEvtFromItems ( entries . map ( dataTransferItemFromEntry ) ) ;
107
+ ] , 2 ) ) ,
108
+ dataTransferItemFromEntry ( fileSystemFileEntryFromFile ( f6 ) , f6 ) ,
109
+ dataTransferItemFromEntry ( fileSystemFileEntryFromFile ( f7 ) , f7 ) ,
110
+ dataTransferItemFromEntry ( fileSystemFileEntryFromFile ( f8 ) , f8 )
111
+ ] ) ;
147
112
148
113
const items = await fromEvent ( evt ) ;
149
114
const files = sortFiles ( items as FileWithPath [ ] ) ;
@@ -170,34 +135,81 @@ it('returns the DataTransfer {items} if the DragEvent {type} is not "drop"', asy
170
135
expect ( itm . kind ) . toBe ( 'file' ) ;
171
136
} ) ;
172
137
173
- // tslint:disable-next-line: max-line-length
174
- it ( 'filters DataTransfer {items} if the DragEvent {type} is not "drop" and DataTransferItem {kind} is "string"' , async ( ) => {
175
- const name = 'test.json' ;
176
- const mockFile = createFile ( name , { ping : true } , {
177
- type : 'application/json'
178
- } ) ;
179
- const file = dataTransferItemFromFile ( mockFile ) ;
180
- const str = dataTransferItemFromStr ( 'test' ) ;
181
- const evt = dragEvtFromItems ( [ file , str ] , 'dragenter' ) ;
138
+ it (
139
+ 'filters DataTransfer {items} if the DragEvent {type} is not "drop" and DataTransferItem {kind} is "string"' ,
140
+ async ( ) => {
141
+ const name = 'test.json' ;
142
+ const mockFile = createFile ( name , { ping : true } , {
143
+ type : 'application/json'
144
+ } ) ;
145
+ const file = dataTransferItemFromFile ( mockFile ) ;
146
+ const str = dataTransferItemFromStr ( 'test' ) ;
147
+ const evt = dragEvtFromItems ( [ file , str ] , 'dragenter' ) ;
182
148
183
- const items = await fromEvent ( evt ) ;
184
- expect ( items ) . toHaveLength ( 1 ) ;
149
+ const items = await fromEvent ( evt ) ;
150
+ expect ( items ) . toHaveLength ( 1 ) ;
185
151
186
- const [ item ] = items as DataTransferItem [ ] ;
152
+ const [ item ] = items as DataTransferItem [ ] ;
187
153
188
- expect ( item . kind ) . toBe ( file . kind ) ;
189
- expect ( item . kind ) . toBe ( 'file' ) ;
154
+ expect ( item . kind ) . toBe ( file . kind ) ;
155
+ expect ( item . kind ) . toBe ( 'file' ) ;
156
+ }
157
+ ) ;
158
+
159
+ it ( 'should throw if reading dir entries fails' , async done => {
160
+ const mockFiles = sortFiles ( [
161
+ createFile ( 'ping.json' , { ping : true } ) ,
162
+ createFile ( 'pong.json' , { pong : true } )
163
+ ] ) ;
164
+ const [ f1 , f2 ] = mockFiles ;
165
+ const evt = dragEvtFromItems ( [
166
+ dataTransferItemFromEntry ( fileSystemDirEntryFromFile ( [
167
+ fileSystemFileEntryFromFile ( f1 ) ,
168
+ fileSystemFileEntryFromFile ( f2 )
169
+ ] , 1 , 1 ) )
170
+ ] ) ;
171
+
172
+ try {
173
+ await fromEvent ( evt ) ;
174
+ done . fail ( 'Getting the files should have failed' ) ;
175
+ } catch ( err ) {
176
+ done ( ) ;
177
+ }
190
178
} ) ;
191
179
180
+ it ( 'should throw if reading file entry fails' , async done => {
181
+ const mockFiles = sortFiles ( [
182
+ createFile ( 'ping.json' , { ping : true } ) ,
183
+ createFile ( 'pong.json' , { pong : true } )
184
+ ] ) ;
185
+ const [ f1 , f2 ] = mockFiles ;
186
+ const evt = dragEvtFromItems ( [
187
+ dataTransferItemFromEntry ( fileSystemDirEntryFromFile ( [
188
+ fileSystemFileEntryFromFile ( f1 ) ,
189
+ fileSystemFileEntryFromFile ( f2 , 'Oops :(' )
190
+ ] , 1 , 1 ) )
191
+ ] ) ;
192
+
193
+ try {
194
+ await fromEvent ( evt ) ;
195
+ done . fail ( 'Getting the files should have failed' ) ;
196
+ } catch ( err ) {
197
+ done ( ) ;
198
+ }
199
+ } ) ;
200
+
201
+ it ( 'should throw if DataTransferItem is not a File' , async done => {
202
+ const item = dataTransferItem ( null , 'file' ) ;
203
+ const evt = dragEvtFromFilesAndItems ( [ ] , [ item ] ) ;
204
+
205
+ try {
206
+ await fromEvent ( evt ) ;
207
+ done . fail ( 'Getting the files should have failed' ) ;
208
+ } catch ( err ) {
209
+ done ( ) ;
210
+ }
211
+ } ) ;
192
212
193
- function dragEvtFromFiles ( files : File | File [ ] , type : string = 'drop' ) : DragEvent {
194
- return {
195
- type,
196
- dataTransfer : {
197
- files : Array . isArray ( files ) ? files : [ files ]
198
- }
199
- } as any ;
200
- }
201
213
202
214
function dragEvtFromItems ( items : DataTransferItem | DataTransferItem [ ] , type : string = 'drop' ) : DragEvent {
203
215
return {
@@ -227,6 +239,16 @@ function dataTransferItemFromFile(file: File): DataTransferItem {
227
239
} as any ;
228
240
}
229
241
242
+ function dataTransferItem ( file ?: any , kind ?: string , type : string = '' ) : DataTransferItem {
243
+ return {
244
+ kind,
245
+ type,
246
+ getAsFile ( ) {
247
+ return file ;
248
+ }
249
+ } as any ;
250
+ }
251
+
230
252
function dataTransferItemFromStr ( str : string ) : DataTransferItem {
231
253
return {
232
254
kind : 'string' ,
@@ -240,26 +262,37 @@ function dataTransferItemFromStr(str: string): DataTransferItem {
240
262
} as any ;
241
263
}
242
264
243
- function dataTransferItemFromEntry ( entry : FileEntry | DirEntry ) : DataTransferItem {
265
+ function dataTransferItemFromEntry ( entry : FileEntry | DirEntry , file ?: File ) : DataTransferItem {
244
266
return {
245
267
kind : 'file' ,
268
+ getAsFile ( ) {
269
+ return file ;
270
+ } ,
246
271
webkitGetAsEntry : ( ) => {
247
272
return entry ;
248
273
}
249
274
} as any ;
250
275
}
251
276
252
- function fileSystemFileEntryFromFile ( file : File ) : FileEntry {
277
+ function fileSystemFileEntryFromFile ( file : File , err ?: any ) : FileEntry {
253
278
return {
254
279
isDirectory : false ,
255
280
isFile : true ,
256
- file ( cb : ( file : File ) => void ) {
257
- cb ( file ) ;
281
+ file ( cb , errCb ) {
282
+ if ( err ) {
283
+ errCb ( err ) ;
284
+ } else {
285
+ cb ( file ) ;
286
+ }
258
287
}
259
288
} ;
260
289
}
261
290
262
- function fileSystemDirEntryFromFile ( files : Array < FileEntry | DirEntry > , batchSize : number = 1 ) : DirEntry {
291
+ function fileSystemDirEntryFromFile (
292
+ files : Array < FileEntry | DirEntry > ,
293
+ batchSize : number = 1 ,
294
+ throwAfter : number = 0
295
+ ) : DirEntry {
263
296
const copy = files . slice ( 0 ) ;
264
297
const batches : Array < Array < FileEntry | DirEntry > > = [ ] ;
265
298
@@ -278,10 +311,14 @@ function fileSystemDirEntryFromFile(files: Array<FileEntry | DirEntry>, batchSiz
278
311
let cbCount = 0 ;
279
312
280
313
return {
281
- readEntries ( cb ) {
314
+ readEntries ( cb , errCb ) {
282
315
const batch = batches [ cbCount ] ;
283
316
cbCount ++ ;
284
317
318
+ if ( throwAfter !== 0 && cbCount === throwAfter ) {
319
+ errCb ( 'Failed to read files' ) ;
320
+ }
321
+
285
322
if ( batch ) {
286
323
cb ( batch ) ;
287
324
} else {
@@ -295,9 +332,11 @@ function fileSystemDirEntryFromFile(files: Array<FileEntry | DirEntry>, batchSiz
295
332
296
333
function inputEvtFromFiles ( ...files : File [ ] ) : Event {
297
334
const input = document . createElement ( 'input' ) ;
298
- Object . defineProperty ( input , 'files' , {
299
- value : files
300
- } ) ;
335
+ if ( files . length ) {
336
+ Object . defineProperty ( input , 'files' , {
337
+ value : files
338
+ } ) ;
339
+ }
301
340
return {
302
341
target : input
303
342
} as any ;
@@ -316,7 +355,10 @@ function sortFiles<T extends File>(files: T[]) {
316
355
317
356
318
357
interface FileEntry extends Entry {
319
- file ( cb : ( file : File ) => void ) : void ;
358
+ file (
359
+ cb : ( file : File ) => void ,
360
+ errCb : ( err : any ) => void
361
+ ) : void ;
320
362
}
321
363
322
364
interface DirEntry extends Entry {
@@ -329,5 +371,8 @@ interface Entry {
329
371
}
330
372
331
373
interface DirReader {
332
- readEntries ( cb : ( entries : Array < FileEntry | DirEntry > ) => void ) : void ;
374
+ readEntries (
375
+ cb : ( entries : Array < FileEntry | DirEntry > ) => void ,
376
+ errCb : ( err : any ) => void
377
+ ) : void ;
333
378
}
0 commit comments