User-event: uploaded files should be iterable

Created on 18 May 2020  路  9Comments  路  Source: testing-library/user-event

Current upload implementation sets the target element files to an object that matches the type definition for FileList. JSDOM and browsers implement FileList extending from Array, allowing them to be iterable (for example, one can perform [...element.files]). With the current implementation, after performing the upload, the attribute is not iterable.

sandbox with a demonstration: https://codesandbox.io/s/blazing-sunset-l6izw

Most helpful comment

At first I was tried to implement function for emulating FileList but it's not possible with current FileList implementation in jsdom.

function createFileList(files) {
  const fileList = new FileList(); // Illegal constructor
  for (const [index, file] of files.entries()) {
    fileList[index] = file;
  }
  fileList.item = (index) => fileList[index];
  return fileList;
}

Thats because of this line. So I see no clean option to make files as FileList at now. Here is the issue in jsdom we can keep eye on.

About iteration I'm not sure although its convenient to use. FileList is not marked as iterable in specs. What do you think @kentcdodds about supporting iteration as Chrome and Firefox do but not Edge (there is a proof in comments of this answer)?

All 9 comments

Thanks for the report @rbusquet!

What do you propose to be done?

I'm having a hard time figuring out how to properly mock it since I can't even find documentation on the fact that it should be iterable at all :/ chrome at least will implement it as an iterable. we could maybe implement the iterable protocol in the returned object? https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

If I could find some doc saying one should actually use Array.from or other ways to deal with the file list, I would for sure change my code to use that. The fact that browsers implement it as an iterable that makes me think we could do something here to make it consistent.

It seems to me that we should probably change this:

https://github.com/testing-library/user-event/blob/1f8ad44a4bdfdd9ab867aae80d0af90c61cab41c/src/index.js#L318-L322

To be a FileList rather than an object with FileList-like properties... What do you think @vadimshvetsov? Is there a reason you didn't implement it as a FileList from the start? I've checked and JSDOM does support FileList.

Hi, @rbusquet! Thanks for describing a problem here.

I鈥檇 tried to implement from the start upload as a FileList as close as possible because it cannot be created and a readonly unfortunately. The only way to create FileList is with DataTransfer constructor which has no reliable node polyfill as I鈥檝e found.

Your case looks common and I will think about how to make it works with another PR.

Thanks @vadimshvetsov, let me know if there鈥檚 anything I can do to help.

At first I was tried to implement function for emulating FileList but it's not possible with current FileList implementation in jsdom.

function createFileList(files) {
  const fileList = new FileList(); // Illegal constructor
  for (const [index, file] of files.entries()) {
    fileList[index] = file;
  }
  fileList.item = (index) => fileList[index];
  return fileList;
}

Thats because of this line. So I see no clean option to make files as FileList at now. Here is the issue in jsdom we can keep eye on.

About iteration I'm not sure although its convenient to use. FileList is not marked as iterable in specs. What do you think @kentcdodds about supporting iteration as Chrome and Firefox do but not Edge (there is a proof in comments of this answer)?

Thanks for investigating, @vadimshvetsov. That's a good point that Edge won't implement it, I'll double-check and make the team here aware if that's an issue.
Will wait on @kentcdodds opinion

If it's not easy to do in the library and it doesn't impact standards-compliant code anyway then I say we make no changes.

Sounds good to me. Again, thanks for investigating!

Was this page helpful?
0 / 5 - 0 ratings