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

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

We have to ensure that students are properly indexed after creation from applicants.

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