source: main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py @ 8286

Last change on this file since 8286 was 8286, checked in by Henrik Bettermann, 12 years ago

Roll back r8282. Also in students the registration state is simply called state.

  • Property svn:keywords set to Id
File size: 42.8 KB
Line 
1## $Id: test_browser.py 8286 2012-04-26 13:58:25Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Test the applicant-related UI components.
20"""
21import pytz
22import shutil
23import tempfile
24import grok
25from StringIO import StringIO
26from datetime import datetime, date, timedelta
27from mechanize import LinkNotFoundError
28from zope.event import notify
29from zope.catalog.interfaces import ICatalog
30from zope.component import createObject, getUtility
31from zope.component.hooks import setSite, clearSite
32from zope.security.interfaces import Unauthorized
33from zope.testbrowser.testing import Browser
34from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
35from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
36from waeup.kofa.app import University
37from waeup.kofa.configuration import SessionConfiguration
38from waeup.kofa.applicants.container import ApplicantsContainer
39from waeup.kofa.applicants.applicant import Applicant
40from waeup.kofa.interfaces import (
41    IExtFileStore, IFileStoreNameChooser, IUserAccount)
42from waeup.kofa.university.faculty import Faculty
43from waeup.kofa.university.department import Department
44
45PH_LEN = 2059  # Length of placeholder file
46
47class ApplicantsFullSetup(FunctionalTestCase):
48    # A test case that only contains a setup and teardown
49    #
50    # Complete setup for applicants handlings is rather complex and
51    # requires lots of things created before we can start. This is a
52    # setup that does all this, creates a university, creates PINs,
53    # etc.  so that we do not have to bother with that in different
54    # test cases.
55
56    layer = FunctionalLayer
57
58    def setUp(self):
59        super(ApplicantsFullSetup, self).setUp()
60
61        # Setup a sample site for each test
62        app = University()
63        self.dc_root = tempfile.mkdtemp()
64        app['datacenter'].setStoragePath(self.dc_root)
65
66        # Prepopulate the ZODB...
67        self.getRootFolder()['app'] = app
68        # we add the site immediately after creation to the
69        # ZODB. Catalogs and other local utilities are not setup
70        # before that step.
71        self.app = self.getRootFolder()['app']
72        # Set site here. Some of the following setup code might need
73        # to access grok.getSite() and should get our new app then
74        setSite(app)
75
76        self.login_path = 'http://localhost/app/login'
77        self.root_path = 'http://localhost/app/applicants'
78        self.manage_root_path = self.root_path + '/@@manage'
79        self.add_container_path = self.root_path + '/@@add'
80        self.container_path = 'http://localhost/app/applicants/app2009'
81        self.manage_container_path = self.container_path + '/@@manage'
82
83        # Add an applicants container
84        applicantscontainer = ApplicantsContainer()
85        applicantscontainer.code = u'app2009'
86        applicantscontainer.prefix = 'app'
87        applicantscontainer.year = 2009
88        applicantscontainer.entry_level = 100
89        applicantscontainer.application_category = 'basic'
90        applicantscontainer.mode = 'create'
91        delta = timedelta(days=10)
92        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
93        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
94        self.app['applicants']['app2009'] = applicantscontainer
95        self.applicantscontainer = self.app['applicants']['app2009']
96
97        # Populate university
98        certificate = createObject('waeup.Certificate')
99        certificate.code = 'CERT1'
100        certificate.application_category = 'basic'
101        certificate.start_level = 100
102        certificate.end_level = 500
103        self.certificate = certificate
104        self.app['faculties']['fac1'] = Faculty()
105        # The code has explicitely to be set, otherwise we don't
106        # find created students in their department
107        self.app['faculties']['fac1']['dep1'] = Department(code='dep1')
108        self.department = self.app['faculties']['fac1']['dep1']
109        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
110            certificate)
111
112        # Put the prepopulated site into test ZODB and prepare test
113        # browser
114        self.browser = Browser()
115        self.browser.handleErrors = False
116
117        # Create 5 access codes with prefix'FOO' and cost 9.99 each
118        pin_container = self.app['accesscodes']
119        pin_container.createBatch(
120            datetime.now(), 'some_userid', 'APP', 9.99, 5)
121        pins = pin_container[pin_container.keys()[0]].values()
122        self.pins = [x.representation for x in pins]
123        self.existing_pin = self.pins[0]
124        parts = self.existing_pin.split('-')[1:]
125        self.existing_series, self.existing_number = parts
126
127        # Add an applicant
128        self.applicant = createObject('waeup.Applicant')
129        # reg_number is the only field which has to be preset here
130        # because managers are allowed to edit this required field
131        self.applicant.reg_number = u'1234'
132        app['applicants']['app2009'].addApplicant(self.applicant)
133        IUserAccount(
134            self.app['applicants']['app2009'][
135            self.applicant.application_number]).setPassword('apwd')
136        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
137            'app2009', self.applicant.application_number, 'manage')
138        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
139            'app2009', self.applicant.application_number, 'edit')
140        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
141            'app2009', self.applicant.application_number)
142
143    def login(self):
144        # Perform an applicant login. This creates an applicant record.
145        #
146        # This helper also sets `self.applicant`, which is the
147        # applicant object created.
148        self.browser.open(self.login_path)
149        self.browser.getControl(
150            name="form.login").value = self.applicant.applicant_id
151        self.browser.getControl(name="form.password").value = 'apwd'
152        self.browser.getControl("Login").click()
153
154    def fill_correct_values(self):
155        # Fill the edit form with suitable values
156        self.browser.getControl(name="form.firstname").value = 'John'
157        self.browser.getControl(name="form.lastname").value = 'Tester'
158        self.browser.getControl(name="form.course1").value = ['CERT1']
159        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
160        self.browser.getControl(name="form.sex").value = ['m']
161        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
162
163    def tearDown(self):
164        super(ApplicantsFullSetup, self).tearDown()
165        clearSite()
166        shutil.rmtree(self.dc_root)
167
168class ApplicantsRootUITests(ApplicantsFullSetup):
169    # Tests for ApplicantsRoot class
170
171    layer = FunctionalLayer
172
173    def test_anonymous_access(self):
174        # Anonymous users can access applicants root
175        self.browser.open(self.root_path)
176        self.assertEqual(self.browser.headers['Status'], '200 Ok')
177        self.assertFalse(
178            'Manage ' in self.browser.contents)
179        return
180
181    def test_anonymous_no_actions(self):
182        # Make sure anonymous users cannot access actions
183        self.browser.open(self.root_path)
184        self.assertRaises(
185            LookupError, self.browser.getControl, "Add local role")
186        # Manage screen neither linked nor accessible for anonymous
187        self.assertRaises(
188            LinkNotFoundError,
189            self.browser.getLink, 'Manage application section')
190        self.assertRaises(
191            Unauthorized, self.browser.open, self.manage_root_path)
192        # Add container screen not accessible for anonymous
193        self.assertRaises(
194            Unauthorized, self.browser.open, self.add_container_path)
195        return
196
197    def test_manage_access(self):
198        # Managers can access the manage pages of applicants root
199        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
200        self.browser.open(self.root_path)
201        self.assertTrue('Manage application section' in self.browser.contents)
202        # There is a manage link
203        link = self.browser.getLink('Manage application section')
204        link.click()
205        self.assertEqual(self.browser.headers['Status'], '200 Ok')
206        self.assertEqual(self.browser.url, self.manage_root_path)
207        return
208
209    def test_manage_actions_access(self):
210        # Managers can access the action on manage screen
211        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
212        self.browser.open(self.manage_root_path)
213        self.browser.getControl("Add local role").click()
214        self.assertTrue('No user selected' in self.browser.contents)
215        return
216
217    # We have no local roles yet
218    #def test_local_roles_add_delete(self):
219    #    # Managers can assign and delete local roles of applicants root
220    #    myusers = self.app['users']
221    #    myusers.addUser('bob', 'bobssecret')
222    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
223    #    self.browser.open(self.manage_root_path)
224    #    self.browser.getControl(name="user").value = ['bob']
225    #    self.browser.getControl(name="local_role").value = [
226    #        'waeup.local.ApplicationsOfficer']
227    #    self.browser.getControl("Add local role").click()
228    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
229    #    # Remove the role assigned
230    #    ctrl = self.browser.getControl(name='role_id')
231    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
232    #    self.browser.getControl("Remove selected local roles").click()
233    #    self.assertTrue('Successfully removed:' in self.browser.contents)
234    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
235    #    return
236
237    def test_add_delete_container(self):
238        # Managers can add and delete applicants containers
239        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
240        self.browser.open(self.manage_root_path)
241        self.browser.getControl("Cancel").click()
242        self.assertEqual(self.browser.url, self.root_path)
243        self.browser.open(self.manage_root_path)
244        self.browser.getControl("Add applicants container").click()
245        self.assertEqual(self.browser.headers['Status'], '200 Ok')
246        self.assertEqual(self.browser.url, self.add_container_path)
247        self.browser.getControl(name="form.prefix").value = ['app']
248        self.browser.getControl("Add applicants container").click()
249        self.assertTrue(
250            'There were errors' in self.browser.contents)
251        self.browser.getControl(name="form.prefix").value = ['app']
252        self.browser.getControl(name="form.year").value = ['2010']
253        self.browser.getControl(name="form.entry_level").value = ['100']
254        self.browser.getControl(name="form.mode").value = ['create']
255        self.browser.getControl(
256            name="form.application_category").value = ['basic']
257        self.browser.getControl("Add applicants container").click()
258        self.assertTrue('Added:' in self.browser.contents)
259        self.browser.getLink("app2010").click()
260        self.assertTrue('<h1>General Studies 2010/2011</h1>'
261            in self.browser.contents)
262        self.browser.open(self.add_container_path)
263        self.browser.getControl("Cancel").click()
264        self.assertEqual(self.browser.url, self.manage_root_path)
265        self.browser.open(self.add_container_path)
266        self.browser.getControl(name="form.prefix").value = ['app']
267        self.browser.getControl(name="form.year").value = ['2010']
268        self.browser.getControl(name="form.entry_level").value = ['100']
269        self.browser.getControl(name="form.mode").value = ['create']
270        self.browser.getControl(
271            name="form.application_category").value = ['basic']
272        self.browser.getControl("Add applicants container").click()
273        self.assertTrue('exists already in the database'
274                        in self.browser.contents)
275        self.browser.open(self.manage_root_path)
276        ctrl = self.browser.getControl(name='val_id')
277        ctrl.getControl(value='app2010').selected = True
278        self.browser.getControl("Remove selected", index=0).click()
279        self.assertTrue('Successfully removed:' in self.browser.contents)
280        self.browser.open(self.add_container_path)
281        self.browser.getControl(name="form.prefix").value = ['app']
282        self.browser.getControl(name="form.year").value = ['2010']
283        self.browser.getControl(name="form.entry_level").value = ['100']
284        self.browser.getControl(name="form.mode").value = ['create']
285        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
286        self.browser.getControl(
287            name="form.application_category").value = ['basic']
288        self.browser.getControl("Add applicants container").click()
289        del self.app['applicants']['app2010']
290        ctrl = self.browser.getControl(name='val_id')
291        ctrl.getControl(value='app2010').selected = True
292        self.browser.getControl("Remove selected", index=0).click()
293        self.assertMatches('...Could not delete...', self.browser.contents)
294        return
295
296class ApplicantsContainerUITests(ApplicantsFullSetup):
297    # Tests for ApplicantsContainer class views and pages
298
299    layer = FunctionalLayer
300
301    def test_anonymous_access(self):
302        # Anonymous users can access applicants containers
303        self.browser.open(self.container_path)
304        self.assertEqual(self.browser.headers['Status'], '200 Ok')
305        self.assertFalse(
306            'Manage ' in self.browser.contents)
307        return
308
309    def test_manage_access(self):
310        # Managers can access the manage pages of applicants
311        # containers and can perform actions
312        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
313        self.browser.open(self.manage_container_path)
314        self.assertEqual(self.browser.headers['Status'], '200 Ok')
315        self.assertEqual(self.browser.url, self.manage_container_path)
316        self.browser.getControl("Save").click()
317        self.assertTrue('Form has been saved' in self.browser.contents)
318        self.browser.getControl("Remove selected", index=0).click()
319        self.assertTrue('No applicant selected' in self.browser.contents)
320        self.browser.getControl("Add local role").click()
321        self.assertTrue('No user selected' in self.browser.contents)
322        self.browser.getControl("Cancel", index=0).click()
323        self.assertEqual(self.browser.url, self.container_path)
324        return
325
326    def test_add_delete_applicants(self):
327        # Managers can add and delete applicants
328        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
329        self.add_applicant_path = self.container_path + '/addapplicant'
330        self.container_manage_path = self.container_path + '/@@manage'
331        self.browser.open(self.container_manage_path)
332        self.browser.getControl("Add applicant").click()
333        self.assertEqual(self.browser.headers['Status'], '200 Ok')
334        self.assertEqual(self.browser.url, self.add_applicant_path)
335        self.browser.getControl(name="form.firstname").value = 'Alois'
336        self.browser.getControl(name="form.middlename").value = 'Kofi'
337        self.browser.getControl(name="form.lastname").value = 'Bettermann'
338        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
339        self.browser.getControl("Create application record").click()
340        self.assertTrue('Application initialized' in self.browser.contents)
341        self.browser.open(self.container_manage_path)
342        self.assertEqual(self.browser.headers['Status'], '200 Ok')
343        ctrl = self.browser.getControl(name='val_id')
344        value = ctrl.options[0]
345        ctrl.getControl(value=value).selected = True
346        self.browser.getControl("Remove selected", index=0).click()
347        self.assertTrue('Successfully removed:' in self.browser.contents)
348        self.browser.open(self.add_applicant_path)
349        self.browser.getControl(name="form.firstname").value = 'Albert'
350        self.browser.getControl(name="form.lastname").value = 'Einstein'
351        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
352        self.browser.getControl("Create application record").click()
353        self.assertTrue('Application initialized' in self.browser.contents)
354        return
355
356class ApplicantUITests(ApplicantsFullSetup):
357    # Tests for uploading/browsing the passport image of appplicants
358
359    layer = FunctionalLayer
360
361    def test_manage_and_view_applicant(self):
362        # Managers can manage applicants
363        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
364        self.slip_path = self.view_path + '/application_slip.pdf'
365        self.browser.open(self.manage_path)
366        self.assertEqual(self.browser.headers['Status'], '200 Ok')
367        self.fill_correct_values()
368        # Fire transition
369        self.browser.getControl(name="transition").value = ['start']
370        self.browser.getControl("Save").click()
371        # Be sure that the empty phone field does not show wrong error message
372        self.assertFalse('Required input is missing' in self.browser.contents)
373        self.assertMatches('...Form has been saved...', self.browser.contents)
374        self.assertMatches('...Application started by Manager...',
375                           self.browser.contents)
376        self.browser.open(self.view_path)
377        self.assertEqual(self.browser.headers['Status'], '200 Ok')
378        # Change course_admitted
379        self.browser.open(self.manage_path)
380        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
381        self.browser.getControl("Save").click()
382        self.assertMatches('...Form has been saved...', self.browser.contents)
383        # Change password
384        self.browser.getControl(name="password").value = 'secret'
385        self.browser.getControl(name="control_password").value = 'secre'
386        self.browser.getControl("Save").click()
387        self.assertMatches('...Passwords do not match...',
388                           self.browser.contents)
389        self.browser.getControl(name="password").value = 'secret'
390        self.browser.getControl(name="control_password").value = 'secret'
391        self.browser.getControl("Save").click()
392        self.assertMatches('...Form has been saved...', self.browser.contents)
393        # Open pdf slip
394        self.browser.open(self.slip_path)
395        self.assertEqual(self.browser.headers['Status'], '200 Ok')
396        self.assertEqual(self.browser.headers['Content-Type'],
397                         'application/pdf')
398        # Managers can view applicants even if certificate has been removed
399        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
400        self.browser.open(self.view_path)
401        self.assertEqual(self.browser.headers['Status'], '200 Ok')
402        self.browser.open(self.slip_path)
403        self.assertEqual(self.browser.headers['Status'], '200 Ok')
404        return
405
406    def test_passport_edit_view(self):
407        # We get a default image after login
408        self.browser.open(self.login_path)
409        self.login()
410        self.browser.open(self.browser.url + '/passport.jpg')
411        self.assertEqual(self.browser.headers['status'], '200 Ok')
412        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
413        self.assertTrue('JFIF' in self.browser.contents)
414        self.assertEqual(
415            self.browser.headers['content-length'], str(PH_LEN))
416
417    def test_edit_applicant(self):
418        # Applicants can edit their record
419        self.browser.open(self.login_path)
420        self.login()
421        self.browser.open(self.edit_path)
422        self.assertTrue(self.browser.url != self.login_path)
423        self.assertEqual(self.browser.headers['Status'], '200 Ok')
424        self.fill_correct_values()
425        self.browser.getControl("Save").click()
426        self.assertMatches('...Form has been saved...', self.browser.contents)
427        return
428
429    def image_url(self, filename):
430        return self.edit_path.replace('edit', filename)
431
432    def test_after_login_default_browsable(self):
433        # After login we see the placeholder image in the edit view
434        self.login()
435        self.assertEqual(self.browser.url, self.view_path)
436        self.browser.open(self.edit_path)
437        # There is a correct <img> link included
438        self.assertTrue(
439              '<img src="passport.jpg" height="180px" />' in self.browser.contents)
440        # Browsing the link shows a real image
441        self.browser.open(self.image_url('passport.jpg'))
442        self.assertEqual(
443            self.browser.headers['content-type'], 'image/jpeg')
444        self.assertEqual(len(self.browser.contents), PH_LEN)
445
446    def test_after_submit_default_browsable(self):
447        # After submitting an applicant form the default image is
448        # still visible
449        self.login()
450        self.browser.open(self.edit_path)
451        self.browser.getControl("Save").click() # submit form
452        # There is a correct <img> link included
453        self.assertTrue(
454            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
455        # Browsing the link shows a real image
456        self.browser.open(self.image_url('passport.jpg'))
457        self.assertEqual(
458            self.browser.headers['content-type'], 'image/jpeg')
459        self.assertEqual(len(self.browser.contents), PH_LEN)
460
461    def test_uploaded_image_respects_file_size_restriction(self):
462        # When we upload an image that is too big ( > 10 KB) we will
463        # get an error message
464        self.login()
465        self.browser.open(self.edit_path)
466        # Create a pseudo image file and select it to be uploaded in form
467        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
468        pseudo_image = StringIO(photo_content)
469        ctrl = self.browser.getControl(name='form.passport')
470        file_ctrl = ctrl.mech_control
471        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
472        self.browser.getControl("Save").click() # submit form
473        # There is a correct <img> link included
474        self.assertTrue(
475            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
476        # We get a warning message
477        self.assertTrue(
478            'Uploaded image is too big' in self.browser.contents)
479        # Browsing the image gives us the default image, not the
480        # uploaded one.
481        self.browser.open(self.image_url('passport.jpg'))
482        self.assertEqual(
483            self.browser.headers['content-type'], 'image/jpeg')
484        self.assertEqual(len(self.browser.contents), PH_LEN)
485        # There is really no file stored for the applicant
486        img = getUtility(IExtFileStore).getFile(
487            IFileStoreNameChooser(self.applicant).chooseName())
488        self.assertTrue(img is None)
489
490    def test_uploaded_image_browsable_w_errors(self):
491        # We can upload a different image and browse it after submit,
492        # even if there are still errors in the form
493        self.login()
494        self.browser.open(self.edit_path)
495        # Create a pseudo image file and select it to be uploaded in form
496        photo_content = 'I pretend to be a graphics file'
497        pseudo_image = StringIO(photo_content)
498        ctrl = self.browser.getControl(name='form.passport')
499        file_ctrl = ctrl.mech_control
500        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
501        self.browser.getControl("Save").click() # submit form
502        # There is a correct <img> link included
503        self.assertTrue(
504            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
505        # Browsing the link shows a real image
506        self.browser.open(self.image_url('passport.jpg'))
507        self.assertEqual(
508            self.browser.headers['content-type'], 'image/jpeg')
509        self.assertEqual(self.browser.contents, photo_content)
510
511    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
512        # After uploading a new passport pic the file is correctly
513        # stored in an imagestorage
514        self.login()
515        self.browser.open(self.edit_path)
516        # Create a pseudo image file and select it to be uploaded in form
517        pseudo_image = StringIO('I pretend to be a graphics file')
518        ctrl = self.browser.getControl(name='form.passport')
519        file_ctrl = ctrl.mech_control
520        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
521        self.browser.getControl("Save").click() # submit form
522        storage = getUtility(IExtFileStore)
523        file_id = IFileStoreNameChooser(self.applicant).chooseName()
524        pseudo_image.seek(0) # reset our file data source
525        self.assertEqual(
526            storage.getFile(file_id).read(), pseudo_image.read())
527        return
528
529    def test_uploaded_image_browsable_wo_errors(self):
530        # We can upload a different image and browse it after submit,
531        # if there are no errors in form
532        self.login()
533        self.browser.open(self.edit_path)
534        self.fill_correct_values() # fill other fields with correct values
535        # Create a pseudo image file and select it to be uploaded in form
536        pseudo_image = StringIO('I pretend to be a graphics file')
537        ctrl = self.browser.getControl(name='form.passport')
538        file_ctrl = ctrl.mech_control
539        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
540        self.browser.getControl("Save").click() # submit form
541        # There is a correct <img> link included
542        self.assertTrue(
543            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
544        # Browsing the link shows a real image
545        self.browser.open(self.image_url('passport.jpg'))
546        self.assertEqual(
547            self.browser.headers['content-type'], 'image/jpeg')
548        self.assertEqual(len(self.browser.contents), 31)
549
550    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
551        # After uploading a new passport pic the file is correctly
552        # stored in an imagestorage if form contains no errors
553        self.login()
554        self.browser.open(self.edit_path)
555        self.fill_correct_values() # fill other fields with correct values
556        # Create a pseudo image file and select it to be uploaded in form
557        pseudo_image = StringIO('I pretend to be a graphics file')
558        ctrl = self.browser.getControl(name='form.passport')
559        file_ctrl = ctrl.mech_control
560        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
561        self.browser.getControl("Save").click() # submit form
562        storage = getUtility(IExtFileStore)
563        file_id = IFileStoreNameChooser(self.applicant).chooseName()
564        # The stored image can be fetched
565        fd = storage.getFile(file_id)
566        file_len = len(fd.read())
567        self.assertEqual(file_len, 31)
568
569    def test_uploaded_images_equal(self):
570        # Make sure uploaded images do really differ if we eject a
571        # change notfication (and do not if we don't)
572        self.login()
573        self.browser.open(self.edit_path)
574        self.fill_correct_values() # fill other fields with correct values
575        self.browser.getControl("Save").click() # submit form
576        # Now go on as an officer
577        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
578        self.browser.open(self.manage_path)
579
580        # Create a pseudo image file and select it to be uploaded in form
581        pseudo_image = StringIO('I pretend to be a graphics file')
582        ctrl = self.browser.getControl(name='form.passport')
583        file_ctrl = ctrl.mech_control
584        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
585        file_id = IFileStoreNameChooser(self.applicant).chooseName()
586        setSite(self.app)
587        passport0 = getUtility(IExtFileStore).getFile(file_id)
588        self.browser.getControl("Save").click() # submit form with changed pic
589        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
590        self.browser.getControl("Save").click() # submit form w/o changes
591        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
592        self.assertTrue(passport0 is None)
593        self.assertTrue(passport0 != passport1)
594        self.assertTrue(passport1 == passport2)
595        return
596
597    def test_pay_application_fee(self):
598        self.login()
599        self.browser.open(self.edit_path)
600        # Payment tickets can't be created before the form has been validated
601        self.browser.getControl("Add online payment ticket").click()
602        self.assertTrue('Required input is missing' in self.browser.contents)
603        self.fill_correct_values()
604        # We have to save the form otherwise the filled fields will be cleared
605        # after adding an online payment, because adding an online payment
606        # requires a filled form but does not save it
607        self.browser.getControl("Save").click()
608        self.browser.getControl("Add online payment ticket").click()
609        # Session object missing
610        self.assertTrue(
611            'Session configuration object is not available'
612            in self.browser.contents)
613        configuration = SessionConfiguration()
614        configuration.academic_session = 2009
615        configuration.application_fee = 200.0
616        self.app['configuration'].addSessionConfiguration(configuration)
617        self.browser.open(self.edit_path)
618        self.fill_correct_values()
619        self.browser.getControl("Add online payment ticket").click()
620        self.assertMatches('...Payment ticket created...',
621                           self.browser.contents)
622        self.assertMatches('...Activation Code...',
623                           self.browser.contents)
624        # Payment ticket can be removed if they haven't received a
625        # valid callback
626        self.browser.open(self.edit_path)
627        ctrl = self.browser.getControl(name='val_id')
628        value = ctrl.options[0]
629        ctrl.getControl(value=value).selected = True
630        self.browser.getControl("Remove selected", index=0).click()
631        self.assertMatches('...Successfully removed...', self.browser.contents)
632        # We will try the callback request view
633        self.browser.getControl("Add online payment ticket").click()
634        self.browser.open(self.edit_path)
635        ctrl = self.browser.getControl(name='val_id')
636        value = ctrl.options[0]
637        self.browser.getLink(value).click()
638        self.assertMatches('...Amount Authorized...',
639                           self.browser.contents)
640        payment_url = self.browser.url
641        # The pdf payment slip can't yet be opened
642        #self.browser.open(payment_url + '/payment_receipt.pdf')
643        #self.assertMatches('...Ticket not yet paid...',
644        #                   self.browser.contents)
645        # Request callback
646        self.browser.getLink("Request callback").click()
647        self.assertMatches('...Valid callback received...',
648                          self.browser.contents)
649        # Callback can't be applied twice
650        self.browser.open(payment_url + '/simulate_callback')
651        self.assertMatches(
652            "...Transition 'pay' requires 'started' as source state...",
653            self.browser.contents)
654        # The payment slip can be downloaded now
655        self.browser.open(payment_url)
656        self.browser.getLink("Download payment slip").click()
657        self.assertEqual(self.browser.headers['Status'], '200 Ok')
658        self.assertEqual(self.browser.headers['Content-Type'],
659                         'application/pdf')
660        # Applicant is is in state 'paid'
661        self.browser.open(self.view_path)
662        self.assertMatches('...paid...',
663                           self.browser.contents)
664        state = IWorkflowState(self.applicant).getState()
665        self.assertTrue(state == 'paid')
666
667    def test_final_submit(self):
668        # Make sure that a correctly filled form with passport picture
669        # can be submitted (only) after payment
670        self.login()
671        self.browser.getLink("Edit application record").click()
672        self.assertFalse('Final Submit' in self.browser.contents)
673        IWorkflowInfo(self.applicant).fireTransition('pay')
674        self.browser.open(self.edit_path)
675        self.assertTrue('Final Submit' in self.browser.contents)
676        self.fill_correct_values() # fill other fields with correct values
677        self.browser.getControl("Final Submit").click()
678        # We forgot to upload a passport picture
679        self.assertTrue(
680            'No passport picture uploaded' in self.browser.contents)
681        # Create a pseudo image file and select it to be uploaded in form
682        pseudo_image = StringIO('I pretend to be a graphics file')
683        ctrl = self.browser.getControl(name='form.passport')
684        file_ctrl = ctrl.mech_control
685        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
686        self.browser.getControl("Final Submit").click() # (finally) submit form
687        # The picture has been uploaded but the form cannot be submitted
688        # since the passport confirmation box was not ticked
689        self.assertTrue(
690            'Passport picture confirmation box not ticked'
691            in self.browser.contents)
692        self.browser.getControl(name="confirm_passport").value = True
693        self.browser.getControl("Final Submit").click()
694        self.assertTrue(
695            '... submitted ...' in self.browser.contents)
696        self.browser.goBack(count=1)
697        self.browser.getControl("Save").click()
698        self.assertTrue(
699            'The requested form is locked' in self.browser.contents)
700        self.browser.goBack(count=1)
701        self.browser.getControl("Final Submit").click()
702        self.assertTrue(
703            'The requested form is locked' in self.browser.contents)
704        return
705
706    def test_locking(self):
707        # Make sure that locked forms can't be submitted
708        self.login()
709        self.browser.open(self.edit_path)
710        self.fill_correct_values() # fill other fields with correct values
711        # Create a pseudo image file and select it to be uploaded in form
712        pseudo_image = StringIO('I pretend to be a graphics file')
713        ctrl = self.browser.getControl(name='form.passport')
714        file_ctrl = ctrl.mech_control
715        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
716        self.browser.getControl("Save").click()
717        # Now we lock the form
718        self.applicant.locked = True
719        self.browser.open(self.edit_path)
720        self.assertEqual(self.browser.headers['Status'], '200 Ok')
721        self.assertTrue(
722            'The requested form is locked' in self.browser.contents)
723        return
724
725    def test_certificate_removed(self):
726        self.login()
727        self.browser.open(self.edit_path)
728        self.fill_correct_values()
729        self.browser.getControl("Save").click()
730        self.browser.open(self.view_path)
731        self.assertTrue(
732            'Unnamed Certificate' in self.browser.contents)
733        self.browser.open(self.edit_path)
734        self.assertTrue(
735            '<option selected="selected" value="CERT1">' in self.browser.contents)
736        # Now we remove the certificate
737        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
738        # The certificate is still shown in display mode
739        self.browser.open(self.view_path)
740        self.assertTrue(
741            'Unnamed Certificate' in self.browser.contents)
742        # The certificate is still selectable in edit mode so that it won't
743        # be automatically replaced by another (arbitrary) certificate
744        self.browser.open(self.edit_path)
745        self.assertTrue(
746            '<option selected="selected" value="CERT1">' in self.browser.contents)
747        # Consequently, the certificate is still shown after saving the form
748        self.browser.getControl("Save").click()
749        self.browser.open(self.view_path)
750        self.assertTrue(
751            'Unnamed Certificate' in self.browser.contents)
752        # Even if we add a new certificate the previous (removed)
753        # certificate is shown
754        certificate = createObject('waeup.Certificate')
755        certificate.code = 'CERT2'
756        certificate.title = 'New Certificate'
757        certificate.application_category = 'basic'
758        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
759            certificate)
760        self.browser.open(self.edit_path)
761        self.assertTrue(
762            '<option selected="selected" value="CERT1">'
763            in self.browser.contents)
764
765class ApplicantRegisterTests(ApplicantsFullSetup):
766    # Tests for applicant registration
767
768    layer = FunctionalLayer
769
770    def test_register_applicant_create(self):
771        # An applicant can register himself.
772        self.browser.open(self.container_path)
773        self.browser.getLink("Register for application").click()
774        # Fill the edit form with suitable values
775        self.browser.getControl(name="form.firstname").value = 'Anna'
776        self.browser.getControl(name="form.lastname").value = 'Kurios'
777        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
778        self.browser.getControl(name="form.phone.country").value = ['+234']
779        self.browser.getControl(name="form.phone.area").value = '555'
780        self.browser.getControl(name="form.phone.ext").value = '6666666'
781        self.browser.getControl("Get login credentials").click()
782        self.assertEqual(self.browser.url,
783            self.container_path + '/registration_complete?email=xx%40yy.zz')
784        # The new applicant can be found in the catalog via the email address
785        cat = getUtility(ICatalog, name='applicants_catalog')
786        results = list(
787            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
788        applicant = results[0]
789        self.assertEqual(applicant.lastname,'Kurios')
790        # The application_id has been copied to the reg_number
791        self.assertEqual(applicant.applicant_id, applicant.reg_number)
792        # The applicant can be found in the catalog via the reg_number
793        results = list(
794            cat.searchResults(
795            reg_number=(applicant.reg_number, applicant.reg_number)))
796        self.assertEqual(applicant,results[0])
797        return
798
799    def test_register_applicant_update(self):
800        # We change the application mode and check if applicants
801        # can find and update imported records instead of creating new records.
802        # First we check what happens if record does not exist.
803        self.applicantscontainer.mode = 'update'
804        self.browser.open(self.container_path + '/register')
805        self.browser.getControl(name="form.firstname").value = 'John'
806        self.browser.getControl(name="form.reg_number").value = 'anynumber'
807        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
808        self.browser.getControl("Get login credentials").click()
809        self.assertTrue('No application record found.'
810            in self.browser.contents)
811        # Even with the correct reg_number we can't register
812        # because firstname attribute is not set.
813        self.applicantscontainer.mode = 'update'
814        self.browser.open(self.container_path + '/register')
815        self.browser.getControl(name="form.firstname").value = 'John'
816        self.browser.getControl(name="form.reg_number").value = '1234'
817        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
818        self.browser.getControl("Get login credentials").click()
819        self.assertTrue('An error occurred.' in self.browser.contents)
820        # Let's set this attribute manually
821        # and try to register with a wrong name.
822        self.applicant.firstname = u'John'
823        self.browser.open(self.container_path + '/register')
824        self.browser.getControl(name="form.firstname").value = 'Johnny'
825        self.browser.getControl(name="form.reg_number").value = '1234'
826        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
827        self.browser.getControl("Get login credentials").click()
828        # Anonymous is not informed that firstname verification failed.
829        # It seems that the record doesn't exist.
830        self.assertTrue('No application record found.'
831            in self.browser.contents)
832        # Even with the correct firstname we can't register because
833        # password has already been set.
834        self.browser.getControl(name="form.firstname").value = 'John'
835        self.browser.getControl(name="form.reg_number").value = '1234'
836        self.browser.getControl("Get login credentials").click()
837        self.assertTrue('Your password has already been set.'
838            in self.browser.contents)
839        # We unset the password and try to register again.
840        IUserAccount(
841            self.app['applicants']['app2009'][
842            self.applicant.application_number]).context.password = None
843        self.browser.open(self.container_path + '/register')
844        # The firstname field, used for verification, is not case-sensitive.
845        self.browser.getControl(name="form.firstname").value = 'jOhn'
846        self.browser.getControl(name="form.reg_number").value = '1234'
847        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
848        self.browser.getControl("Get login credentials").click()
849        # Yeah, we succeded ...
850        self.assertTrue('Your registration was successful.'
851            in self.browser.contents)
852        # ... and  applicant can be found in the catalog via the email address
853        cat = getUtility(ICatalog, name='applicants_catalog')
854        results = list(
855            cat.searchResults(
856            email=('xx@yy.zz', 'xx@yy.zz')))
857        self.assertEqual(self.applicant,results[0])
858        return
859
860    def test_register_applicant_wo_phone(self):
861        # We don't require the phone number when registering
862        self.browser.open(self.container_path)
863        self.browser.getLink("Register for application").click()
864        # Fill the edit form with suitable values
865        self.browser.getControl(name="form.firstname").value = 'John'
866        self.browser.getControl(name="form.lastname").value = 'Tester'
867        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
868        self.browser.getControl("Get login credentials").click()
869        self.assertEqual(self.browser.url,
870            self.container_path + '/registration_complete?email=xx%40yy.zz')
871        return
872
873    def test_change_password_request(self):
874        self.browser.open('http://localhost/app/sendpw')
875        self.browser.getControl(name="form.reg_number").value = '1234'
876        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
877        self.browser.getControl("Get new login credentials").click()
878        self.assertTrue('No record found' in self.browser.contents)
879        self.applicant.email = 'aa@aa.ng'
880        # Update the catalog
881        notify(grok.ObjectModifiedEvent(self.applicant))
882        self.browser.open('http://localhost/app/sendpw')
883        self.browser.getControl(name="form.reg_number").value = '1234'
884        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
885        self.browser.getControl("Get new login credentials").click()
886        self.assertTrue(
887            'An email with your user name and password has been sent'
888            in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.