feat: enforce Upload client-side constraints in UploadTester - #198
Open
totally-not-ai[bot] wants to merge 2 commits into
Open
feat: enforce Upload client-side constraints in UploadTester#198totally-not-ai[bot] wants to merge 2 commits into
totally-not-ai[bot] wants to merge 2 commits into
Conversation
UploadTester entered at the transport layer, so everything the vaadin-upload web component checks in _addFile() before a request is ever made had no counterpart on the server. maxFileSize and the accepted file types were ignored outright, and maxFiles was never compared against the file list, so a test could prove an upload path works with input the user could never submit and the FileRejectedEvent branch of an application was unreachable. Files now go through the same gate as in the browser, in the same order: maxFiles, then maxFileSize, then the accept pattern. A rejected file is not delivered to the upload handler or receiver; a FileRejectedEvent is fired instead, carrying the message from the component UploadI18N when set and the web component default otherwise. Since maxFiles is compared against the client file list, the tester emulates that list on the component. UploadTester#removeFile simulates the user removing an entry, firing FileRemovedEvent and freeing a slot, an aborted upload drops its file as the browser does, and pending Upload#clearFileList() calls are picked up on the next interaction. The three accept APIs all converge on the accept element property, so one pattern derived from it covers setAcceptedFileTypes, setAcceptedMimeTypes and setAcceptedFileExtensions alike. Fixes #180
maxFiles and maxFileSize were gated on the value being greater than zero, which cannot tell an unset limit from setMaxFiles(0). The client-side default is Infinity while the Upload getters report an unset limit as zero, so the element property now decides whether the limit applies at all, leaving setMaxFiles(0) rejecting every file as it does in a browser. Also cover the paths the client-side gate now sits in front of: a file accepted by the accept pattern but refused by Flow's server-side accepted type validation, repeated clearFileList() calls, and removeFile() on a component that is not usable. The class javadoc now spells out the emulated file list and how the client-side accepted type check relates to the server-side one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
UploadTesternow applies the same checks thevaadin-uploadweb component does before it sends a file, somaxFiles,maxFileSizeand the accepted file types are respected in browserless tests. A file that fails a check is not passed to the upload handler or receiver; aFileRejectedEventis fired instead, just like in a browser.Fixes #180
What changed
maxFiles, thenmaxFileSize, then theacceptpattern. The first failing check rejects the file.UploadI18Nwhen it is set, and from the web component default otherwise (Too Many Files.,File is Too Big.,Incorrect File Type.).maxFilesis compared against an emulated client file list kept on the component, so files from earlier calls still count. PendingUpload#clearFileList()calls are picked up on the next interaction.UploadTester#removeFilesimulates the user removing an entry: it firesFileRemovedEventand frees a slot. An aborted upload drops its file the way the browser does; a failed upload keeps it.setAcceptedFileTypes,setAcceptedMimeTypes,setAcceptedFileExtensions) end up in the sameacceptelement property, so one pattern derived from that property covers them all.setMaxFiles(0), which now rejects every file as it does in a browser.maxFilesno longer throwsIllegalStateExceptionfromuploadAll; the extra files are rejected instead.Use case
An app lets users attach up to two documents, at most 1 MB each, and shows a notification when a file is refused. The developer wants a test that proves the
FileRejectedEventbranch actually runs, which was impossible before because the tester ignored these limits.API Changes
com.vaadin.flow.component.upload.UploadTester
Test summary
maxFilesrejects only the extra file; the ones that fit are receivedmaxFilessetMaxFiles(0)rejects every filemaxFileSizeis rejected andAllFinishedis not fired; a file of exactly the limit is acceptedacceptpattern matches by mime wildcard and by file name extension; anything else is rejectedUploadI18Nwhen set, and from the web component default otherwiseremoveFilefiresFileRemovedEventand frees a slotremoveFileon a file that is not in the list throwsIllegalArgumentException; on an unusable component throwsIllegalStateExceptionUpload#clearFileList()calls each free the slotsFileRejectedEventis firedUploadTesterTest.uploadAll_fileCountExceeded_extraFilesRejected→ 1UploadTesterDeprecatedAPITest.uploadAll_fileCountExceeded_extraFilesRejected→ 1 (receiver/legacy API path)UploadTesterTest.upload_fileCountExceededOverSeparateUploads_extraFilesRejected→ 2UploadTesterTest.upload_maxFilesSetToZero_everyFileRejected→ 3UploadTesterTest.upload_exceedsMaxFileSize_rejected→ 4UploadTesterTest.upload_acceptedFileTypes_onlyMatchingFilesAccepted→ 5UploadTesterTest.upload_acceptedFileExtensions_disallowedExtensionRejected,UploadTesterTest.upload_acceptedMimeTypes_disallowedTypeRejected→ 5, 6 (default message)UploadTesterTest.upload_customI18n_rejectionUsesConfiguredMessage→ 6UploadTesterTest.removeFile_fileRemovedNotifiedAndSlotFreed→ 7UploadTesterTest.removeFile_fileNotInFileList_throws,UploadTesterTest.upload_componentNotUsable_throws→ 8UploadTesterTest.clearFileList_slotsFreed→ 9UploadTesterTest.uploadAborted_fileRemovedFromFileList,UploadTesterTest.uploadFailed_fileKeptInFileList→ 10UploadTesterTest.upload_acceptedByClientButNotByServer_notReceived→ 11Left untested on purpose: the exact regex escaping of every possible
accepttoken, since it is derived from the same property for all three accept APIs and is covered through them; and theremoveFile(File)overload, which only delegates toremoveFile(String).