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

Last change on this file since 7984 was 7984, checked in by Henrik Bettermann, 12 years ago

Remove unneeded default values in interfaces. Adjust tests.

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