[Checkins] SVN: z3c.form/trunk/src/z3c/form/ improve group testing,

Roger Ineichen roger at projekt01.ch
Fri Apr 3 00:08:51 EDT 2009


Log message for revision 98805:
  improve group testing,
  now we have 100% coverage in every test except the object.py implementation
  
  Note:
  the z3c.pt implementation is buggy and doesn't work right.
  I left a test in group.txt which shows that a div tag get skipped with z3c.pt.
  We need to fix this in z3c.pt or chameleon and the test should be fine without
  any changes.

Changed:
  U   z3c.form/trunk/src/z3c/form/group.txt
  A   z3c.form/trunk/src/z3c/form/tests/simple_nested_groupedit.pt

-=-
Modified: z3c.form/trunk/src/z3c/form/group.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/group.txt	2009-04-03 04:06:20 UTC (rev 98804)
+++ z3c.form/trunk/src/z3c/form/group.txt	2009-04-03 04:08:51 UTC (rev 98805)
@@ -456,9 +456,94 @@
   >>> attrs.attributes
   ('license', 'address', 'model', 'make', 'year')
 
-And that's it!
 
+Group form as instance
+----------------------
 
+It is also possible to use group instances in forms. Let's setup our previous
+form and assing a group instance:
+
+  >>> class RegistrationEditForm(group.GroupForm, form.EditForm):
+  ...     fields = field.Fields(IVehicleRegistration).select(
+  ...         'firstName', 'lastName')
+  ...
+  ...     template = viewpagetemplatefile.ViewPageTemplateFile(
+  ...         'simple_groupedit.pt', os.path.dirname(tests.__file__))
+
+  >>> request = testing.TestRequest()
+
+  >>> edit = RegistrationEditForm(reg, request)
+
+Instanciate the form and use a group class and a group instance:
+
+  >>> carGroupInstance = CarGroup(edit.context, request, edit)
+  >>> edit.groups = (LicenseGroup, carGroupInstance)
+  >>> edit.update()
+  >>> print edit.render()
+  <html xmlns="http://www.w3.org/1999/xhtml">
+    <body>
+      <form action=".">
+        <div class="row">
+          <label for="form-widgets-firstName">First Name</label>
+          <input id="form-widgets-firstName"
+                 name="form.widgets.firstName"
+                 class="text-widget required textline-field"
+                 value="Stephan" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-lastName">Last Name</label>
+          <input id="form-widgets-lastName"
+                 name="form.widgets.lastName"
+                 class="text-widget required textline-field"
+                 value="Richter" type="text" />
+        </div>
+        <fieldset>
+          <legend>License</legend>
+        <div class="row">
+          <label for="form-widgets-license">License</label>
+          <input id="form-widgets-license"
+                 name="form.widgets.license"
+                 class="text-widget required textline-field"
+                 value="MA 4038765" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-address">Address</label>
+          <input id="form-widgets-address"
+                 name="form.widgets.address"
+                 class="text-widget required textline-field"
+                 value="11 Main St, Maynard, MA" type="text" />
+        </div>
+        </fieldset>
+        <fieldset>
+          <legend>Car</legend>
+        <div class="row">
+          <label for="form-widgets-model">Model</label>
+          <input id="form-widgets-model" name="form.widgets.model"
+                 class="text-widget required textline-field"
+                 value="Ford" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-make">Make</label>
+          <input id="form-widgets-make" name="form.widgets.make"
+                 class="text-widget required textline-field"
+                 value="F150" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-year">Year</label>
+          <input id="form-widgets-year" name="form.widgets.year"
+                 class="text-widget required textline-field"
+                 value="2006" type="text" />
+            </div>
+        </fieldset>
+        <div class="action">
+          <input id="form-buttons-apply" name="form.buttons.apply"
+                 class="submit-widget button-field" value="Apply"
+                 type="submit" />
+        </div>
+      </form>
+    </body>
+  </html>
+
 Groups with Different Content
 -----------------------------
 
@@ -524,7 +609,6 @@
   ...     template = viewpagetemplatefile.ViewPageTemplateFile(
   ...         'simple_groupedit.pt', os.path.dirname(tests.__file__))
 
-
   >>> reg = VehicleRegistration(
   ...               license=u'MA 40387',
   ...               address=u'10 Main St, Maynard, MA',
@@ -645,10 +729,9 @@
 
 
 Nested Groups
------------------
+-------------
 
-The group can contains groups.
-Let's adapt the previous RegistrationEditForm
+The group can contains groups. Let's adapt the previous RegistrationEditForm:
 
   >>> class OwnerGroup(group.Group):
   ...     label = u'Owner'
@@ -662,14 +745,16 @@
   ...     fields = field.Fields(IVehicleRegistration).omit(
   ...         'owner')
   ...     groups = (OwnerGroup,)
+  ...
+  ...     template = viewpagetemplatefile.ViewPageTemplateFile(
+  ...         'simple_groupedit.pt', os.path.dirname(tests.__file__))
 
   >>> class RegistrationEditForm(group.GroupForm, form.EditForm):
   ...     groups = (VehicleRegistrationGroup,)
   ...
   ...     template = viewpagetemplatefile.ViewPageTemplateFile(
-  ...         'simple_groupedit.pt', os.path.dirname(tests.__file__))
+  ...         'simple_nested_groupedit.pt', os.path.dirname(tests.__file__))
 
-
   >>> reg = VehicleRegistration(
   ...               license=u'MA 40387',
   ...               address=u'10 Main St, Maynard, MA',
@@ -721,11 +806,168 @@
   >>> reg.year
   u'2005'
 
-So what happens, if errors happen inside a nested group?
+So what happens, if errors happen inside a nested group? Let's use an empty
+invllaid object for the test missing input errors:
 
+  >>> reg = VehicleRegistration(owner=VehicleOwner())
+
   >>> request = testing.TestRequest(form={
+  ...     'form.widgets.owner.firstName': u'',
+  ...     'form.widgets.owner.lastName': u'',
+  ...     'form.widgets.license': u'',
+  ...     'form.widgets.address': u'',
+  ...     'form.widgets.model': u'',
+  ...     'form.widgets.make': u'',
+  ...     'form.widgets.year': u'',
+  ...     'form.buttons.apply': u'Apply'
+  ...     })
+
+  >>> edit = RegistrationEditForm(reg, request)
+  >>> edit.update()
+  >>> data, errors = edit.extractData()
+  >>> print testing.render(edit, './/xmlns:i')
+  <i >There were some errors.</i>
+
+  >>> print testing.render(edit, './/xmlns:fieldset[1]/xmlns:ul')
+  <ul>
+    <li>
+    License:
+      <div class="error">Required input is missing.</div>
+    </li>
+    <li>
+    Address:
+      <div class="error">Required input is missing.</div>
+    </li>
+    <li>
+    Model:
+      <div class="error">Required input is missing.</div>
+    </li>
+    <li>
+    Make:
+      <div class="error">Required input is missing.</div>
+    </li>
+    <li>
+    Year:
+      <div class="error">Required input is missing.</div>
+    </li>
+  </ul>
+  <ul>
+    <li>
+    First Name:
+      <div class="error">Required input is missing.</div>
+    </li>
+    <li>
+    Last Name:
+      <div class="error">Required input is missing.</div>
+    </li>
+  </ul>
+
+
+Group instance in nested group
+------------------------------
+
+Let's also test if the Group class can handle group objects as instances:
+
+  >>> reg = VehicleRegistration(
+  ...               license=u'MA 40387',
+  ...               address=u'10 Main St, Maynard, MA',
+  ...               model=u'BMW',
+  ...               make=u'325',
+  ...               year=u'2005',
+  ...               owner=VehicleOwner(firstName=u'Stephan',
+  ...                                  lastName=u'Richter'))
+  >>> request = testing.TestRequest()
+
+  >>> edit = RegistrationEditForm(reg, request)
+  >>> vrg = VehicleRegistrationGroup(edit.context, request, edit)
+  >>> ownerGroup = OwnerGroup(edit.context, request, edit)
+
+Now build the group instance object chain:
+
+  >>> vrg.groups = (ownerGroup,)
+  >>> edit.groups = (vrg,)
+
+Also use refreshActions whihc is not needed but will make coverage this
+additional line of code in the update method:
+
+  >>> edit.refreshActions = True
+
+Update and render:
+
+  >>> edit.update()
+  >>> print edit.render()
+  <html xmlns="http://www.w3.org/1999/xhtml">
+    <body>
+      <form action=".">
+        <fieldset>
+          <legend>Registration</legend>
+        <div class="row">
+          <label for="form-widgets-license">License</label>
+          <input id="form-widgets-license"
+                 name="form.widgets.license"
+                 class="text-widget required textline-field"
+                 value="MA 40387" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-address">Address</label>
+          <input id="form-widgets-address"
+                 name="form.widgets.address"
+                 class="text-widget required textline-field"
+                 value="10 Main St, Maynard, MA" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-model">Model</label>
+          <input id="form-widgets-model" name="form.widgets.model"
+                 class="text-widget required textline-field"
+                 value="BMW" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-make">Make</label>
+          <input id="form-widgets-make" name="form.widgets.make"
+                 class="text-widget required textline-field"
+                 value="325" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-year">Year</label>
+          <input id="form-widgets-year" name="form.widgets.year"
+                 class="text-widget required textline-field"
+                 value="2005" type="text" />
+        </div>
+          <fieldset>
+          <legend>Owner</legend>
+        <div class="row">
+          <label for="form-widgets-owner-firstName">First Name</label>
+          <input id="form-widgets-owner-firstName"
+                 name="form.widgets.owner.firstName"
+                 class="text-widget required textline-field"
+                 value="Stephan" type="text" />
+        </div>
+        <div class="row">
+          <label for="form-widgets-owner-lastName">Last Name</label>
+          <input id="form-widgets-owner-lastName"
+                 name="form.widgets.owner.lastName"
+                 class="text-widget required textline-field"
+                 value="Richter" type="text" />
+        </div>
+        </fieldset>
+        </fieldset>
+        <div class="action">
+          <input id="form-buttons-apply" name="form.buttons.apply"
+                 class="submit-widget button-field" value="Apply"
+                 type="submit" />
+          </div>
+      </form>
+    </body>
+  </html>
+
+
+Now test the error handling if just one missing value is given in a group:
+
+  >>> request = testing.TestRequest(form={
   ...     'form.widgets.owner.firstName': u'Paul',
+  ...     'form.widgets.owner.lastName': u'',
   ...     'form.widgets.license': u'MA 4038765',
+  ...     'form.widgets.address': u'Berkeley',
   ...     'form.widgets.model': u'BMW',
   ...     'form.widgets.make': u'325',
   ...     'form.widgets.year': u'2005',
@@ -733,25 +975,24 @@
   ...     })
 
   >>> edit = RegistrationEditForm(reg, request)
+  >>> vrg = VehicleRegistrationGroup(edit.context, request, edit)
+  >>> ownerGroup = OwnerGroup(edit.context, request, edit)
+  >>> vrg.groups = (ownerGroup,)
+  >>> edit.groups = (vrg,)
+
   >>> edit.update()
   >>> data, errors = edit.extractData()
-  >>> " ".join(["%s %s"%(error.widget.label, error.render()) for error in errors])
-  u'Address \n  <div class="error">Required input is missing.</div>\n\n Last Name \n  <div class="error">Required input is missing.</div>\n\n'
-
   >>> print testing.render(edit, './/xmlns:i')
   <i >There were some errors.</i>
 
   >>> print testing.render(edit, './/xmlns:fieldset[1]/xmlns:ul')
-  <ul >
-     <li>
-       Address:
-       <div class="error">Required input is missing.</div>
-     </li>
+  <ul>
+    <li>
+    Last Name:
+      <div class="error">Required input is missing.</div>
+    </li>
   </ul>
 
-
-And that's it!
-
 Just check whether we fully support the interface:
 
   >>> from z3c.form import interfaces

Added: z3c.form/trunk/src/z3c/form/tests/simple_nested_groupedit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_nested_groupedit.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/tests/simple_nested_groupedit.pt	2009-04-03 04:08:51 UTC (rev 98805)
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:metal="http://xml.zope.org/namespaces/metal"
+      xmlns:tal="http://xml.zope.org/namespaces/tal">       
+  <body>
+    <i tal:condition="view/status" tal:content="view/status"/>
+    <ul tal:condition="view/widgets/errors"
+        metal:define-macro="errors">
+      <li tal:repeat="error view/widgets/errors">
+        <tal:block condition="error/widget">
+          <tal:block replace="error/widget/label" />:
+        </tal:block>
+        <tal:block replace="structure error/render" />
+      </li>
+    </ul>
+    <form action=".">
+      <metal:block metal:define-macro="rows">
+      <div class="row"
+           tal:repeat="widget view/widgets/values">
+        <b tal:condition="widget/error"
+           tal:content="structure widget/error/render" />
+        <label for=""
+               tal:attributes="for widget/id"
+               tal:content="widget/label" />
+        <input type="text" tal:replace="structure widget/render" />
+      </div>
+      </metal:block>
+      <fieldset tal:condition="view/groups|nothing"
+                tal:repeat="view view/groups">
+        <legend tal:condition="view/label"
+                tal:content="view/label">Label</legend>
+        <div metal:use-macro="template/macros/errors" />
+        <div metal:use-macro="template/macros/rows" />
+        <fieldset tal:condition="view/groups|nothing"
+                  tal:repeat="view view/groups">
+          <legend tal:condition="view/label"
+                  tal:content="view/label">Label</legend>
+          <div metal:use-macro="template/macros/errors" />
+          <div metal:use-macro="template/macros/rows" />
+        </fieldset>
+      </fieldset>
+      <div class="action"
+           tal:condition="view/actions|nothing"
+           tal:repeat="action view/actions/values">
+        <input type="submit" tal:replace="structure action/render"
+      /></div>
+    </form>
+  </body>
+</html>



More information about the Checkins mailing list