Skip to content

Commit

Permalink
Fixed #9200 -- Added new form wizard to formtools based on class base…
Browse files Browse the repository at this point in the history
…d views. Many thanks to Stephan Jäkel, ddurham and ElliottM for their work.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16307 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
jezdez committed Jun 1, 2011
1 parent 1a951fa commit 632dfa2
Show file tree
Hide file tree
Showing 39 changed files with 2,594 additions and 344 deletions.
126 changes: 76 additions & 50 deletions django/contrib/formtools/tests/__init__.py
Original file line number Original file line Diff line number Diff line change
@@ -1,13 +1,19 @@
import os import os
import re
import warnings import warnings


from django import forms, http from django import http
from django.conf import settings from django.conf import settings
from django.contrib.formtools import preview, wizard, utils from django.contrib.formtools import preview, wizard, utils
from django.test import TestCase from django.test import TestCase
from django.test.utils import get_warnings_state, restore_warnings_state from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import unittest from django.utils import unittest


from django.contrib.formtools.wizard.tests import *
from django.contrib.formtools.tests.forms import *

warnings.filterwarnings('ignore', category=PendingDeprecationWarning,
module='django.contrib.formtools.wizard')


success_string = "Done was called!" success_string = "Done was called!"


Expand All @@ -24,12 +30,6 @@ def done(self, request, cleaned_data):
return http.HttpResponse(success_string) return http.HttpResponse(success_string)




class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
bool1 = forms.BooleanField(required=False)


class PreviewTests(TestCase): class PreviewTests(TestCase):
urls = 'django.contrib.formtools.tests.urls' urls = 'django.contrib.formtools.tests.urls'


Expand Down Expand Up @@ -63,7 +63,7 @@ def test_form_get(self):
is created to manage the stage. is created to manage the stage.
""" """
response = self.client.get('/test1/') response = self.client.get('/preview/')
stage = self.input % 1 stage = self.input % 1
self.assertContains(response, stage, 1) self.assertContains(response, stage, 1)
self.assertEqual(response.context['custom_context'], True) self.assertEqual(response.context['custom_context'], True)
Expand All @@ -81,7 +81,7 @@ def test_form_preview(self):
# Pass strings for form submittal and add stage variable to # Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form. # show we previously saw first stage of the form.
self.test_data.update({'stage': 1}) self.test_data.update({'stage': 1})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
# Check to confirm stage is set to 2 in output form. # Check to confirm stage is set to 2 in output form.
stage = self.input % 2 stage = self.input % 2
self.assertContains(response, stage, 1) self.assertContains(response, stage, 1)
Expand All @@ -99,11 +99,11 @@ def test_form_submit(self):
# Pass strings for form submittal and add stage variable to # Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form. # show we previously saw first stage of the form.
self.test_data.update({'stage':2}) self.test_data.update({'stage':2})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertNotEqual(response.content, success_string) self.assertNotEqual(response.content, success_string)
hash = self.preview.security_hash(None, TestForm(self.test_data)) hash = self.preview.security_hash(None, TestForm(self.test_data))
self.test_data.update({'hash': hash}) self.test_data.update({'hash': hash})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.content, success_string) self.assertEqual(response.content, success_string)


def test_bool_submit(self): def test_bool_submit(self):
Expand All @@ -122,7 +122,7 @@ def test_bool_submit(self):
self.test_data.update({'stage':2}) self.test_data.update({'stage':2})
hash = self.preview.security_hash(None, TestForm(self.test_data)) hash = self.preview.security_hash(None, TestForm(self.test_data))
self.test_data.update({'hash':hash, 'bool1':u'False'}) self.test_data.update({'hash':hash, 'bool1':u'False'})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.content, success_string) self.assertEqual(response.content, success_string)


def test_form_submit_good_hash(self): def test_form_submit_good_hash(self):
Expand All @@ -133,11 +133,11 @@ def test_form_submit_good_hash(self):
# Pass strings for form submittal and add stage variable to # Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form. # show we previously saw first stage of the form.
self.test_data.update({'stage':2}) self.test_data.update({'stage':2})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertNotEqual(response.content, success_string) self.assertNotEqual(response.content, success_string)
hash = utils.form_hmac(TestForm(self.test_data)) hash = utils.form_hmac(TestForm(self.test_data))
self.test_data.update({'hash': hash}) self.test_data.update({'hash': hash})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.content, success_string) self.assertEqual(response.content, success_string)




Expand All @@ -149,12 +149,12 @@ def test_form_submit_bad_hash(self):
# Pass strings for form submittal and add stage variable to # Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form. # show we previously saw first stage of the form.
self.test_data.update({'stage':2}) self.test_data.update({'stage':2})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertNotEqual(response.content, success_string) self.assertNotEqual(response.content, success_string)
hash = utils.form_hmac(TestForm(self.test_data)) + "bad" hash = utils.form_hmac(TestForm(self.test_data)) + "bad"
self.test_data.update({'hash': hash}) self.test_data.update({'hash': hash})
response = self.client.post('/test1/', self.test_data) response = self.client.post('/previewpreview/', self.test_data)
self.assertNotEqual(response.content, success_string) self.assertNotEqual(response.content, success_string)




Expand Down Expand Up @@ -220,38 +220,14 @@ def test_empty_permitted(self):
self.assertEqual(hash1, hash2) self.assertEqual(hash1, hash2)




class HashTestForm(forms.Form):
name = forms.CharField()
bio = forms.CharField()


class HashTestBlankForm(forms.Form):
name = forms.CharField(required=False)
bio = forms.CharField(required=False)

# #
# FormWizard tests # FormWizard tests
# #



class TestWizardClass(wizard.FormWizard):
class WizardPageOneForm(forms.Form):
field = forms.CharField()


class WizardPageTwoForm(forms.Form):
field = forms.CharField()

class WizardPageTwoAlternativeForm(forms.Form):
field = forms.CharField()

class WizardPageThreeForm(forms.Form):
field = forms.CharField()


class WizardClass(wizard.FormWizard):


def get_template(self, step): def get_template(self, step):
return 'formwizard/wizard.html' return 'forms/wizard.html'


def done(self, request, cleaned_data): def done(self, request, cleaned_data):
return http.HttpResponse(success_string) return http.HttpResponse(success_string)
Expand All @@ -269,6 +245,20 @@ def __init__(self, POST=None):


class WizardTests(TestCase): class WizardTests(TestCase):
urls = 'django.contrib.formtools.tests.urls' urls = 'django.contrib.formtools.tests.urls'
input_re = re.compile('name="([^"]+)" value="([^"]+)"')
wizard_step_data = (
{
'0-name': 'Pony',
'0-thirsty': '2',
},
{
'1-address1': '123 Main St',
'1-address2': 'Djangoland',
},
{
'2-random_crap': 'blah blah',
}
)


def setUp(self): def setUp(self):
self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
Expand All @@ -290,21 +280,21 @@ def test_step_starts_at_zero(self):
""" """
step should be zero for the first form step should be zero for the first form
""" """
response = self.client.get('/wizard/') response = self.client.get('/wizard1/')
self.assertEqual(0, response.context['step0']) self.assertEqual(0, response.context['step0'])


def test_step_increments(self): def test_step_increments(self):
""" """
step should be incremented when we go to the next page step should be incremented when we go to the next page
""" """
response = self.client.post('/wizard/', {"0-field":"test", "wizard_step":"0"}) response = self.client.post('/wizard1/', {"0-field":"test", "wizard_step":"0"})
self.assertEqual(1, response.context['step0']) self.assertEqual(1, response.context['step0'])


def test_bad_hash(self): def test_bad_hash(self):
""" """
Form should not advance if the hash is missing or bad Form should not advance if the hash is missing or bad
""" """
response = self.client.post('/wizard/', response = self.client.post('/wizard1/',
{"0-field":"test", {"0-field":"test",
"1-field":"test2", "1-field":"test2",
"wizard_step": "1"}) "wizard_step": "1"})
Expand All @@ -319,7 +309,7 @@ def test_good_hash(self):
"1-field": "test2", "1-field": "test2",
"hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c", "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
"wizard_step": "1"} "wizard_step": "1"}
response = self.client.post('/wizard/', data) response = self.client.post('/wizard1/', data)
self.assertEqual(2, response.context['step0']) self.assertEqual(2, response.context['step0'])


def test_11726(self): def test_11726(self):
Expand All @@ -330,7 +320,7 @@ def test_11726(self):
reached = [False] reached = [False]
that = self that = self


class WizardWithProcessStep(WizardClass): class WizardWithProcessStep(TestWizardClass):
def process_step(self, request, form, step): def process_step(self, request, form, step):
if step == 0: if step == 0:
if self.num_steps() < 2: if self.num_steps() < 2:
Expand Down Expand Up @@ -362,7 +352,7 @@ def test_14498(self):
reached = [False] reached = [False]
that = self that = self


class WizardWithProcessStep(WizardClass): class WizardWithProcessStep(TestWizardClass):
def process_step(self, request, form, step): def process_step(self, request, form, step):
that.assertTrue(hasattr(form, 'cleaned_data')) that.assertTrue(hasattr(form, 'cleaned_data'))
reached[0] = True reached[0] = True
Expand All @@ -386,7 +376,7 @@ def test_14576(self):
reached = [False] reached = [False]
that = self that = self


class Wizard(WizardClass): class Wizard(TestWizardClass):
def done(self, request, form_list): def done(self, request, form_list):
reached[0] = True reached[0] = True
that.assertTrue(len(form_list) == 2) that.assertTrue(len(form_list) == 2)
Expand All @@ -409,7 +399,7 @@ def test_15075(self):
reached = [False] reached = [False]
that = self that = self


class WizardWithProcessStep(WizardClass): class WizardWithProcessStep(TestWizardClass):
def process_step(self, request, form, step): def process_step(self, request, form, step):
if step == 0: if step == 0:
self.form_list[1] = WizardPageTwoAlternativeForm self.form_list[1] = WizardPageTwoAlternativeForm
Expand All @@ -426,3 +416,39 @@ def process_step(self, request, form, step):
"wizard_step": "1"} "wizard_step": "1"}
wizard(DummyRequest(POST=data)) wizard(DummyRequest(POST=data))
self.assertTrue(reached[0]) self.assertTrue(reached[0])

def grab_field_data(self, response):
"""
Pull the appropriate field data from the context to pass to the next wizard step
"""
previous_fields = response.context['previous_fields']
fields = {'wizard_step': response.context['step0']}

def grab(m):
fields[m.group(1)] = m.group(2)
return ''

self.input_re.sub(grab, previous_fields)
return fields

def check_wizard_step(self, response, step_no):
"""
Helper function to test each step of the wizard
- Make sure the call succeeded
- Make sure response is the proper step number
- return the result from the post for the next step
"""
step_count = len(self.wizard_step_data)

self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Step %d of %d' % (step_no, step_count))

data = self.grab_field_data(response)
data.update(self.wizard_step_data[step_no - 1])

return self.client.post('/wizard2/', data)

def test_9473(self):
response = self.client.get('/wizard2/')
for step_no in range(1, len(self.wizard_step_data) + 1):
response = self.check_wizard_step(response, step_no)
43 changes: 43 additions & 0 deletions django/contrib/formtools/tests/forms.py
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,43 @@
from django import forms
from django.contrib.formtools.wizard import FormWizard
from django.http import HttpResponse

class Page1(forms.Form):
name = forms.CharField(max_length=100)
thirsty = forms.NullBooleanField()

class Page2(forms.Form):
address1 = forms.CharField(max_length=100)
address2 = forms.CharField(max_length=100)

class Page3(forms.Form):
random_crap = forms.CharField(max_length=100)

class ContactWizard(FormWizard):
def done(self, request, form_list):
return HttpResponse("")

class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
bool1 = forms.BooleanField(required=False)

class HashTestForm(forms.Form):
name = forms.CharField()
bio = forms.CharField()

class HashTestBlankForm(forms.Form):
name = forms.CharField(required=False)
bio = forms.CharField(required=False)

class WizardPageOneForm(forms.Form):
field = forms.CharField()

class WizardPageTwoForm(forms.Form):
field = forms.CharField()

class WizardPageTwoAlternativeForm(forms.Form):
field = forms.CharField()

class WizardPageThreeForm(forms.Form):
field = forms.CharField()
Original file line number Original file line Diff line number Diff line change
@@ -1,13 +1,13 @@
<html> <html>
<body> <body>
<p>Step {{ step }} of {{ step_count }}</p> <p>Step {{ step }} of {{ step_count }}</p>
<form action="." method="post"> <form action="." method="post">
<table> <table>
{{ form }} {{ form }}
</table> </table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
{{ previous_fields|safe }} {{ previous_fields|safe }}
<input type="submit"> <input type="submit">
</form> </form>
</body> </body>
</html> </html>

This file was deleted.

15 changes: 9 additions & 6 deletions django/contrib/formtools/tests/urls.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
""" """


from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from django.contrib.formtools.tests import * from django.contrib.formtools.tests import TestFormPreview, TestWizardClass

from forms import (ContactWizard, Page1, Page2, Page3, TestForm,
WizardPageOneForm, WizardPageTwoForm, WizardPageThreeForm)


urlpatterns = patterns('', urlpatterns = patterns('',
(r'^test1/', TestFormPreview(TestForm)), url(r'^preview/', TestFormPreview(TestForm)),
(r'^wizard/$', WizardClass([WizardPageOneForm, url(r'^wizard1/$', TestWizardClass(
WizardPageTwoForm, [WizardPageOneForm, WizardPageTwoForm, WizardPageThreeForm])),
WizardPageThreeForm])), url(r'^wizard2/$', ContactWizard([Page1, Page2, Page3])),
) )
1 change: 1 addition & 0 deletions django/contrib/formtools/wizard/__init__.py
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1 @@
from django.contrib.formtools.wizard.legacy import FormWizard
7 changes: 7 additions & 0 deletions django/contrib/formtools/wizard/forms.py
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,7 @@
from django import forms

class ManagementForm(forms.Form):
"""
``ManagementForm`` is used to keep track of the current wizard step.
"""
current_step = forms.CharField(widget=forms.HiddenInput)
Loading

0 comments on commit 632dfa2

Please sign in to comment.