[Solved] How can i handle a fileupload in a functional test?

I have a AddForm of a custom contenttype. In a functional test, i would check my custom constraints of some fields. The form contain a NamedBlobFile Field. My Question: How can i fill the fileuploadfield with a local file in a test?

# The Form
form = self.browser.getForm("form")

# a Textfield
input = form.getControl(name="form.widgets.firstname")
input.value = "Susi"

# fileupload field
input = form.getControl(name="form.widgets.file")
input.value = ???
        
# Save the form
button = form.getControl(name="form.buttons.save")
button.click()

Try the following:

def get_file_as_data64(filename):
    filepath = os.path.join(assets_dir, filename)
    with open(filepath, "rb") as f:
        datab64 = base64.b64encode(f.read())
    filename_b64 = base64.b64encode(str.encode(filename))
    data64 = "filenameb64:%s;datab64:%s" % (filename_b64.decode(), datab64.decode())
    return data64
...
input.value = get_file_as_data64(filename)

with the solution above, after the click on the save button, a traceback occurs

Traceback (most recent call last):
  File "/usr/lib/python3.10/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/lib/python3.10/unittest/case.py", line 591, in run
    self._callTestMethod(testMethod)
  File "/usr/lib/python3.10/unittest/case.py", line 549, in _callTestMethod
    method()
  File "/opt/development/projects/my.addon/src/my/addon/tests/test_constraints.py", line 148, in test_constraints_all_fields_valid
    button.click()
  File "/opt/devel/.buildout/eggs/cp310/zope.testbrowser-5.6.1-py3.10.egg/zope/testbrowser/browser.py", line 784, in click
    self.browser._clickSubmit(self._form, self._control)
  File "/opt/devel/.buildout/eggs/cp310/zope.testbrowser-5.6.1-py3.10.egg/zope/testbrowser/browser.py", line 277, in _clickSubmit
    self._processRequest(url, make_request)
  File "/opt/devel/.buildout/eggs/cp310/zope.testbrowser-5.6.1-py3.10.egg/zope/testbrowser/browser.py", line 282, in _processRequest
    resp = make_request(reqargs)
  File "/opt/devel/.buildout/eggs/cp310/zope.testbrowser-5.6.1-py3.10.egg/zope/testbrowser/browser.py", line 270, in make_request
    return self._submit(
  File "/opt/devel/.buildout/eggs/cp310/zope.testbrowser-5.6.1-py3.10.egg/zope/testbrowser/browser.py", line 318, in _submit
    return form.response.goto(url, method=form.method,
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/response.py", line 270, in goto
    return method(href, **args)
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/app.py", line 368, in post
    return self._gen_request('POST', url, params=params, headers=headers,
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/app.py", line 721, in _gen_request
    content_type, params = self.encode_multipart(
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/app.py", line 504, in encode_multipart
    _append_file([key] + list(value.value))
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/app.py", line 475, in _append_file
    key, filename, value, fcontent = self._get_file_info(file_info)
  File "/opt/devel/.buildout/eggs/cp310/WebTest-3.0.0-py3.10.egg/webtest/app.py", line 765, in _get_file_info
    raise ValueError('File content must be %s not %s'
ValueError: File content must be <class 'bytes'> not <class 'str'>

Sorry, I've overseen you were in functional tests.

Try the following:

Get the file contents as bytes (b"your content")

input = form.getControl(name="form.widgets.file")
import io
input.add_file(io.BytesIO(b"your content"), 'text/plain', 'filename.txt')
1 Like

:+1:
Thanks, that was the right solution input.add_file(binary, mimetype, filename).