Luke Plant avatar Luke Plant committed c3d2862 Merge

Merged from default

Comments (0)

Files changed (15)

 Tests
 =====
 
-./manage.py test --settings=cciw.settings_tests cciwmain officers bookings
+./manage.py test --settings=cciw.settings_tests cciw

cciw/bookings/tests.py

 from django.core import mail
 from django.core.urlresolvers import reverse
 from django.test import TestCase
-from twill import commands as tc
 import xlrd
 
 from cciw.bookings.management.commands.expire_bookings import Command as ExpireBookingsCommand
 from cciw.officers.tests.references import OFFICER_USERNAME, OFFICER_PASSWORD, BOOKING_SEC_USERNAME, BOOKING_SEC_PASSWORD, BOOKING_SEC
 from cciw.sitecontent.models import HtmlChunk
 from cciw.utils.spreadsheet import ExcelFormatter
-from cciw.utils.tests.twillhelpers import TwillMixin, make_django_url
+from cciw.utils.tests.webtest import WebTestBase
 
 
 DISABLED_BOOK_NOW_BTN = "id_book_now_btn\" disabled>"
             self.assertNotEqual(acc.bookings.all()[0].first_name, "A New Name")
 
 
-class TestEditPlaceAdmin(CreatePlaceMixin, TwillMixin, TestCase):
+class TestEditPlaceAdmin(CreatePlaceMixin, WebTestBase):
 
     fixtures = ['basic.json', 'officers_users.json']
 
         acc = self.get_account()
         b = acc.bookings.all()[0]
 
-        self._twill_login(BOOKING_SEC)
-        tc.go(make_django_url("admin:bookings_booking_change", b.id))
-        tc.code(200)
-        tc.fv('booking_form', 'state', str(BOOKING_APPROVED))
-        tc.submit('save')
-        tc.find("An email has been sent")
+        self.webtest_officer_login(BOOKING_SEC)
+        response = self.get("admin:bookings_booking_change", b.id)
+        self.code(response, 200)
+        response = self.fill(response.forms['booking_form'],
+                             {'state': BOOKING_APPROVED}
+                             ).submit().follow()
+        self.assertContains(response, "An email has been sent")
         self.assertEqual(len(mail.outbox), 1)
 
-    def fill(self, form_id, fields):
-        for k, v in fields.items():
-            tc.fv(form_id, k, unicode(v).encode('utf-8'))
-
     def test_create(self):
-        self._twill_login(BOOKING_SEC)
-        tc.go(make_django_url("admin:bookings_bookingaccount_add"))
-        self.fill('bookingaccount_form', {
-                'name': 'Joe',
-                'email': self.email,
-                'address': '123',
-                'post_code': 'XYZ',
-                })
-        tc.submit()
-        tc.code(200)
+        self.webtest_officer_login(BOOKING_SEC)
+        response = self.get("admin:bookings_bookingaccount_add")
+        response = self.fill(response.forms['bookingaccount_form'],
+                             {'name': 'Joe',
+                              'email': self.email,
+                              'address': '123',
+                              'post_code': 'XYZ',
+                              }).submit().follow()
+        self.code(response, 200)
         account = BookingAccount.objects.get(email=self.email)
 
-        tc.go(make_django_url("admin:bookings_booking_add"))
-        tc.code(200)
+        response = self.get("admin:bookings_booking_add")
+        self.code(response, 200)
         fields = self.place_details.copy()
         fields.update({
                 'account': account.id,
                 'state': BOOKING_BOOKED,
                 'amount_due': '130.00',
                 })
-
-        # Ensure we can edit hidden 'account' field:
-        tc.browser.get_form('booking_form').set_all_readonly(False)
-        self.fill('booking_form', fields)
-        tc.submit('save')
-        tc.find('Select booking')
-        tc.find('A confirmation email has been sent')
+        form = response.forms['booking_form']
+        # Hack needed to cope with autocomplete_light widget
+        form.fields['account'][0].options.append((str(account.id), False))
+        response = self.fill(
+            form, fields).submit('save').follow()
+        self.assertContains(response, 'Select booking')
+        self.assertContains(response, 'A confirmation email has been sent')
 
 
 class TestListBookings(CreatePlaceMixin, TestCase):

cciw/cciwmain/tests/members.py

 from django.core import mail
 from django.core.urlresolvers import reverse
 from django.test import TestCase
-from twill import commands as tc
 
 from cciw.forums.models import Member, Message
 from cciw.cciwmain.tests.client import CciwClient, RequestFactory
 from cciw.cciwmain.tests.mailhelpers import read_email_url
 from cciw.cciwmain.tests.utils import init_query_caches, FuzzyInt
-from cciw.utils.tests.twillhelpers import TwillMixin, make_twill_url
+from cciw.utils.tests.webtest import WebTestBase
 
 
 # created by fixture
         _remove_member_icons(TEST_MEMBER_USERNAME)
 
 
-class MemberSignup(TwillMixin, TestCase):
+class MemberSignup(WebTestBase):
     fixtures=['basic.json','test_members.json']
 
     def setUp(self):
     def test_signup_complete_correct(self):
         self._test_signup_send_email_part1()
         url, path, querydata = self._read_signup_email(mail.outbox[0])
-        local_url = make_twill_url(url)
-        tc.go(local_url)
-        tc.notfind("Error")
-        tc.fv('1', 'user_name', NEW_MEMBER_USERNAME)
-        tc.fv('1', 'password1', NEW_MEMBER_PASSWORD)
-        tc.fv('1', 'password2', NEW_MEMBER_PASSWORD)
-        tc.submit()
-        self._twill_assert_finished()
+        response = self.get(url)
+        self.assertNotContains(response, "Error")
+        response = self.fill(response.forms[0],
+                             {'user_name': NEW_MEMBER_USERNAME,
+                              'password1': NEW_MEMBER_PASSWORD,
+                              'password2': NEW_MEMBER_PASSWORD}).submit()
+        self.assert_finished(response)
 
-    def _twill_assert_finished(self):
-        tc.find("Finished!")
-        tc.find("Your account has been created")
+    def assert_finished(self, response):
+        self.assertContains(response, "Finished!")
+        self.assertContains(response, "Your account has been created")
 
     def test_signup_complete_bad_password(self):
         self._test_signup_send_email_part1()
         url, path, querydata = self._read_signup_email(mail.outbox[0])
-        tc.go(make_twill_url(url))
-        tc.notfind("Error")
-        tc.fv('1', 'user_name', NEW_MEMBER_USERNAME)
-        tc.fv('1', 'password1', NEW_MEMBER_PASSWORD)
-        tc.fv('1', 'password2', NEW_MEMBER_PASSWORD + "x")
-        tc.submit()
-        tc.find("Error")
+        response = self.get(url)
+        self.assertNotContains(response, "Error")
+        response = self.fill(response.forms[0],
+                             {'user_name': NEW_MEMBER_USERNAME,
+                              'password1': NEW_MEMBER_PASSWORD,
+                              'password2': NEW_MEMBER_PASSWORD + "x"}).submit()
+        self.assertContains(response, "Error")
 
         # Correct it, without setting user_name
-        tc.fv('1', 'password1', NEW_MEMBER_PASSWORD)
-        tc.fv('1', 'password2', NEW_MEMBER_PASSWORD)
+        response = self.fill(response.forms[0],
+                             {'password1': NEW_MEMBER_PASSWORD,
+                              'password2': NEW_MEMBER_PASSWORD}).submit()
 
-        # try again
-        tc.submit()
-        self._twill_assert_finished()
+        self.assert_finished(response)
 
     def test_signup_complete_bad_username(self):
         self._test_signup_send_email_part1()
         url, path, querydata = self._read_signup_email(mail.outbox[0])
-        tc.go(make_twill_url(url))
-        tc.notfind("Error")
-        tc.fv('1', 'user_name', TEST_MEMBER_USERNAME)
-        tc.fv('1', 'password1', NEW_MEMBER_PASSWORD)
-        tc.fv('1', 'password2', NEW_MEMBER_PASSWORD)
-        tc.submit()
-        tc.find("Error")
+        response = self.get(url)
+        self.assertNotContains(response, "Error")
+        response = self.fill(response.forms[0],
+                             {'user_name': TEST_MEMBER_USERNAME,
+                              'password1': NEW_MEMBER_PASSWORD,
+                              'password2': NEW_MEMBER_PASSWORD}).submit()
+        self.assertContains(response, "Error")
 
     def test_signup_incorrect_hash(self):
         self._test_signup_send_email_part1()
         url, path, querydata = self._read_signup_email(mail.outbox[0])
         querydata['h'] = querydata['h'] + "x"
         response = self._follow_email_url(path, querydata)
-        self.assertTrue("Error" in response.content, "Error should be reported if the hash is incorrect")
+        self.assertIn("Error", response.content, "Error should be reported if the hash is incorrect")
 
     def test_signup_incorrect_email(self):
         self._test_signup_send_email_part1()
         url, path, querydata = self._read_signup_email(mail.outbox[0])
         querydata['email'] = querydata['email'] + "x"
         response = self._follow_email_url(path, querydata)
-        self.assertTrue("Error" in response.content, "Error should be reported if the email is incorrect")
+        self.assertIn("Error", response.content, "Error should be reported if the email is incorrect")
 
 
 class MemberLists(TestCase):

cciw/officers/tests/applicationform.py

 from django.core import mail
 from django.core.urlresolvers import reverse
 from django.test import TestCase
-from twill import commands as tc
 
 from cciw.cciwmain.tests.mailhelpers import read_email_url
 from cciw.cciwmain.models import Camp
 from cciw.officers.models import Application
 from cciw.officers.applications import application_difference
 from cciw.officers.tests.references import OFFICER, LEADER
-from cciw.utils.tests.twillhelpers import TwillMixin, make_django_url
+from cciw.utils.tests.webtest import WebTestBase
 
-class ApplicationFormView(TwillMixin, TestCase):
+class ApplicationFormView(WebTestBase):
     fixtures = ['basic.json', 'officers_users.json']
 
     def _application_edit_url(self, app_id):
-        return make_django_url('admin:officers_application_change', app_id)
+        return reverse('admin:officers_application_change', args=[app_id])
 
     def setUp(self):
         # Make sure second camp has end date in future, otherwise we won't be able to
         a.save()
         return a
 
-    def _finish_application_form(self):
+    def _finish_application_form(self, response):
         # A full set of values that pass validation.
-        tc.formvalue('1', 'full_name', 'x')
-        tc.formvalue('1', 'full_maiden_name', 'x')
-        tc.formvalue('1', 'birth_date', '2000-01-01')
-        tc.formvalue('1', 'birth_place', 'x')
-        tc.formvalue('1', 'address_firstline', 'x')
-        tc.formvalue('1', 'address_town', 'x')
-        tc.formvalue('1', 'address_county', 'x')
-        tc.formvalue('1', 'address_postcode', 'x')
-        tc.formvalue('1', 'address_country', 'x')
-        tc.formvalue('1', 'address_tel', 'x')
-        tc.formvalue('1', 'address_mobile', 'x')
-        tc.formvalue('1', 'address_since', '2008/01')
-        tc.formvalue('1', 'address_email', 'foo@foo.com')
-        tc.formvalue('1', 'christian_experience', 'x')
-        tc.formvalue('1', 'youth_experience', 'x')
-        tc.formvalue('1', 'youth_work_declined_details', 'x')
-        tc.formvalue('1', 'illness_details', 'x')
-        tc.formvalue('1', 'employer1_name', 'x')
-        tc.formvalue('1', 'employer1_from', '2008/01')
-        tc.formvalue('1', 'employer1_to', '2008/01')
-        tc.formvalue('1', 'employer1_job', 'x')
-        tc.formvalue('1', 'employer1_leaving', 'x')
-        tc.formvalue('1', 'employer2_name', 'x')
-        tc.formvalue('1', 'employer2_from', '2008/01')
-        tc.formvalue('1', 'employer2_to', '2008/01')
-        tc.formvalue('1', 'employer2_job', 'x')
-        tc.formvalue('1', 'employer2_leaving', 'x')
-        tc.formvalue('1', 'referee1_name', 'x')
-        tc.formvalue('1', 'referee1_address', 'x')
-        tc.formvalue('1', 'referee1_tel', 'x')
-        tc.formvalue('1', 'referee1_mobile', 'x')
-        tc.formvalue('1', 'referee1_email', 'foo1@foo1.com')
-        tc.formvalue('1', 'referee2_name', 'x')
-        tc.formvalue('1', 'referee2_address', 'x')
-        tc.formvalue('1', 'referee2_tel', 'x')
-        tc.formvalue('1', 'referee2_mobile', 'x')
-        tc.formvalue('1', 'referee2_email', 'foo2@foo2.com')
-        tc.formvalue('1', 'crime_details', 'x')
-        tc.formvalue('1', 'court_details', 'x')
-        tc.formvalue('1', 'concern_details', 'x')
-        tc.formvalue('1', 'youth_work_declined', '2')
-        tc.formvalue('1', 'relevant_illness', '2')
-        tc.formvalue('1', 'crime_declaration', '2')
-        tc.formvalue('1', 'court_declaration', '2')
-        tc.formvalue('1', 'concern_declaration', '2')
-        tc.formvalue('1', 'allegation_declaration', '2')
-        tc.formvalue('1', 'crb_check_consent', '2')
-        tc.formvalue('1', 'finished', 'on')
+        return self.fill(response.forms['application_form'],
+                         {'full_name': 'x',
+                          'full_maiden_name': 'x',
+                          'birth_date': '2000-01-01',
+                          'birth_place': 'x',
+                          'address_firstline': 'x',
+                          'address_town': 'x',
+                          'address_county': 'x',
+                          'address_postcode': 'x',
+                          'address_country': 'x',
+                          'address_tel': 'x',
+                          'address_mobile': 'x',
+                          'address_since': '2008/01',
+                          'address_email': 'foo@foo.com',
+                          'christian_experience': 'x',
+                          'youth_experience': 'x',
+                          'youth_work_declined_details': 'x',
+                          'illness_details': 'x',
+                          'employer1_name': 'x',
+                          'employer1_from': '2008/01',
+                          'employer1_to': '2008/01',
+                          'employer1_job': 'x',
+                          'employer1_leaving': 'x',
+                          'employer2_name': 'x',
+                          'employer2_from': '2008/01',
+                          'employer2_to': '2008/01',
+                          'employer2_job': 'x',
+                          'employer2_leaving': 'x',
+                          'referee1_name': 'x',
+                          'referee1_address': 'x',
+                          'referee1_tel': 'x',
+                          'referee1_mobile': 'x',
+                          'referee1_email': 'foo1@foo1.com',
+                          'referee2_name': 'x',
+                          'referee2_address': 'x',
+                          'referee2_tel': 'x',
+                          'referee2_mobile': 'x',
+                          'referee2_email': 'foo2@foo2.com',
+                          'crime_details': 'x',
+                          'court_details': 'x',
+                          'concern_details': 'x',
+                          'youth_work_declined': '2',
+                          'relevant_illness': '2',
+                          'crime_declaration': '2',
+                          'court_declaration': '2',
+                          'concern_declaration': '2',
+                          'allegation_declaration': '2',
+                          'crb_check_consent': '2',
+                          'finished': 'on',
+                          })
 
     def _get_application_form_emails(self):
         return [e for e in mail.outbox if "CCIW application form" in e.subject]
         return [e for e in mail.outbox if "E-mail change" in e.subject]
 
     def test_change_application(self):
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         a = self._add_application()
         u = User.objects.get(username=OFFICER[0])
         self.assertEqual(u.application_set.count(), 1)
-        tc.go(self._application_edit_url(a.id))
-        tc.code(200)
-        tc.find('Save and continue editing')
-        tc.notfind('Save and add another')
-        tc.formvalue('1', 'full_name', 'Test full name')
-        tc.submit('_save')
-        tc.url(reverse("cciw.officers.views.applications"))
+        response = self.get(self._application_edit_url(a.id))
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'Save and continue editing')
+        self.assertNotContains(response, 'Save and add another')
+        response = self.fill(response.forms['application_form'], {'full_name': 'Test full name'}).submit('_save').follow()
+        self.assertUrl(response, "cciw.officers.views.applications")
         self.assertEqual(u.application_set.count(), 1)
         self.assertEqual(u.application_set.all()[0].full_name, 'Test full name')
 
         Ensure that a leader can change a finished application of an officer
         """
         self.test_finish_complete() # adds app for OFFICER
-        self._twill_logout()
+        self.webtest_officer_logout()
 
-        self._twill_login(LEADER)
+        self.webtest_officer_login(LEADER)
         # To catch a bug, give the leader an application form for the same camp
         self._add_application(officer=LEADER)
         u = User.objects.get(username=OFFICER[0])
         apps = u.application_set.all()
         self.assertEqual(len(apps), 1)
-        tc.go(self._application_edit_url(apps[0].id))
-        tc.code(200)
-        tc.formvalue('1', 'full_name', 'Changed full name')
-        tc.submit('_save')
-        tc.url(reverse("cciw.officers.views.applications"))
+        response = self.get(self._application_edit_url(apps[0].id))
+        self.assertEqual(response.status_code, 200)
+        response = self.fill(response.forms['application_form'],
+                             {'full_name': 'Changed full name'}).submit('_save').follow()
+        self.assertUrl(response, "cciw.officers.views.applications")
         self.assertEqual(u.application_set.count(), 1)
         self.assertEqual(u.application_set.all()[0].full_name, 'Changed full name')
 
 
         # setup
         self.assertEqual(len(mail.outbox), 0)
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         u = User.objects.get(username=OFFICER[0])
         a = self._add_application()
         self.assertEqual(u.application_set.count(), 1)
         self.assertNotEqual(orig_email, new_email)
 
         # visit page
-        tc.go(self._application_edit_url(a.id))
-        tc.code(200)
-        self._finish_application_form()
-        tc.formvalue('1', 'full_name', 'Test full name')
-        tc.formvalue('1', 'address_email', new_email)
-        tc.submit('_save')
-        tc.url(reverse("cciw.officers.views.applications"))
-
+        response = self.get(self._application_edit_url(a.id))
+        self.assertEqual(response.status_code, 200)
+        self._finish_application_form(response)
+        response = self.fill(response.forms['application_form'],
+                             {'full_name': 'Test full name',
+                              'address_email': new_email}).submit('_save').follow()
+        self.assertUrl(response, "cciw.officers.views.applications")
         self.assertEqual(u.application_set.count(), 1)
 
         # Check the e-mails have been sent
         then no e-mail is sent out
         """
         self.assertEqual(len(mail.outbox), 0)
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         u = User.objects.get(username=OFFICER[0])
         a = self._add_application()
         self.assertEqual(u.application_set.count(), 1)
 
-        tc.go(self._application_edit_url(a.id))
-        tc.code(200)
-        self._finish_application_form()
-        tc.formvalue('1', 'address_email', u.email.upper())
-        tc.submit('_save')
+        response = self.get(self._application_edit_url(a.id))
+        self.assertEqual(response.status_code, 200)
+        self._finish_application_form(response)
+        response = self.fill(response.forms['application_form'],
+                             {'address_email': u.email.upper()}).submit('_save').follow()
 
         # Check no e-mails have been sent
         emails = self._get_email_change_emails()
     def test_finish_incomplete(self):
         u = User.objects.get(username=OFFICER[0])
         self.assertEqual(u.application_set.count(), 0)
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         a = self._add_application()
-        tc.go(self._application_edit_url(a.id))
-        url = tc.browser.get_url()
-        tc.code(200)
-        tc.formvalue('1', 'finished', 'on')
-        tc.submit('_save')
-        tc.url(url)
-        tc.find("Please correct the errors below")
-        tc.find("form-row errors field-address")
+        response = self.get(self._application_edit_url(a.id))
+        url = response.request.url
+        self.assertEqual(response.status_code, 200)
+        response = self.fill(response.forms['application_form'], {'finished': 'on'}).submit('_save')
+        self.assertEqual(url, response.request.url) # Same page
+        self.assertContains(response, "Please correct the errors below")
+        self.assertContains(response, "form-row errors field-address")
         self.assertEqual(u.application_set.exclude(date_submitted__isnull=True).count(), 0) # shouldn't have been saved
 
     def test_finish_complete(self):
         u = User.objects.get(username=OFFICER[0])
         self.assertEqual(u.application_set.count(), 0)
         self.assertEqual(len(mail.outbox), 0)
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         # An old, unfinished application form
         self._add_application()
         a = self._add_application()
-        tc.go(self._application_edit_url(a.id))
-        tc.code(200)
-        self._finish_application_form()
-
-        tc.submit('_save')
-        tc.url(reverse("cciw.officers.views.applications"))
+        response = self.get(self._application_edit_url(a.id))
+        self.assertEqual(response.status_code, 200)
+        response = self._finish_application_form(response).submit('_save').follow()
+        self.assertUrl(response, "cciw.officers.views.applications")
 
         apps = list(u.application_set.all())
         # The old one should have been deleted.
         Ensure that the user can't change an application after it has been
         'finished'
         """
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         a = self._add_application()
         a.finished = True
         a.save()
 
-        tc.go(self._application_edit_url(a.id))
-        url = tc.browser.get_url()
-        tc.code(200)
-        tc.formvalue('1', 'full_name', 'A Changed Full Name')
-        tc.submit('_save')
+        response = self.get(self._application_edit_url(a.id))
+        url = response.request.url
+        self.assertEqual(response.status_code, 200)
+        response = self.fill(response.forms['application_form'],
+                             {'full_name': 'A Changed Full Name'}).submit('_save')
         # we should be on same page:
-        tc.url(url)
-        tc.find("You cannot change a submitted")
+        self.assertEqual(url, response.request.url)
+        self.assertContains(response, "You cannot change a submitted")
         # shouldn't have changed data:
         self.assertNotEqual(a.full_name, 'A Changed Full Name')
 
         """
         Ensure that normal officers can't see the list of applications
         """
-        self._twill_login(OFFICER)
-        tc.go(make_django_url("admin:officers_application_changelist"))
-        tc.code(403)
+        self.webtest_officer_login(OFFICER)
+        response = self.app.get(reverse("admin:officers_application_changelist"),
+                                expect_errors=[403])
+        self.assertEqual(response.status_code, 403)
 
     def test_list_applications_leaders(self):
         """
         Ensure that leaders can see the list of applications
         """
-        self._twill_login(LEADER)
-        tc.go(make_django_url("admin:officers_application_changelist"))
-        tc.code(200)
+        self.webtest_officer_login(LEADER)
+        response = self.get("admin:officers_application_changelist")
+        self.assertEqual(response.status_code, 200)
 
     def test_add_application_duplicate(self):
         """
         Test that we can't add a new application twice in a year
         """
-        self._twill_login(OFFICER)
+        self.webtest_officer_login(OFFICER)
         a1 = self._add_application()
         a1.date_submitted = datetime.date.today()
         a1.save()
         a2 = self._add_application()
-        tc.go(self._application_edit_url(a2.id))
-        self._finish_application_form()
-        tc.submit('_save')
-        tc.find("You've already submitted")
+        response = self.get(self._application_edit_url(a2.id))
+        response = self._finish_application_form(response).submit('_save')
+        self.assertContains(response, "You've already submitted")
         u = User.objects.get(username=OFFICER[0])
         self.assertEqual(u.application_set.exclude(date_submitted__isnull=True).count(), 1)
 
 
         # Create another application
         app1 = self._add_application()
-        tc.go(self._application_edit_url(app1.id))
-        self._finish_application_form()
+        response = self.get(self._application_edit_url(app1.id))
+        self._finish_application_form(response)
         # Now change some values
-        tc.formvalue('1', 'full_name', 'New Full Name')
-        tc.submit('_save')
-        tc.url(reverse("cciw.officers.views.applications"))
+        response = self.fill(response.forms['application_form'],
+                             {'full_name': 'New Full Name'}).submit('_save').follow()
+        self.assertUrl(response, "cciw.officers.views.applications")
 
         emails = self._get_application_form_emails()
         self.assertEqual(len(emails), 2)

cciw/officers/tests/references.py

 from django.core import mail
 from django.core.urlresolvers import reverse
 from django.test import TestCase
-from twill import commands as tc
 
 from cciw.cciwmain.models import Camp
 from cciw.officers.email import make_ref_form_url
 from cciw.officers.models import Application
 from cciw.officers.views import get_previous_references
-from cciw.utils.tests.twillhelpers import TwillMixin, make_django_url, make_twill_url
-
+from cciw.utils.tests.webtest import WebTestBase
 
 OFFICER_USERNAME = 'mrofficer2'
 OFFICER_PASSWORD = 'test_normaluser_password'
 #
 
 
-class ReferencesPage(TwillMixin, TestCase):
+class ReferencesPage(WebTestBase):
 
     fixtures = ['basic.json', 'officers_users.json', 'references.json']
 
     def test_page_ok(self):
         # Value of this test lies in the test data.
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.manage_references", year=2000, number=1))
-        tc.code(200)
-        tc.find('For camp 2000-1')
-        tc.notfind('referee1@email.co.uk') # Received
-        tc.find('referee2@email.co.uk')    # Not received
-        tc.find('referee3@email.co.uk')
-        tc.find('referee4@email.co.uk')
+        self.webtest_officer_login(LEADER)
+        response = self.get("cciw.officers.views.manage_references", year=2000, number=1)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'For camp 2000-1')
+        self.assertNotContains(response, 'referee1@email.co.uk') # Received
+        self.assertContains(response, 'referee2@email.co.uk')    # Not received
+        self.assertContains(response, 'referee3@email.co.uk')
+        self.assertContains(response, 'referee4@email.co.uk')
 
     def test_page_anonymous_denied(self):
-        tc.go(make_django_url("cciw.officers.views.manage_references", year=2000, number=1))
-        tc.code(200) # at a redirection page
-        tc.notfind('For camp 2000-1')
+        response = self.get("cciw.officers.views.manage_references", year=2000, number=1)
+        self.assertEqual(response.status_code, 200) # at a redirection page
+        self.assertNotContains(response, 'For camp 2000-1')
 
     def test_page_officers_denied(self):
-        self._twill_login(OFFICER)
-        tc.go(make_django_url("cciw.officers.views.manage_references", year=2000, number=1))
-        tc.code(403)
-        tc.notfind('For camp 2000-1')
+        self.webtest_officer_login(OFFICER)
+        response = self.app.get(reverse("cciw.officers.views.manage_references", kwargs=dict(year=2000, number=1)),
+                                expect_errors=[403])
+        self.assertEqual(response.status_code, 403)
+        self.assertNotIn(response.content, 'For camp 2000-1')
 
 
-class RequestReference(TwillMixin, TestCase):
+class RequestReference(WebTestBase):
     """
     Tests for page where reference is requested, and referee e-mail can be updated.
     """
         app = Application.objects.get(pk=3)
         self.assertTrue(app.referees[0].email != '')
         refinfo = app.references[0]
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2000, number=1) + "?ref_id=%d" % refinfo.id)
-        tc.code(200)
-        tc.notfind("No e-mail address")
-        tc.find("The following e-mail")
-        tc.formvalue("2", "send", "send")
-        tc.submit()
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2000, number=1))
+                                + "?ref_id=%d" % refinfo.id)
+        self.assertEqual(response.status_code, 200)
+        self.assertNotContains(response, "No e-mail address")
+        self.assertContains(response, "The following e-mail")
+        response = response.forms['id_request_reference'].submit("send")
         msgs = [e for e in mail.outbox if "Reference for" in e.subject]
         self.assertEqual(len(msgs), 1)
         self.assertEqual(msgs[0].extra_headers.get('Reply-To', ''), LEADER_EMAIL)
         app = Application.objects.get(pk=3)
         self.assertTrue(app.referees[1].email == '')
         refinfo = app.references[1]
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2000, number=1) + "?ref_id=%d" % refinfo.id)
-        tc.code(200)
-        tc.find("No e-mail address")
-        tc.notfind("This field is required") # Don't want errors on first view
-        tc.notfind("The following e-mail")
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2000, number=1))
+                                + "?ref_id=%d" % refinfo.id)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, "No e-mail address")
+        self.assertNotContains(response, "This field is required") # Don't want errors on first view
+        self.assertNotContains(response, "The following e-mail")
+        return response
 
     def test_add_email(self):
         """
         Ensure we can add the e-mail address
         """
-        self.test_no_email()
-        tc.formvalue('1', 'email', 'addedemail@example.com')
-        tc.submit()
+        response = self.test_no_email()
+        response = self.fill(response.forms['id_set_email_form'],
+                             {'email': 'addedemail@example.com'}).submit('setemail')
         app = Application.objects.get(pk=3)
-        self.assertTrue(app.referees[1].email == 'addedemail@example.com')
-        tc.find("E-mail address updated.")
+        self.assertEqual(app.referees[1].email, 'addedemail@example.com')
+        self.assertContains(response, "E-mail address updated.")
 
     def test_cancel(self):
         # Application 3 has an e-mail address for first referee
         app = Application.objects.get(pk=3)
         self.assertTrue(app.referees[0].email != '')
         refinfo = app.references[0]
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2000, number=1) + "?ref_id=%d" % refinfo.id)
-        tc.code(200)
-        tc.formvalue("2", "cancel", "cancel")
-        tc.submit()
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2000, number=1))
+                                + "?ref_id=%d" % refinfo.id)
+        self.assertEqual(response.status_code, 200)
+        response = response.forms['id_request_reference'].submit("cancel")
         self.assertEqual(len(mail.outbox), 0)
 
     def test_dont_remove_link(self):
         """
         app = Application.objects.get(pk=3)
         refinfo = app.references[0]
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2000, number=1) + "?ref_id=%d" % refinfo.id)
-        tc.code(200)
-        tc.formvalue('2', 'message', 'I removed the link! Haha')
-        tc.submit()
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2000, number=1))
+                                + "?ref_id=%d" % refinfo.id)
+        self.assertEqual(response.status_code, 200)
+        response = self.fill(response.forms['id_request_reference'],
+                             {'message': 'I removed the link! Haha'}).submit('send')
         url = make_ref_form_url(refinfo.id, None)
-        tc.find(url)
-        tc.find("You removed the link")
+        self.assertContains(response, url)
+        self.assertContains(response, "You removed the link")
         self.assertEqual(len(mail.outbox), 0)
 
     def test_update_with_exact_match(self):
         refinfo = app.references[0]
         prev_refs, exact = get_previous_references(refinfo, camp)
         assert exact is not None
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2001, number=1) + "?ref_id=%d&update=1&prev_ref_id=%d" % (refinfo.id, exact.id))
-        tc.code(200)
-        tc.find("Mr Referee1 Name has done a reference for Mr in the past.")
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2001, number=1))
+                                + "?ref_id=%d&update=1&prev_ref_id=%d" % (refinfo.id, exact.id))
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, "Mr Referee1 Name has done a reference for Mr in the past.")
 
     def test_update_with_no_exact_match(self):
         """
         prev_refs, exact = get_previous_references(refinfo, camp)
         assert exact is None
         assert prev_refs[0].reference_form.referee_name == "Mr Referee1 Name"
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.request_reference", year=2001, number=1) + "?ref_id=%d&update=1&prev_ref_id=%d" % (refinfo.id, prev_refs[0].id))
-        tc.code(200)
-        tc.notfind("Mr Referee1 Name has done a reference for Mr in the past.")
-        tc.find("""In the past, "Mr Referee1 Name <referee1@email.co.uk>" did""")
-        tc.find("If you have confirmed")
-        tc.find("""email address is now "Mr Referee1 Name <a_new_email_for_ref1@example.com>",""")
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.request_reference", kwargs=dict(year=2001, number=1))
+                                + "?ref_id=%d&update=1&prev_ref_id=%d" % (refinfo.id, prev_refs[0].id))
+        self.assertEqual(response.status_code, 200)
+        self.assertNotContains(response, "Mr Referee1 Name has done a reference for Mr in the past.")
+        self.assertContains(response, """In the past, "Mr Referee1 Name <referee1@email.co.uk>" did""")
+        self.assertContains(response, "If you have confirmed")
+        self.assertContains(response, """email address is now "Mr Referee1 Name <a_new_email_for_ref1@example.com>",""")
 
     def test_nag(self):
         """
         """
         app = Application.objects.get(pk=1)
         refinfo = app.references[0]
-        self._twill_login(LEADER)
-        tc.go(make_django_url("cciw.officers.views.nag_by_officer", year=2000, number=1) + "?ref_id=%d" % refinfo.id)
-        tc.code(200)
-        tc.find("to nag their referee")
-        tc.formvalue("1", "send", "send")
-        tc.submit()
+        self.webtest_officer_login(LEADER)
+        response = self.app.get(reverse("cciw.officers.views.nag_by_officer", kwargs=dict(year=2000, number=1))
+                                + "?ref_id=%d" % refinfo.id)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, "to nag their referee")
+        response = response.forms[0].submit('send')
         msgs = [e for e in mail.outbox if "Need reference from" in e.subject]
         self.assertEqual(len(msgs), 1)
         self.assertEqual(msgs[0].extra_headers.get('Reply-To', ''), LEADER_EMAIL)
 
-class CreateReference(TwillMixin, TestCase):
+class CreateReference(WebTestBase):
     """
     Tests for page for referees submitting references
     """
         """
         app = Application.objects.get(pk=2)
         url = make_ref_form_url(app.references[0].id, None)
-        tc.go(make_twill_url(url))
-        tc.code(200)
+        response = self.get(url)
+        self.assertEqual(response.status_code, 200)
+        return response
 
     def test_page_submit(self):
         """
         app = Application.objects.get(pk=2)
         self.assertEqual(app.referees[0].name, "Mr Referee3 Name")
         self.assertTrue(app.references[0].reference_form is None)
-        self.test_page_ok()
-
-        tc.formvalue('1', 'referee_name', 'Referee3 Name')
-        tc.formvalue('1', 'how_long_known', 'Forever')
-        tc.formvalue('1', 'capacity_known', 'Minister')
-        tc.formvalue('1', 'capability_children', 'Fine')
-        tc.formvalue('1', 'character', 'Great')
-        tc.formvalue('1', 'concerns', 'No')
-        tc.submit()
+        response = self.test_page_ok()
+        response = self.fill(response.forms['id_create_reference'],
+                             {'referee_name': 'Referee3 Name',
+                              'how_long_known': 'Forever',
+                              'capacity_known': 'Minister',
+                              'capability_children': 'Fine',
+                              'character': 'Great',
+                              'concerns': 'No',
+                              }).submit().follow()
 
         # Check the data has been saved
         app = Application.objects.get(pk=2)
 
         # Go to the corresponding URL
         url = make_ref_form_url(app2.references[0].id, app1.references[0].id)
-        tc.go(make_twill_url(url))
-        tc.code(200)
+        response = self.get(url)
+        self.assertEqual(response.status_code, 200)
 
         # Check it is pre-filled as we expect
-        html = tc.show()
+        html = response.content
         self.assertInHTML("""<input id="id_referee_name" maxlength="100" name="referee_name" type="text" value="Mr Referee1 Name" />""", html)
         self.assertInHTML("""<input id="id_how_long_known" maxlength="150" name="how_long_known" type="text" value="A long time" />""", html)
 
     'autocomplete_light',
     'djiki',
     'paypal.standard.ipn',
+    'django.contrib.humanize',
+    'django_notify',
+    'mptt',
+    'sekizai',
+    'sorl.thumbnail',
+    'wiki',
+    'wiki.plugins.attachments',
+    'wiki.plugins.notifications',
+    'wiki.plugins.images',
+    'wiki.plugins.macros',
 )
 
 if not (LIVEBOX and WEBSERVER_RUNNING):
 )
 
 TEMPLATE_CONTEXT_PROCESSORS = [
+    "django.core.context_processors.debug",
     "django.core.context_processors.media",
     "django.core.context_processors.static",
     "django.core.context_processors.request",
     "django.contrib.auth.context_processors.auth",
     "django.contrib.messages.context_processors.messages",
     "cciw.cciwmain.common.standard_processor",
+    "django.core.context_processors.tz",
+    "sekizai.context_processors.sekizai",
 ]
 
 if DEBUG:
 from django.contrib import admin
 from django.contrib.auth.models import User
 from django.views.generic.base import RedirectView
+from django_notify.urls import get_pattern as get_notify_pattern
+from wiki.urls import get_pattern as get_wiki_pattern
 
 import cciw.auth
 from cciw.bookings.models import BookingAccount
     (r'^admin/', include(admin.site.urls)),
     (r'^officers/', include('cciw.officers.urls')),
     url('^autocomplete/', include('autocomplete_light.urls')),
-    (r'^wiki/', include('djiki.urls')),
+    (r'^notify/', get_notify_pattern()),
+    (r'^wiki/', get_wiki_pattern()),
     (r'^paypal/ipn/', include('paypal.standard.ipn.urls')),
 )
 

cciw/utils/tests/twillhelpers.py

-from StringIO import StringIO
-
-import twill
-from twill import commands as tc
-from django.core.handlers.wsgi import WSGIHandler
-from django.core.urlresolvers import reverse
-from twill.shell import TwillCommandLoop
-
-def make_twill_url(url):
-    url = url.replace("http://www.cciw.co.uk/", "http://127.0.0.1:8080/")
-    return url.replace("https://www.cciw.co.uk/", "http://127.0.0.1:8080/")
-
-BASE = "https://www.cciw.co.uk"
-def make_django_url(view, *args, **kwargs):
-    return make_twill_url(BASE + reverse(view, args=args, kwargs=kwargs))
-
-def twill_setup():
-    app = WSGIHandler()
-    twill.add_wsgi_intercept("127.0.0.1", 8080, lambda: app)
-    b = twill.get_browser()
-    b._browser._factory.is_html = True # make it handle XHTML
-    twill.browser = b
-
-def twill_teardown():
-    twill.remove_wsgi_intercept('127.0.0.1', 8080)
-
-class TwillMixin(object):
-    twill_quiet = True
-
-    @classmethod
-    def setUpClass(cls):
-        twill_setup()
-        if cls.twill_quiet:
-            twill.set_output(StringIO())
-
-    def _twill_login(self, creds):
-        tc.go(make_django_url("cciw.officers.views.index"))
-        tc.fv(1, 'id_username', creds[0])
-        tc.fv(1, 'id_password', creds[1])
-        tc.submit()
-        tc.code(200)
-
-    def _twill_logout(self):
-        twill.get_browser().clear_cookies()
-
-    def continue_twill(self):
-        cmd = TwillCommandLoop()
-        cmd.cmdloop()
-
-    @classmethod
-    def tearDownClass(cls):
-        twill_teardown()
-
-# Twill snippets
-# To interactively continue, finish test with this:
-#   self.continue_twill()
-# And add
-#   twill_quiet = False
-# to the class

cciw/utils/tests/webtest.py

+import urlparse
+
+from django_webtest import WebTest
+from django.core.urlresolvers import reverse
+
+class WebTestBase(WebTest):
+    """
+    Base class for integration tests that need more than Django's test Client.
+    """
+    # This uses django_webtest, with convenience wrappers.
+    def webtest_officer_login(self, creds):
+        form = self.get("cciw.officers.views.index").form
+        self.fill(form,
+                  {'username': creds[0],
+                   'password': creds[1],
+                   })
+        response = form.submit().follow()
+        self.assertEqual(response.status_code, 200)
+
+    def webtest_officer_logout(self):
+        self.app.cookiejar.clear()
+
+    def fill(self, form, data):
+        for k,v in data.items():
+            form[k] = unicode(v)
+        return form
+
+    def code(self, response, status_code):
+        self.assertEqual(response.status_code, status_code)
+
+    def get(self, urlname, *args, **kwargs):
+        if '/' not in urlname:
+            url = reverse(urlname, args=args, kwargs=kwargs)
+        else:
+            url = urlname
+        return self.app.get(url)
+
+    def assertUrl(self, response, urlname):
+        url = reverse(urlname)
+        path = urlparse.urlparse(response.request.url).path
+        # response.url doesn't work in current version of django_webtest
+        self.assertEqual(path, url)
 
 @task
 def test():
-    local("./manage.py test cciw.cciwmain.tests cciw.officers.tests cciw.bookings.tests --settings=cciw.settings_tests", capture=False)
+    local("./manage.py test --settings=cciw.settings_tests cciw", capture=False)
 
 
 def install_dependencies():
 BeautifulSoup==3.2.0
 Pillow>=2.2.1
 psycopg2==2.2.2
-twill==0.9
 zc.lockfile==1.0.0
 south==0.7.2
 xlwt==0.7.2
 gunicorn
 psutil
 fabric==1.6.0
+webtest
+django-webtest
+-e git://github.com/benjaoming/django-wiki@844438366bebf40ad91b02a64dd3e7a518e4b8c8#egg=wiki

scripts/migrate_wiki.py

+#!/usr/bin/env python
+
+import os
+import re
+import subprocess
+
+os.environ['DJANGO_SETTINGS_MODULE'] = 'cciw.settings'
+
+
+from djiki.models import Page
+from wiki.models import Article, ArticleRevision, URLPath, ArticleForObject
+
+def creole_to_markdown(creole):
+    from creole import Parser
+    from creole.html_emitter import HtmlEmitter
+
+    html = HtmlEmitter(Parser(creole).parse()).emit().encode('utf-8', 'ignore')
+    p = subprocess.Popen(["pandoc", "-f", "html", "-t", "markdown"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    md = p.communicate(html)[0]
+    md = re.sub(r"\[([A-Za-z0-9]+)\]\(\1\)", r"[\1](/wiki/\1/)", md)
+    return md
+
+def main():
+    ArticleForObject.objects.all().delete()
+    URLPath.objects.all().delete()
+    Article.objects.all().delete()
+    ArticleRevision.objects.all().delete()
+
+    root = URLPath.create_root()
+    rev = root.article.current_revision
+    rev.title = "Index"
+    rev.content = "[article_list]"
+    rev.save()
+
+    for p in Page.objects.all():
+        if p.title == "Index":
+            continue
+        first_rev = p.revisions.all().order_by('created')[0]
+        last_rev = p.revisions.all().order_by('-created')[0]
+        article = Article.objects.create(
+            owner=first_rev.author,
+            )
+        previous_revision = None
+        for revno, r in enumerate(p.revisions.all().order_by('created')):
+            revision = ArticleRevision.objects.create(
+                article=article,
+                content=creole_to_markdown(r.content),
+                title=p.title,
+                revision_number=revno+1,
+                previous_revision=previous_revision,
+                user=r.author,
+                )
+            revision.save()
+            # Must be after last save:
+            ArticleRevision.objects.filter(id=revision.id).update(
+                created=r.created,
+                modified=r.created,
+                )
+            previous_revision = revision
+        article.current_revision = article.articlerevision_set.latest()
+        article.save()
+        # Must be after last save:
+        Article.objects.filter(id=article.id).update(
+            created=first_rev.created,
+            modified=last_rev.created,
+            )
+        urlpath = URLPath.objects.create(site_id=1,
+                                         parent=root,
+                                         slug=p.title,
+                                         article=article,
+                                         )
+        article.add_object_relation(urlpath)
+
+
+if __name__ == '__main__':
+    main()

templates/cciw/officers/create_reference.html

     </p>
     {% endif %}
 
-    <form method="post" action="">{% csrf_token %}
+    <form id="id_create_reference" method="post" action="">{% csrf_token %}
       <table>
       {{ form }}
       </table>

templates/cciw/officers/request_reference.html

     address, enter it below and press 'Save' to continue:</p>
 
 
-  <form method="post" action="">{% csrf_token %}
+  <form id="id_set_email_form" method="post" action="">
+    {% csrf_token %}
     {{ emailform.as_p }}
     <div><input type="submit" name="setemail" value="Save" /></div>
   </form>
   <p>If you need to correct the e-mail address, please edit below and press
   'Save' before continuing:</p>
 
-  <form method="post" action="">{% csrf_token %}
+  <form id="id_set_email_form" method="post" action="">
+    {% csrf_token %}
     {{ emailform.as_p }}
     <p><input type="submit" name="setemail" value="Save" /></p>
   </form>
 
   <p>The following e-mail, which you can now modify, will be sent to them.
     Make sure you don't modify the link contained in the e-mail.</p>
-  <form action="" method="post">{% csrf_token %}
+  <form id="id_request_reference" action="" method="post">
+    {% csrf_token %}
     {{ messageform.as_p }}
     <p>
     <input type="submit" name="send" value="Send" />

templates/wiki/base.html

+{% extends "wiki/base_site.html" %}
+
+{% block wiki_header_branding %}
+<a class="navbar-brand" href="/">CCIW</a>
+{% endblock %}
+
+{% block wiki_header_navlinks %}
+<ul class="nav navbar-nav">
+  <li class="active"><a href="{% url 'wiki:root' %}">Wiki</a></li>
+</ul>
+{% endblock %}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.