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

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

Remove all ApplicantsContainerProvider? components. Experience has shown that we only need one type of ApplicantsContainers? and one type of Applicants but with different interfaces for form generation.

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