Skip to content

Commit

Permalink
- This Deform version requires colander version 0.7.3 or better.
Browse files Browse the repository at this point in the history
 
- The mapping and sequence item templates now correctly display errors
  with ``msg`` values that are lists.  Previously, a repr of a Python
  list was displayed when a widget had an error with a ``msg`` value
  that was a list; now multiple <p> nodes are inserted into the
  rendering, each <p> node containing an individual error message.
  (Note that this change requires colander 0.7.3).

- Provided better instructions for running the demo app and running
  the tests for the demo app in ``deformdemo/README.txt``.

- Try to prevent false test failures by injecting sleep statements in
  things that use ``browser.key_press``.

- Moved ``deformdemo/tests/test_demo.py`` to ``deformdemo/test.py`` as
  well as moving ``deformdemo/tests/selenium.py`` to
  ``deformdemo/selenium.py``.  Removed the ``deformdemo/tests``
  subdirectory.
  • Loading branch information
mcdonc committed Sep 2, 2010
1 parent e169392 commit 85d0b67
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 19 deletions.
20 changes: 19 additions & 1 deletion CHANGES.txt
Expand Up @@ -65,7 +65,7 @@ Features
Requirements
~~~~~~~~~~~~

- This Deform version requires ``colander`` version 0.7.2 or better.
- This Deform version requires ``colander`` version 0.7.3 or better.

Bug Fixes
~~~~~~~~~
Expand All @@ -92,6 +92,13 @@ Bug Fixes
field marker (e.g. ``deformField1``) in the same way it already
changed the value of ``id`` attributes which include a field marker.

- The mapping and sequence item templates now correctly display errors
with ``msg`` values that are lists. Previously, a repr of a Python
list was displayed when a widget had an error with a ``msg`` value
that was a list; now multiple <p> nodes are inserted into the
rendering, each <p> node containing an individual error message.
(Note that this change requires colander 0.7.3).

Backwards Incompatibilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -108,6 +115,17 @@ Backwards Incompatibilities
Internal
~~~~~~~~

- Provided better instructions for running the demo app and running
the tests for the demo app in ``deformdemo/README.txt``.

- Try to prevent false test failures by injecting sleep statements in
things that use ``browser.key_press``.

- Moved ``deformdemo/tests/test_demo.py`` to ``deformdemo/test.py`` as
well as moving ``deformdemo/tests/selenium.py`` to
``deformdemo/selenium.py``. Removed the ``deformdemo/tests``
subdirectory.

- The date input widget now uses JQueryUI's ``datepicker``
functionality rather than relying on JQuery Tools' ``date`` input.
The latter was broken for sequences, and the former works fine.
Expand Down
9 changes: 7 additions & 2 deletions deform/templates/mapping_item.pt
Expand Up @@ -12,8 +12,13 @@
id="req-${field.oid}">*</span>
</label>
<span tal:replace="structure field.serialize(cstruct)"/>

<p tal:condition="field.error and not field.widget.hidden"
id="error-${field.oid}"
class="${field.widget.error_class}">${field.error.msg}</p>
tal:define="errstr 'error-%s' % field.oid"
tal:repeat="msg field.error.messages()"
tal:attributes="id repeat.msg.index==0 and errstr or
('%s-%s' % (errstr, repeat.msg.index))"
class="${field.widget.error_class}">${msg}</p>

<!-- /mapping_item -->
</li>
9 changes: 7 additions & 2 deletions deform/templates/sequence_item.pt
Expand Up @@ -10,8 +10,13 @@
alt="Remove" onclick="javascript:$(this).parent().remove();"/>

<span tal:replace="structure field.serialize(cstruct)"/>

<p tal:condition="field.error and not field.widget.hidden"
id="error-${field.oid}"
class="${field.widget.error_class}">${field.error.msg}</p>
tal:define="errstr 'error-%s' % field.oid"
tal:repeat="msg field.error.messages()"
tal:attributes="id repeat.msg.index==0 and errstr or
('%s-%s' % (errstr, repeat.msg.index))"
class="${field.widget.error_class}">${msg}</p>

<!-- /sequence_item -->
</li>
88 changes: 76 additions & 12 deletions deformdemo/README.txt
Expand Up @@ -4,26 +4,90 @@ deformdemo
Software which demonstrates the operation of the ``deform`` form
generation package.

To use it, install deform with the "demo" extra; preferably from
within a virtualenv::
Running the Demo
----------------

bin/easy_install deform[demo]
- Create a virtualenv::

This will cause ``repoze.bfg``, ``Pygments``, ``Babel``, and a number
of other dependencies to be installed along with deform.
$ virtualenv2.6 --no-site-packages /path/to/my/venv

Get a checkout of deform:
Hereafter ``/path/to/my/venv`` will be referred to as $VENV in steps
below.

svn co http://svn.repoze.org/deform/trunk deform
- Install ``repoze.bfg``, ``pygments`` and ``Babel`` into your
virtualenv using ``easy_install``::

cd to the deform package:
$ $VENV/bin/easy_install repoze.bfg pygments Babel

cd deform
- Get a checkout of deform::

To start the demo, run:
$ svn co http://svn.repoze.org/deform/trunk deform

bin/paster serve deformdemo/demo.ini
- ``cd`` to the newly checked out deform package::

Visit http://localhost:8521 to see the demo.
$ cd deform

- Run ``setup.py develop`` using the virtualenv's ``python`` command::

$ $VENV/bin/python setup.py develop

- While your working directory is still ``deform``, start the demo
application::

$ $VENV/bin/paster serve deformdemo/demo.ini

- Visit http://localhost:8521 in a browser to see the demo.

Running the Demo's Selenium Tests
---------------------------------

The ``deformdemo`` application serves as a target for functional
testing during Deform's development. A suite of Selenium tests may be
run against a local instance of the demonstration application. It is
wise to run these tests before submitting a patch. Here's how:

- Make sure you have a Java interpreter installed.

- Start the ``deformdemo`` application as described above in "Running
the Demo".

- Download `Selenium RC <http://seleniumhq.org/download/>`.

- Unpack the resulting zipfile into a directory (perhaps
``$HOME/opt/selenium``).

- ``cd`` to the ``selenium-server-1.0.3`` subdirectory of the
directory to which you unpacked the zipfile.

- Run ``java -jar selenium-server.jar``. Success is defined as seeing
output on the console that ends like this::

01:49:06.105 INFO - Started SocketListener on 0.0.0.0:4444
01:49:06.105 INFO - Started org.openqa.jetty.jetty.Server@7d2a1e44

- Leave the terminal window in which the selenium server is now
running open, and open another terminal window.

- In the new terminal window, cd to the "deform" checkout directory
you created above in "Running the Demo"::

$ cd /path/to/my/deform/checkout

- Run the tests::

$ $VENV/bin/python deformdemo/test.py

``$VENV`` is defined as it was in "Running the Demo" above.

- You will (hopefully) see Firefox pop up in a two-windowed
arrangement, and it will begin to display in quick succession the
loading of pages in the bottom window and some test output in the
top window. The tests will run for a minute or two.

- Test success means that the console window on which you ran
``test.py`` shows a bunch of dots, a test summary, then ``OK``. If
it shows a traceback, ``FAILED``, or anything other than a straight
line of dots, it means there was an error.

- Fix any errors by modifying your code or by modifying the tests to
expect the changes you've made.
44 changes: 44 additions & 0 deletions deformdemo/app.py
Expand Up @@ -911,6 +911,50 @@ def validator(form, value):
form = deform.Form(schema, buttons=('submit',))
return self.render_form(form)

@bfg_view(renderer='templates/form.pt', name='multiple_error_messages_map')
@demonstrate('Multiple Error Messages For a Single Widget (Mapping)')
def multiple_error_messages_mapping(self):
def v1(node, value):
msg = _('Error ${num}', mapping=dict(num=1))
raise colander.Invalid(node, msg)
def v2(node, value):
msg = _('Error ${num}', mapping=dict(num=2))
raise colander.Invalid(node, msg)
def v3(node, value):
msg = _('Error ${num}', mapping=dict(num=3))
raise colander.Invalid(node, msg)
class Schema(colander.Schema):
field = colander.SchemaNode(
colander.String(),
title="Fill in a value and submit to see multiple errors",
validator = colander.All(v1, v2, v3))
schema = Schema()
form = deform.Form(schema, buttons=('submit',))
return self.render_form(form)

@bfg_view(renderer='templates/form.pt', name='multiple_error_messages_seq')
@demonstrate('Multiple Error Messages For a Single Widget (Sequence)')
def multiple_error_messages_seq(self):
def v1(node, value):
msg = _('Error ${num}', mapping=dict(num=1))
raise colander.Invalid(node, msg)
def v2(node, value):
msg = _('Error ${num}', mapping=dict(num=2))
raise colander.Invalid(node, msg)
def v3(node, value):
msg = _('Error ${num}', mapping=dict(num=3))
raise colander.Invalid(node, msg)
class Sequence(colander.SequenceSchema):
field = colander.SchemaNode(
colander.String(),
title="Fill in a value and submit to see multiple errors",
validator = colander.All(v1, v2, v3))
class Schema(colander.Schema):
fields = Sequence()
schema = Schema()
form = deform.Form(schema, buttons=('submit',))
return self.render_form(form)

@bfg_view(renderer='templates/form.pt', name="multiple_forms")
@demonstrate('Multiple Forms on the Same Page')
def multiple_forms(self):
Expand Down
File renamed without changes.
41 changes: 40 additions & 1 deletion deformdemo/tests/test_demo.py → deformdemo/test.py
Expand Up @@ -5,7 +5,7 @@
# to run:
# console 1: java -jar selenium-server.jar
# console 2: start the deform demo server (paster serve deformdemo.ini)
# console 3: python test_demo.py
# console 3: python test.py

# Instead of using -browserSessionReuse as an arg to
# selenium-server.jar to speed up tests, we rely on
Expand Down Expand Up @@ -188,26 +188,32 @@ def test_render_default(self):
self.failIf(browser.is_element_present('css=.errorMsgLbl'))

def test_type_bad_input(self):
import time
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
browser.key_press('deformField1', 'a')
time.sleep(.005)
browser.focus('deformField1-confirm')
browser.key_press('deformField1-confirm', 'a')
time.sleep(.005)
self.failUnless(
browser.get_value('deformField1') in ('', '###-##-####'))
self.failUnless(
browser.get_value('deformField1-confirm') in ('', '###-##-####'))

def test_submit_success(self):
import time
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
for key in '140118866':
browser.key_press('deformField1', key)
time.sleep(.005)
browser.focus('deformField1-confirm')
for key in '140118866':
browser.key_press('deformField1-confirm', key)
time.sleep(.005)
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('css=#captured'),
Expand Down Expand Up @@ -1691,13 +1697,15 @@ def test_submit_two_unfilled(self):
self.assertEqual(captured, 'None')

def test_submit_one_filled(self):
import time
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.click('deformField1-seqAdd')
added = 'dom=document.forms[0].text'
browser.focus(added)
for key in '140118866':
browser.key_press(added, key)
time.sleep(.005)
browser.click("submit")
browser.wait_for_page_to_load("30000")
self.failIf(browser.is_element_present('css=.errorMsgLbl'))
Expand Down Expand Up @@ -2280,31 +2288,62 @@ def test_render_default(self):
self.failIf(browser.is_element_present('css=.errorMsgLbl'))

def test_type_bad_input(self):
import time
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
browser.key_press('deformField1', 'a')
time.sleep(.005)
browser.focus('deformField2')
browser.key_press('deformField2', 'a')
time.sleep(.005)
self.failUnless(
browser.get_value('deformField1') in ('', '___-__-____'))
self.failUnless(
browser.get_value('deformField2') in ('', '__/__/____'))

def test_submit_success(self):
import time
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
for key in '140118866':
browser.key_press('deformField1', key)
time.sleep(.005)
browser.focus('deformField2')
for key in '10102010':
browser.key_press('deformField2', key)
time.sleep(.005)
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('css=#captured'),
u"{'date': u'10/10/2010', 'ssn': u'140-11-8866'}")

class MultipleErrorMessagesInMappingTest(unittest.TestCase):
url = "/multiple_error_messages_map/"
def test_it(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.type('deformField1', 'whatever')
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('error-deformField1'), 'Error 1')
self.assertEqual(browser.get_text('error-deformField1-1'), 'Error 2')
self.assertEqual(browser.get_text('error-deformField1-2'), 'Error 3')

class MultipleErrorMessagesInSequenceTest(unittest.TestCase):
url = "/multiple_error_messages_seq/"
def test_it(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.click('deformField1-seqAdd')
browser.type('dom=document.forms[0].field', 'whatever')
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('error-deformField3'), 'Error 1')
self.assertEqual(browser.get_text('error-deformField3-1'), 'Error 2')
self.assertEqual(browser.get_text('error-deformField3-2'), 'Error 3')

if __name__ == '__main__':
setUpModule()
try:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -23,7 +23,7 @@
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()

requires = [
'colander>=0.7.2', # widget-arg providing
'colander>=0.7.3', # Invalid.messages()-providing
'chameleon>=1.2.3', # debug arg
'translationstring',
'peppercorn',
Expand Down

0 comments on commit 85d0b67

Please sign in to comment.