source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_browser.py @ 7427

Last change on this file since 7427 was 7426, checked in by uli, 13 years ago

Cosmetics.

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