User-event: `upload` method doesn't account for input `accept` attribute

Created on 27 Jul 2020  路  6Comments  路  Source: testing-library/user-event

  • @testing-library/user-event version: 12.0.11
  • Testing Framework and version: Mocha 6.1.4, Chai 3.5.0, Sinon 9.0.2
  • DOM Environment: JSDOM 16.2.2

Relevant code or config:

it('restricts accepted file types', () => {
  const onChange = sinon.spy();
  const { getByTestId } = render(
    <input data-testid="upload" type="file" accept="image/*" onChange={onChange} />,
  );
  const file = new window.File([''], 'upload.txt', { type: 'text/plain' });
  userEvent.upload(getByTestId('upload'), file);

  expect(onChange.called).to.be.false();
});

What you did:

  1. Assign accept to <input type="file" /> to limit accepted file types
  2. Trigger userEvent.upload with an unacceptable file type and expect change callback not to be fired

What happened:

Change callback is triggered.

  1) demo
       restricts accepted file types:
     AssertionError: expected true to be false
      at execDeferred (node_modules/dirty-chai/lib/dirty-chai.js:43:29)
      at Assertion.newMethod (node_modules/dirty-chai/lib/dirty-chai.js:68:18)
      at Assertion.assert (node_modules/chai/lib/chai/utils/addChainableMethod.js:84:49)
      at Context.<anonymous> (spec/demo.js:29:3)
      at processImmediate (internal/timers.js:456:21)

Problem description:

If the scope of @testing-library/user-event should include validations that a user would encounter in interacting with page elements, I would expect accept attribute to be respected.

Suggested solution:

There is currently one validation in upload:

https://github.com/testing-library/user-event/blob/448046c237482837d18439ed9fc1128065e641f3/src/upload.js#L7

It's suggested this could be expanded to cover fileOrFiles validation based on target element's accept attribute:

Pseudo-code:

if (!every(fileOrFiles, createIsAcceptableByAttribute(element.getAttribute('accept'))) return
enhancement help wanted

All 6 comments

That suggested solution seems reasonable to me 馃憤

It seems that browsers don't reliably block uploads of files whose extension/MIME type doesn't match the accept value. From MDN:

The accept attribute doesn't validate the types of the selected files; it simply provides hints for browsers to guide users towards selecting the correct file types. It is still possible (in most cases) for users to toggle an option in the file chooser that makes it possible to override this and select any file they wish, and then choose incorrect file types.

Because of this, you should make sure that the accept attribute is backed up by appropriate server-side validation.

Is there any concern that, if this type of validation was added to upload, it would give users undue confidence that files of unexpected types couldn't possibly be uploaded? Or is there more value in assuming that the browser successfully discourages uploads of unexpected file types?

@maxnewlands Those are good questions! I could see arguments either way. Personally, I might still lean toward validating, due to the following:

  • Technically, as a user, I could also remove the disabled attribute and fill out a field (maybe not quite as easily, but I could!). We'd still rely on server validation there, yet @testing-library/user-events will prevent input of a disabled field. There's some precedent here.
  • If a goal of @testing-library/user-event is to serve as a higher level of abstraction than the low-level fireEvent and mimic more of the real experience of a user, I think it would be reasonable to expect accept validation to be accounted for.

Thank you for bringing this up @maxnewlands,

Is there any concern that, if this type of validation was added to upload, it would give users undue confidence that files of unexpected types couldn't possibly be uploaded?

Yes, this is a major concern and for me it's enough that I don't think this should be included in the library. It's one thing to prevent the user from doing things that the browser prevents when certain attributes are on an element. It's a different thing entirely to programmatically make it impossible to do something that a user could actually do (like attempt to upload a file that's the wrong type).

Thanks @kentcdodds @maxnewlands . I see your points, and am fine to go ahead and close the issue.

From my perspective, it still leaves an open question of "How do I test the intended effects of adding accept to my input field?" It seems if this filtering is so easy to bypass, I may still want to have some _client-side_ validation (in addition the server-side) to check the type of the file that the user selected. But then...

  • Is the accept attribute still valuable? Probably, since it's at least a nice UX to try to direct the user toward success
  • Do I need or want test coverage for this attribute?
  • If so, how would I achieve that? At this point, is it a matter of testing the DOM elements directly? (arguably bypassing testing as "what the user would experience")

What I would do is add an assertion that the attribute is there and then trust the browser to do what it should based on its presence.

Was this page helpful?
0 / 5 - 0 ratings