source: main/waeup.sirp/branches/henrik-bootstrap/src/waeup/sirp/applicants/tests/test_browser.py @ 11107

Last change on this file since 11107 was 7436, checked in by Henrik Bettermann, 13 years ago

Set current_level when creating students from applicant data. Use new entry_level attribute from ApplicantsContainer?.

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