Skip to content

Commit 7c0596f

Browse files
committed
fix: handle getFile returning null and close #106, close #120
1 parent 90fa75c commit 7c0596f

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

src/file-selector.spec.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,35 @@ it('should not use getAsFileSystemHandle when not in a secure context', async ()
333333
window.isSecureContext = true;
334334
});
335335

336+
it('should reject when getAsFileSystemHandle resolves to null', async () => {
337+
const evt = dragEvtFromItems([
338+
dataTransferItemWithFsHandle(null, null)
339+
]);
340+
expect(fromEvent(evt)).rejects.toThrow('[object Object] is not a File');
341+
});
342+
343+
it('should fallback to getAsFile when getAsFileSystemHandle resolves to undefined', async () => {
344+
const name = 'test.nosec.json';
345+
const mockFile = createFile(name, {ping: false}, {
346+
type: 'application/json'
347+
});
348+
const evt = dragEvtFromItems([
349+
dataTransferItemWithFsHandle(mockFile, undefined)
350+
]);
351+
352+
const files = await fromEvent(evt);
353+
expect(files).toHaveLength(1);
354+
expect(files.every(file => file instanceof File)).toBe(true);
355+
356+
const [file] = files as FileWithPath[];
357+
358+
expect(file.name).toBe(mockFile.name);
359+
expect(file.type).toBe(mockFile.type);
360+
expect(file.size).toBe(mockFile.size);
361+
expect(file.lastModified).toBe(mockFile.lastModified);
362+
expect(file.path).toBe(`./${name}`);
363+
});
364+
336365
function dragEvtFromItems(items: DataTransferItem | DataTransferItem[], type: string = 'drop'): DragEvent {
337366
return {
338367
type,
@@ -403,7 +432,7 @@ function dataTransferItemFromEntry(entry: FileEntry | DirEntry, file?: File): Da
403432
} as any;
404433
}
405434

406-
function dataTransferItemWithFsHandle(file?: File, h?: FileSystemFileHandle): DataTransferItem {
435+
function dataTransferItemWithFsHandle(file?: File | null, h?: FileSystemFileHandle | null): DataTransferItem {
407436
return {
408437
kind: 'file',
409438
getAsFile() {
@@ -510,7 +539,7 @@ function sortFiles<T extends File>(files: T[]) {
510539

511540

512541
interface FileSystemFileHandle {
513-
getFile(): Promise<File>;
542+
getFile(): Promise<File | null>;
514543
}
515544

516545
type FileOrDirEntry = FileEntry | DirEntry

src/file-selector.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,16 @@ async function fromDataTransferItem(item: DataTransferItem, entry?: FileSystemEn
129129
// - https://github.com/react-dropzone/react-dropzone/issues/1397
130130
if (globalThis.isSecureContext && typeof (item as any).getAsFileSystemHandle === 'function') {
131131
const h = await (item as any).getAsFileSystemHandle();
132-
const file = await h.getFile();
133-
file.handle = h;
134-
return toFileWithPath(file);
132+
if (h === null) {
133+
throw new Error(`${item} is not a File`);
134+
}
135+
// It seems that the handle can be `undefined` (see https://github.com/react-dropzone/file-selector/issues/120),
136+
// so we check if it isn't; if it is, the code path continues to the next API (`getAsFile`).
137+
if (h !== undefined) {
138+
const file = await h.getFile();
139+
file.handle = h;
140+
return toFileWithPath(file);
141+
}
135142
}
136143
const file = item.getAsFile();
137144
if (!file) {

0 commit comments

Comments
 (0)