Adding testbrowser Form Inputs

by Ross Patterson last modified 2008-11-23T04:04:50+02:00
Mock dynamic form inputs with zope.testbrowser

When writing functional tests that cover forms with elements that are dynamically manipulated from JavaScript, such as the ReferenceBrowserWidget, I often simply didn't cover those elements becuase it simply wasn't worth it to add Selenium or zc.testbrowser.real as a testing dependency  for what are usually very small pieces of what is being tested.

What I've always wanted was a way to reproduce the effects of the dynamic manipulation in the testbrowser.  When I was recently bitten by a bug that I didn't catch for lack of functional coverage of a ReferenceField, I dug into the ClientForm package that zope.testbrowser uses and found the HTMLForm.new_control() method.  This is the method that ClientForm uses to construct the controls that zope.testbrowser provides lookup for.

Since Firefox allows you to inspect the DOM either by selecting the elements and using "View selection source" or with Web Developer's DOM inspector, you can ferret out what the dynamic manipulation created and use that information to construct the HTMLForm.new_control() call that will reproduce that.  The following example would add the foo object to the related items on another object's edit form.

>>> form = browser.getForm(name="edit_form")
>>> form.mech_form.new_control(
...     type='checkbox',
...     name='relatedItems:list',
...     attrs=dict(checked='checked', value=foo.UID()))

See the ClientForm source for more details.

BTW, it seems the the ReferenceBrowserWidget includes an empty string on submission of the form.  This empty string case seems to be handled in the field's set() method and not in the widget where it seems like it should be.  Not knowing this, I implemented a custom mutator with a bug that I didn't catch because I didn't have test coverage on the form submission.  Now I do.  :)