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

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

The result list instance has to be created before concatenating with [curr_course,]. Now all tests pass.

  • Property svn:keywords set to Id
File size: 37.2 KB
Line 
1## $Id: test_browser.py 7434 2011-12-22 07:39:00Z 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        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
286class ApplicantsContainerUITests(ApplicantsFullSetup):
287    # Tests for ApplicantsContainer class views and pages
288
289    layer = FunctionalLayer
290
291    def test_anonymous_access(self):
292        # Anonymous users can access applicants containers
293        self.browser.open(self.container_path)
294        self.assertEqual(self.browser.headers['Status'], '200 Ok')
295        self.assertFalse(
296            'Manage' in self.browser.contents)
297        return
298
299    def test_manage_access(self):
300        # Managers can access the manage pages of applicants
301        # containers and can perform actions
302        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
303        self.browser.open(self.manage_container_path)
304        self.assertEqual(self.browser.headers['Status'], '200 Ok')
305        self.assertEqual(self.browser.url, self.manage_container_path)
306        self.browser.getControl("Save").click()
307        self.assertTrue('Data saved' in self.browser.contents)
308        self.browser.getControl("Remove selected", index=0).click()
309        self.assertTrue('No applicant selected' in self.browser.contents)
310        self.browser.getControl("Add local role").click()
311        self.assertTrue('No user selected' in self.browser.contents)
312        self.browser.getControl("Cancel", index=0).click()
313        self.assertEqual(self.browser.url, self.container_path)
314        return
315
316    def test_add_delete_applicants(self):
317        # Managers can add and delete applicants
318        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
319        self.add_applicant_path = self.container_path + '/addapplicant'
320        self.container_manage_path = self.container_path + '/@@manage'
321        self.browser.open(self.container_manage_path)
322        self.browser.getControl("Add applicant").click()
323        self.assertEqual(self.browser.headers['Status'], '200 Ok')
324        self.assertEqual(self.browser.url, self.add_applicant_path)
325        self.browser.getControl(name="form.firstname").value = 'Alois'
326        self.browser.getControl(name="form.middlename").value = 'Kofi'
327        self.browser.getControl(name="form.lastname").value = 'Bettermann'
328        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
329        self.browser.getControl("Create application record").click()
330        self.assertTrue('Application initialized' in self.browser.contents)
331        self.browser.open(self.container_manage_path)
332        self.assertEqual(self.browser.headers['Status'], '200 Ok')
333        ctrl = self.browser.getControl(name='val_id')
334        value = ctrl.options[0]
335        ctrl.getControl(value=value).selected = True
336        self.browser.getControl("Remove selected", index=0).click()
337        self.assertTrue('Successfully removed:' in self.browser.contents)
338        self.browser.open(self.add_applicant_path)
339        self.browser.getControl(name="form.firstname").value = 'Albert'
340        self.browser.getControl(name="form.lastname").value = 'Einstein'
341        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
342        self.browser.getControl("Create application record").click()
343        self.assertTrue('Application initialized' in self.browser.contents)
344        return
345
346class ApplicantUITests(ApplicantsFullSetup):
347    # Tests for uploading/browsing the passport image of appplicants
348
349    layer = FunctionalLayer
350
351    def test_manage_and_view_applicant(self):
352        # Managers can manage applicants
353        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
354        self.slip_path = self.view_path + '/application_slip.pdf'
355        self.browser.open(self.manage_path)
356        self.assertEqual(self.browser.headers['Status'], '200 Ok')
357        self.fill_correct_values()
358        # Fire transition
359        self.browser.getControl(name="transition").value = ['start']
360        self.browser.getControl("Save").click()
361        # Be sure that the empty phone field does not show wrong error message
362        self.assertFalse('Required input is missing' in self.browser.contents)
363        self.assertMatches('...Form has been saved...', self.browser.contents)
364        self.assertMatches('...Application started by Manager...',
365                           self.browser.contents)
366        self.browser.open(self.view_path)
367        self.assertEqual(self.browser.headers['Status'], '200 Ok')
368        # Change course_admitted
369        self.browser.open(self.manage_path)
370        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
371        self.browser.getControl("Save").click()
372        self.assertMatches('...Form has been saved...', self.browser.contents)
373        # Change password
374        self.browser.getControl(name="password").value = 'secret'
375        self.browser.getControl(name="control_password").value = 'secre'
376        self.browser.getControl("Save").click()
377        self.assertMatches('...Passwords do not match...',
378                           self.browser.contents)
379        self.browser.getControl(name="password").value = 'secret'
380        self.browser.getControl(name="control_password").value = 'secret'
381        self.browser.getControl("Save").click()
382        self.assertMatches('...Form has been saved...', self.browser.contents)
383        # Open pdf slip
384        self.browser.open(self.slip_path)
385        self.assertEqual(self.browser.headers['Status'], '200 Ok')
386        self.assertEqual(self.browser.headers['Content-Type'],
387                         'application/pdf')
388        # Managers can view applicants even if certificate has been removed
389        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
390        self.browser.open(self.view_path)
391        self.assertEqual(self.browser.headers['Status'], '200 Ok')
392        self.browser.open(self.slip_path)
393        self.assertEqual(self.browser.headers['Status'], '200 Ok')
394        return
395
396    def test_passport_edit_view(self):
397        # We get a default image after login
398        self.browser.open(self.login_path)
399        self.login()
400        self.browser.open(self.browser.url + '/passport.jpg')
401        self.assertEqual(self.browser.headers['status'], '200 Ok')
402        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
403        self.assertTrue('JFIF' in self.browser.contents)
404        self.assertEqual(
405            self.browser.headers['content-length'], str(PH_LEN))
406
407    def test_edit_applicant(self):
408        # Applicants can edit their record
409        self.browser.open(self.login_path)
410        self.login()
411        self.browser.open(self.edit_path)
412        self.assertTrue(self.browser.url != self.login_path)
413        self.assertEqual(self.browser.headers['Status'], '200 Ok')
414        self.fill_correct_values()
415        self.browser.getControl("Save").click()
416        self.assertMatches('...Form has been saved...', self.browser.contents)
417        return
418
419    def image_url(self, filename):
420        return self.edit_path.replace('edit', filename)
421
422    def test_after_login_default_browsable(self):
423        # After login we see the placeholder image in the edit view
424        #import pdb; pdb.set_trace()
425        self.login()
426        self.assertEqual(self.browser.url, self.view_path)
427        self.browser.open(self.edit_path)
428        # There is a correct <img> link included
429        self.assertTrue(
430              '<img src="passport.jpg" />' in self.browser.contents)
431        # Browsing the link shows a real image
432        self.browser.open(self.image_url('passport.jpg'))
433        self.assertEqual(
434            self.browser.headers['content-type'], 'image/jpeg')
435        self.assertEqual(len(self.browser.contents), PH_LEN)
436
437    def test_after_submit_default_browsable(self):
438        # After submitting an applicant form the default image is
439        # still visible
440        self.login()
441        self.browser.open(self.edit_path)
442        self.browser.getControl("Save").click() # submit form
443        # There is a correct <img> link included
444        self.assertTrue(
445            '<img src="passport.jpg" />' in self.browser.contents)
446        # Browsing the link shows a real image
447        self.browser.open(self.image_url('passport.jpg'))
448        self.assertEqual(
449            self.browser.headers['content-type'], 'image/jpeg')
450        self.assertEqual(len(self.browser.contents), PH_LEN)
451
452    def test_uploaded_image_respects_file_size_restriction(self):
453        # When we upload an image that is too big ( > 10 KB) we will
454        # get an error message
455        self.login()
456        self.browser.open(self.edit_path)
457        # Create a pseudo image file and select it to be uploaded in form
458        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
459        pseudo_image = StringIO(photo_content)
460        ctrl = self.browser.getControl(name='form.passport')
461        file_ctrl = ctrl.mech_control
462        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
463        self.browser.getControl("Save").click() # submit form
464        # There is a correct <img> link included
465        self.assertTrue(
466            '<img src="passport.jpg" />' in self.browser.contents)
467        # We get a warning message
468        self.assertTrue(
469            'Uploaded image is too big' in self.browser.contents)
470        # Browsing the image gives us the default image, not the
471        # uploaded one.
472        self.browser.open(self.image_url('passport.jpg'))
473        self.assertEqual(
474            self.browser.headers['content-type'], 'image/jpeg')
475        self.assertEqual(len(self.browser.contents), PH_LEN)
476        # There is really no file stored for the applicant
477        img = getUtility(IExtFileStore).getFile(
478            IFileStoreNameChooser(self.applicant).chooseName())
479        self.assertTrue(img is None)
480
481    def test_uploaded_image_browsable_w_errors(self):
482        # We can upload a different image and browse it after submit,
483        # even if there are still errors in the form
484        self.login()
485        self.browser.open(self.edit_path)
486        # Create a pseudo image file and select it to be uploaded in form
487        photo_content = 'I pretend to be a graphics file'
488        pseudo_image = StringIO(photo_content)
489        ctrl = self.browser.getControl(name='form.passport')
490        file_ctrl = ctrl.mech_control
491        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
492        self.browser.getControl("Save").click() # submit form
493        # There is a correct <img> link included
494        self.assertTrue(
495            '<img src="passport.jpg" />' in self.browser.contents)
496        # Browsing the link shows a real image
497        self.browser.open(self.image_url('passport.jpg'))
498        self.assertEqual(
499            self.browser.headers['content-type'], 'image/jpeg')
500        self.assertEqual(self.browser.contents, photo_content)
501
502    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
503        # After uploading a new passport pic the file is correctly
504        # stored in an imagestorage
505        self.login()
506        self.browser.open(self.edit_path)
507        # Create a pseudo image file and select it to be uploaded in form
508        pseudo_image = StringIO('I pretend to be a graphics file')
509        ctrl = self.browser.getControl(name='form.passport')
510        file_ctrl = ctrl.mech_control
511        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
512        self.browser.getControl("Save").click() # submit form
513        storage = getUtility(IExtFileStore)
514        file_id = IFileStoreNameChooser(self.applicant).chooseName()
515        pseudo_image.seek(0) # reset our file data source
516        self.assertEqual(
517            storage.getFile(file_id).read(), pseudo_image.read())
518        return
519
520    def test_uploaded_image_browsable_wo_errors(self):
521        # We can upload a different image and browse it after submit,
522        # if there are no errors in form
523        self.login()
524        self.browser.open(self.edit_path)
525        self.fill_correct_values() # fill other fields with correct values
526        # Create a pseudo image file and select it to be uploaded in form
527        pseudo_image = StringIO('I pretend to be a graphics file')
528        ctrl = self.browser.getControl(name='form.passport')
529        file_ctrl = ctrl.mech_control
530        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
531        self.browser.getControl("Save").click() # submit form
532        # There is a correct <img> link included
533        self.assertTrue(
534            '<img src="passport.jpg" />' in self.browser.contents)
535        # Browsing the link shows a real image
536        self.browser.open(self.image_url('passport.jpg'))
537        self.assertEqual(
538            self.browser.headers['content-type'], 'image/jpeg')
539        self.assertEqual(len(self.browser.contents), 31)
540
541    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
542        # After uploading a new passport pic the file is correctly
543        # stored in an imagestorage if form contains no errors
544        self.login()
545        self.browser.open(self.edit_path)
546        self.fill_correct_values() # fill other fields with correct values
547        # Create a pseudo image file and select it to be uploaded in form
548        pseudo_image = StringIO('I pretend to be a graphics file')
549        ctrl = self.browser.getControl(name='form.passport')
550        file_ctrl = ctrl.mech_control
551        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
552        self.browser.getControl("Save").click() # submit form
553        storage = getUtility(IExtFileStore)
554        file_id = IFileStoreNameChooser(self.applicant).chooseName()
555        # The stored image can be fetched
556        fd = storage.getFile(file_id)
557        file_len = len(fd.read())
558        self.assertEqual(file_len, 31)
559
560    def test_uploaded_images_equal(self):
561        # Make sure uploaded images do really differ if we eject a
562        # change notfication (and do not if we don't)
563        self.login()
564        self.browser.open(self.edit_path)
565        self.fill_correct_values() # fill other fields with correct values
566        self.browser.getControl("Save").click() # submit form
567        # Now go on as an officer
568        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
569        self.browser.open(self.manage_path)
570
571        # Create a pseudo image file and select it to be uploaded in form
572        pseudo_image = StringIO('I pretend to be a graphics file')
573        ctrl = self.browser.getControl(name='form.passport')
574        file_ctrl = ctrl.mech_control
575        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
576        file_id = IFileStoreNameChooser(self.applicant).chooseName()
577        setSite(self.app)
578        passport0 = getUtility(IExtFileStore).getFile(file_id)
579        self.browser.getControl("Save").click() # submit form with changed pic
580        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
581        self.browser.getControl("Save").click() # submit form w/o changes
582        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
583        self.assertTrue(passport0 is None)
584        self.assertTrue(passport0 != passport1)
585        self.assertTrue(passport1 == passport2)
586        return
587
588    def test_pay_acceptance_fee(self):
589        self.login()
590        self.browser.open(self.edit_path)
591        # Payment tickets can't be created before the form has been validated
592        self.browser.getControl("Add online payment ticket").click()
593        self.assertTrue('Required input is missing' in self.browser.contents)
594        self.fill_correct_values()
595        # We have to save the form otherwise the filled fields will be cleared
596        # after adding an online payment, because adding an online payment
597        # requires a filled form but does not save it
598        self.browser.getControl("Save").click()
599        self.browser.getControl("Add online payment ticket").click()
600        # Session object missing
601        self.assertTrue(
602            'Session configuration object is not available'
603            in self.browser.contents)
604        configuration = SessionConfiguration()
605        configuration.academic_session = 2009
606        configuration.acceptance_fee = 200
607        self.app['configuration'].addSessionConfiguration(configuration)
608        self.browser.open(self.edit_path)
609        self.fill_correct_values()
610        self.browser.getControl("Add online payment ticket").click()
611        self.assertMatches('...Payment ticket created...',
612                           self.browser.contents)
613        # Payment ticket can be removed if they haven't received a
614        # valid callback
615        ctrl = self.browser.getControl(name='val_id')
616        value = ctrl.options[0]
617        ctrl.getControl(value=value).selected = True
618        self.browser.getControl("Remove selected", index=0).click()
619        self.assertMatches('...Successfully removed...', self.browser.contents)
620        # We will try the callback request view
621        self.browser.getControl("Add online payment ticket").click()
622        ctrl = self.browser.getControl(name='val_id')
623        value = ctrl.options[0]
624        self.browser.getLink(value).click()
625        self.assertMatches('...Amount Authorized...',
626                           self.browser.contents)
627        payment_url = self.browser.url
628        # The pdf payment receipt can't yet be opened
629        self.browser.open(payment_url + '/payment_receipt.pdf')
630        self.assertMatches('...Ticket not yet paid...',
631                           self.browser.contents)
632        # Request callback
633        self.browser.open(payment_url)
634        self.browser.getLink("Request callback").click()
635        self.assertMatches('...Valid callback received...',
636                          self.browser.contents)
637        # Callback can't be applied twice
638        self.browser.open(payment_url + '/callback')
639        self.assertMatches(
640            "...Transition 'pay' requires 'started' as source state...",
641            self.browser.contents)
642        # The payment receipt can be downloaded now
643        self.browser.open(payment_url)
644        self.browser.getLink("Download payment receipt").click()
645        self.assertEqual(self.browser.headers['Status'], '200 Ok')
646        self.assertEqual(self.browser.headers['Content-Type'],
647                         'application/pdf')
648        # Applicant is is in state 'paid'
649        self.browser.open(self.view_path)
650        self.assertMatches('...paid...',
651                           self.browser.contents)
652        state = IWorkflowState(self.applicant).getState()
653        self.assertTrue(state == 'paid')
654
655    def test_final_submit(self):
656        # Make sure that a correctly filled form with passport picture
657        # can be submitted (only) after payment
658        self.login()
659        self.browser.getLink("Edit application record").click()
660        self.assertFalse('Final Submit' in self.browser.contents)
661        IWorkflowInfo(self.applicant).fireTransition('pay')
662        self.browser.open(self.edit_path)
663        self.assertTrue('Final Submit' in self.browser.contents)
664        self.fill_correct_values() # fill other fields with correct values
665        self.browser.getControl("Final Submit").click()
666        # We forgot to upload a passport picture
667        self.assertTrue(
668            'No passport picture uploaded' in self.browser.contents)
669        # Create a pseudo image file and select it to be uploaded in form
670        pseudo_image = StringIO('I pretend to be a graphics file')
671        ctrl = self.browser.getControl(name='form.passport')
672        file_ctrl = ctrl.mech_control
673        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
674        self.browser.getControl("Final Submit").click() # (finally) submit form
675        # The picture has been uploaded but the form cannot be submitted
676        # since the passport confirmation box was not ticked
677        self.assertTrue(
678            'Passport picture confirmation box not ticked'
679            in self.browser.contents)
680        self.browser.getControl(name="confirm_passport").value = True
681        self.browser.getControl("Final Submit").click()
682        self.assertTrue(
683            '... submitted ...' in self.browser.contents)
684        self.browser.goBack(count=1)
685        self.browser.getControl("Save").click()
686        self.assertTrue(
687            'The requested form is locked' in self.browser.contents)
688        self.browser.goBack(count=1)
689        self.browser.getControl("Final Submit").click()
690        self.assertTrue(
691            'The requested form is locked' in self.browser.contents)
692        return
693
694    def test_locking(self):
695        # Make sure that locked forms can't be submitted
696        self.login()
697        self.browser.open(self.edit_path)
698        self.fill_correct_values() # fill other fields with correct values
699        # Create a pseudo image file and select it to be uploaded in form
700        pseudo_image = StringIO('I pretend to be a graphics file')
701        ctrl = self.browser.getControl(name='form.passport')
702        file_ctrl = ctrl.mech_control
703        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
704        self.browser.getControl("Save").click()
705        # Now we lock the form
706        self.applicant.locked = True
707        self.browser.open(self.edit_path)
708        self.assertEqual(self.browser.headers['Status'], '200 Ok')
709        self.assertTrue(
710            'The requested form is locked' in self.browser.contents)
711        return
712
713    def test_certificate_removed(self):
714        self.login()
715        self.browser.open(self.edit_path)
716        self.fill_correct_values()
717        self.browser.getControl("Save").click()
718        self.browser.open(self.view_path)
719        self.assertTrue(
720            'Unnamed Certificate' in self.browser.contents)
721        self.browser.open(self.edit_path)
722        self.assertTrue(
723            '<option selected="selected" value="CERT1">' in self.browser.contents)
724        # Now we remove the certificate
725        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
726        # The certificate is still shown in display mode
727        self.browser.open(self.view_path)
728        self.assertTrue(
729            'Unnamed Certificate' in self.browser.contents)
730        # The certificate is still selectable in edit mode so that it won't
731        # be automatically replaced by another (arbitrary) certificate
732        self.browser.open(self.edit_path)
733        self.assertTrue(
734            '<option selected="selected" value="CERT1">' in self.browser.contents)
735        # Consequently, the certificate is still shown after saving the form
736        self.browser.getControl("Save").click()
737        self.browser.open(self.view_path)
738        self.assertTrue(
739            'Unnamed Certificate' in self.browser.contents)
740        # Even if we add a new certificate the previous (removed)
741        # certificate is shown
742        certificate = createObject('waeup.Certificate')
743        certificate.code = 'CERT2'
744        certificate.title = 'New Certificate'
745        certificate.application_category = 'basic'
746        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
747            certificate)
748        self.browser.open(self.edit_path)
749        self.assertTrue(
750            '<option selected="selected" value="CERT1">' in self.browser.contents)
751
752class ApplicantRegisterTests(ApplicantsFullSetup):
753    # Tests for applicant registration
754
755    layer = FunctionalLayer
756
757    def test_register_applicant(self):
758        # An applicant can register himself.
759        self.browser.open(self.container_path)
760        self.browser.getLink("Register for application").click()
761        # Fill the edit form with suitable values
762        self.browser.getControl(name="form.firstname").value = 'John'
763        self.browser.getControl(name="form.lastname").value = 'Tester'
764        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
765        self.browser.getControl(name="form.phone.country").value = '234'
766        self.browser.getControl(name="form.phone.area").value = '555'
767        self.browser.getControl(name="form.phone.extension").value = '6666666'
768        self.browser.getControl("Get login credentials").click()
769        self.assertEqual(self.browser.url,
770            self.container_path + '/registration_complete?email=xx%40yy.zz')
771        return
772
773    def test_register_applicant_wo_phone(self):
774        # We don't require the phone number when registering
775        self.browser.open(self.container_path)
776        self.browser.getLink("Register for application").click()
777        # Fill the edit form with suitable values
778        self.browser.getControl(name="form.firstname").value = 'John'
779        self.browser.getControl(name="form.lastname").value = 'Tester'
780        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
781        self.browser.getControl("Get login credentials").click()
782        self.assertEqual(self.browser.url,
783            self.container_path + '/registration_complete?email=xx%40yy.zz')
784        return
Note: See TracBrowser for help on using the repository browser.