Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(upload): accept type should be more lenient #1064

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

ktmud
Copy link

@ktmud ktmud commented Sep 22, 2022

What:

Fixes a bug where file upload input[accept] is not respected when there are spaces in the accept attribute. Closes #1060.

Also raises an error in case the explicitly provided list of files did not have any match.

Why:

HTML attributes are notoriously lenient---if something is valid in HTML, then it should be valid in test cases. The accept attribute ignores both letter cases and whitespaces (including new lines). Plus it is very common for users to provide at least 1 space separator for for multi types, e.g. <input type="file" accept="image/png, image/jpeg" />.

Raising an error in case of empty filtered file list is more user-friendly than silently fail as a user's test case may fail anyway if an explicit call of upload was not successful.

How:

The PR handles these special cases using string replacement and case coercion.

Checklist:

  • Documentation N/A as this should be the default expected behavior.
  • Tests
  • Ready to be merged

@codesandbox-ci
Copy link

codesandbox-ci bot commented Sep 22, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 44b6498:

Sandbox Source
userEvent-dom Configuration
userEvent-react Configuration
vibrant-morning-8w6ywc Issue #1060

Copy link

@liamcmitchell-sc liamcmitchell-sc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just ran into this issue today, thanks for submitting a fix!

Comment on lines 69 to 85
return accept
.replace(/\s+/, '')
.toLowerCase()
.replace('.jpeg', '.jpg')
.replace('/jpeg', '/jpg')
.split(/,/)
.some(acceptToken => {
if (acceptToken.startsWith('.')) {
// tokens starting with a dot represent a file extension
return file.name
.toLowerCase()
.replace(/\.jpeg$/, '.jpg')
.endsWith(acceptToken)
} else if (wildcards.includes(acceptToken)) {
return file.type
.toLowerCase()
.startsWith(acceptToken.slice(0, acceptToken.length - 1))
}
return file.type.toLowerCase().replace('/jpeg', '/jpg') === acceptToken
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your replacements aren't global so will only replace the first instance of each.

Regarding JPEG/JPG; JPEG is the only valid MIME type but after playing with Chrome I see browsers are really lenient. If this is the same as other browsers then lenient matching here makes sense and will save devs from dealing with jpg/jpeg typos that don't matter. On the other hand, I would lean towards stricter tests and writing more lenient code (accept=".jpg, .jpeg").

Suggestion with global replacements and lenient matching:

// When matching files, browsers ignore case and consider jpeg/jpg interchangeable.
function normalize(nameOrType: string) {
  return nameOrType.toLowerCase().replace(/\bjpg\b/g, 'jpeg')
}

function isAcceptableFile(file: File, accept: string) {
  if (!accept) {
    return true
  }

  const wildcards = ['audio/*', 'image/*', 'video/*']

  return normalize(accept)
    .trim()
    .split(/\s*,\s*/)
    .some((acceptToken) => {
      // tokens starting with a dot represent a file extension
      if (acceptToken.startsWith('.')) {
        return normalize(file.name).endsWith(acceptToken)
      } else if (wildcards.includes(acceptToken)) {
        return normalize(file.type).startsWith(acceptToken.replace('*', ''))
      }
      return normalize(file.type) === acceptToken
    })
}

Copy link
Author

@ktmud ktmud Sep 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestions! I incorporated your changes but made a small adjustment to the regex---just to make it a little bit stricter to exclude some cases when jpg appears in the middle of a file or folder name.

@@ -54,20 +59,28 @@ export async function upload(
input.removeEventListener('fileDialog', fileDialog)
}

// When matching files, browsers ignore case and consider jpeg/jpg interchangeable.
function normalize(nameOrType: string) {
return nameOrType.toLowerCase().replace(/(\.|\/)jpg\b/g, '$1jpeg')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes came here to complain about them being case sensitive :D

new File(['there'], 'there.jpg', {type: 'audio/mp3'}),
new File(['there'], 'there.csv', {type: 'text/csv'}),
new File(['there'], 'there.jpg', {type: 'video/mp4'}),
new File(['hello'], 'image.png', {type: 'image/png'}),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put in some image.PNG for good measure

@ktmud
Copy link
Author

ktmud commented Oct 31, 2022

@ph-fritsche @Gpx @kentcdodds do you mind taking a look at this?

@kentcdodds
Copy link
Member

This looks good to me. I'm not an active maintainer on this package anymore so I don't think I should merge it, but if you don't get a reply in a day or so then I'll go ahead and merge it 👍

@ktmud
Copy link
Author

ktmud commented Jul 26, 2023

@ph-fritsche @Gpx @kentcdodds can we merge this?

@kentcdodds
Copy link
Member

Sorry nobody has replied on this PR.

Unfortunately it looks like in the time since this PR was updated, there were some dependencies that got changed which is likely what is causing the build failure. I'm afraid I don't have more time than to just click the "merge" button on this project, but it won't do any good if the build is failing. So this will have to wait until someone can adjust this PR to fix any build issues. Sorry.

@ph-fritsche
Copy link
Member

@ktmud I'm sorry about the delay here. Some updates in our dependencies blocked our previous CI. We also learned that the previous CI wasn't sufficient to ensure that bug fixes we apply don't cause new problems in other environments.
A new testing environment is already in place, but there still are some uncertainties that need to be resolved before a new version will be released. See the pinned issues and #1091 for details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

userEvent.upload does not work when input accept contains space
5 participants