mbraak/django-file-form

Getting InMemoryUploadedFile during testing

BoPeng opened this issue · 3 comments

class UploadWidget(BaseUploadWidget):
def value_from_datadict(
self, data: QueryDict, files: MultiValueDict, prefixed_field_name: str
):
upload = super().value_from_datadict(data, files, prefixed_field_name)
if upload:
return upload
else:
uploads = get_uploads(data, prefixed_field_name)
upload = uploads[0] if uploads else None
metadata = get_file_meta(data, prefixed_field_name)
if upload and upload.name in metadata:
upload.metadata = metadata[upload.name]
return upload

I got InMemoryUploadedFile instead of S3UploadedFileWithId while testing my upload widget using selenium-based tests, even when the file has been confirmed to be uploaded to s3 (localstack). The culprit appears to be the super().value_from_datadict part, which basically says, for testing, If the input widget is filled with file data (but S3 is triggered), super().value_from_datadict returns a valid InMemoryUploadedFile, then the S3 information would be completely ignored....

Perhaps the super() logic should be removed?

Edit: I think what is happening is that when selenium fills the input element with sendkeys, it automatically uploads to the file, which makes the super() call returns a valid InMemoryUploadedFile object. My tests now work after removing the super() call.

I will have a look.

I added a test for an s3 single file upload, but I don't get the error. super().value_from_datadict returns None. Also see this pr: #460

I think the super call is necessary to support uploads without javascript. Removing the call breaks a lot of tests in the test suite.

It's strange that super().value_from_datadict returns a value. At that point there shouldn't be an uploaded file in the form data (parameters data or files).

Could you share some more info about the selenium test?

  • Is it for a single or a multiple field (UploadedFileField or MultipleUploadedFileField)?
  • Does the test wait for the upload to finish? E.g. by looking for an html element with the classdff-upload-success.
  • In value_from_datadict, does data and files contain an upload?

Thanks @mbraak I was wondering why your selenium tests work but mine did not. It turned out that my test has a bug in waiting for the completion of the upload so the form was submitted prematurely. So it appears that

  1. selenium uploads the file and attach its content to input element with sendkeys
  2. if the form is submitted prematurely, the form will look like a "local download" and returns InMemoryUploadedFile.
  3. If the js code is allowed to complete, the file content is somehow "consumed" and super() will return invalid object, allowing the s3 part to work.

To answer your question, if the form is submitted prematurely, the *-upload fields of data are empty ([]) and files contains the file object.