Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simplified example to demonstrate how to Mock a FileList for unit testing purposes.
// Method to test
public uploadFileList(files: FileList) {
// whatever
}
// Test
it("uploadFileList", () => {
const blob = new Blob([""], { type: "text/html" });
blob["lastModifiedDate"] = "";
blob["name"] = "filename";
const file = <File>blob;
const fileList = {
0: file,
1: file,
length: 2,
item: (index: number) => file
};
const spy = spyOn(service, "uploadFileList").and.returnValue([]);
expect(service.uploadFileList(fileList)).toEqual([]);
});
@kroeder

This comment has been minimized.

Copy link

@kroeder kroeder commented Mar 18, 2020

Thanks for saving my day 🎉

I implemented a more dynamic way using your approach

interface MockFile {
    name: string;
    body: string;
    mimeType: string;
}

const createFileFromMockFile = (file: MockFile): File => {
    const blob = new Blob([file.body], { type: file.mimeType }) as any;
    blob['lastModifiedDate'] = new Date();
    blob['name'] = file.name;
    return blob as File;
};

const createMockFileList = (files: MockFile[]) => {
    const fileList: FileList = {
        length: files.length,
        item(index: number): File {
            return fileList[index];
        }
    };
    files.forEach((file, index) => fileList[index] = createFileFromMockFile(file));

    return fileList;
};

How to use

/* Just some random test I need */
it('should convert a text file', async () => {
    const service: DocumentService = TestBed.get(DocumentService);

    const fileList = createMockFileList([
        {
            body: 'test',
            mimeType: 'text/plain',
            name: 'test.txt'
        }
    ]);

    const convertedFiles = await service.convertFilesToModelDocuments(fileList);

    expect(convertedFiles).toBe([
        {
            name: 'test.txt',
            body: 'dGVzdA==',
            mimeType: 'text/plain'
        }
    ]);
});

Hope this helps!

@VergilSkye

This comment has been minimized.

Copy link

@VergilSkye VergilSkye commented Jun 1, 2020

Thank soo much! I almost lost one hour trying to do "files = new FileList()" without success

@neil-berg

This comment has been minimized.

Copy link

@neil-berg neil-berg commented Jun 18, 2020

Thanks @kroeder! Very helpful.

@delorie

This comment has been minimized.

Copy link

@delorie delorie commented Jul 28, 2020

Thanks @kroeder!

@shabbir-dhangot

This comment has been minimized.

Copy link

@shabbir-dhangot shabbir-dhangot commented Mar 15, 2021

getting this error

Property '[Symbol.iterator]' is missing in type '{ length: number; item(index: number): File; }' but required in type 'FileList'
@CameronJThomas

This comment has been minimized.

Copy link

@CameronJThomas CameronJThomas commented Apr 8, 2021

Depending on the use case, a much simpler - and cleaner - way of handling this is to use a Jasmine spy. For example, I needed to mock a DragEvent for testing my drag & drop handlers. For this, we can instantiate a DataTransfer and that comes with a FileList of its own, which makes this possible:

const fileList = [{ name: 'Example File' }, { name: 'Another File' }]; 
const dataTransfer = new DataTransfer();
const dragEvent = { dataTransfer } as DragEvent;

spyOnProperty(dataTransfer, 'files').and.returnValue(fileList);

If you have a use case in which a FileList is unavoidable, I would recommend seeing if there's a relevant object you can instantiate and spy on. That way you don't have to worry about effectively "replicating" the structure of the FileList, which would likely cause TS errors if any new fields are added to FileList in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment