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

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

Remove entry_level attribute. The entry level is given by the start level of the study course admitted.

  • Property svn:keywords set to Id
File size: 42.5 KB
Line 
1## $Id: test_browser.py 8311 2012-04-29 19:47:24Z 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 pytz
22import shutil
23import tempfile
24import grok
25from StringIO import StringIO
26from datetime import datetime, date, timedelta
27from mechanize import LinkNotFoundError
28from zope.event import notify
29from zope.catalog.interfaces import ICatalog
30from zope.component import createObject, getUtility
31from zope.component.hooks import setSite, clearSite
32from zope.security.interfaces import Unauthorized
33from zope.testbrowser.testing import Browser
34from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
35from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
36from waeup.kofa.app import University
37from waeup.kofa.configuration import SessionConfiguration
38from waeup.kofa.applicants.container import ApplicantsContainer
39from waeup.kofa.applicants.applicant import Applicant
40from waeup.kofa.interfaces import (
41    IExtFileStore, IFileStoreNameChooser, IUserAccount)
42from waeup.kofa.university.faculty import Faculty
43from waeup.kofa.university.department import Department
44
45PH_LEN = 2059  # Length of placeholder file
46
47class ApplicantsFullSetup(FunctionalTestCase):
48    # A test case that only contains a setup and teardown
49    #
50    # Complete setup for applicants handlings is rather complex and
51    # requires lots of things created before we can start. This is a
52    # setup that does all this, creates a university, creates PINs,
53    # etc.  so that we do not have to bother with that in different
54    # test cases.
55
56    layer = FunctionalLayer
57
58    def setUp(self):
59        super(ApplicantsFullSetup, self).setUp()
60
61        # Setup a sample site for each test
62        app = University()
63        self.dc_root = tempfile.mkdtemp()
64        app['datacenter'].setStoragePath(self.dc_root)
65
66        # Prepopulate the ZODB...
67        self.getRootFolder()['app'] = app
68        # we add the site immediately after creation to the
69        # ZODB. Catalogs and other local utilities are not setup
70        # before that step.
71        self.app = self.getRootFolder()['app']
72        # Set site here. Some of the following setup code might need
73        # to access grok.getSite() and should get our new app then
74        setSite(app)
75
76        self.login_path = 'http://localhost/app/login'
77        self.root_path = 'http://localhost/app/applicants'
78        self.manage_root_path = self.root_path + '/@@manage'
79        self.add_container_path = self.root_path + '/@@add'
80        self.container_path = 'http://localhost/app/applicants/app2009'
81        self.manage_container_path = self.container_path + '/@@manage'
82
83        # Add an applicants container
84        applicantscontainer = ApplicantsContainer()
85        applicantscontainer.code = u'app2009'
86        applicantscontainer.prefix = 'app'
87        applicantscontainer.year = 2009
88        applicantscontainer.application_category = 'basic'
89        applicantscontainer.mode = 'create'
90        delta = timedelta(days=10)
91        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
92        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
93        self.app['applicants']['app2009'] = applicantscontainer
94        self.applicantscontainer = self.app['applicants']['app2009']
95
96        # Populate university
97        certificate = createObject('waeup.Certificate')
98        certificate.code = 'CERT1'
99        certificate.application_category = 'basic'
100        certificate.start_level = 100
101        certificate.end_level = 500
102        self.certificate = certificate
103        self.app['faculties']['fac1'] = Faculty()
104        # The code has explicitely to be set, otherwise we don't
105        # find created students in their department
106        self.app['faculties']['fac1']['dep1'] = Department(code='dep1')
107        self.department = self.app['faculties']['fac1']['dep1']
108        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
109            certificate)
110
111        # Put the prepopulated site into test ZODB and prepare test
112        # browser
113        self.browser = Browser()
114        self.browser.handleErrors = False
115
116        # Create 5 access codes with prefix'FOO' and cost 9.99 each
117        pin_container = self.app['accesscodes']
118        pin_container.createBatch(
119            datetime.now(), 'some_userid', 'APP', 9.99, 5)
120        pins = pin_container[pin_container.keys()[0]].values()
121        self.pins = [x.representation for x in pins]
122        self.existing_pin = self.pins[0]
123        parts = self.existing_pin.split('-')[1:]
124        self.existing_series, self.existing_number = parts
125
126        # Add an applicant
127        self.applicant = createObject('waeup.Applicant')
128        # reg_number is the only field which has to be preset here
129        # because managers are allowed to edit this required field
130        self.applicant.reg_number = u'1234'
131        app['applicants']['app2009'].addApplicant(self.applicant)
132        IUserAccount(
133            self.app['applicants']['app2009'][
134            self.applicant.application_number]).setPassword('apwd')
135        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
136            'app2009', self.applicant.application_number, 'manage')
137        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
138            'app2009', self.applicant.application_number, 'edit')
139        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
140            'app2009', self.applicant.application_number)
141
142    def login(self):
143        # Perform an applicant login. This creates an applicant record.
144        #
145        # This helper also sets `self.applicant`, which is the
146        # applicant object created.
147        self.browser.open(self.login_path)
148        self.browser.getControl(
149            name="form.login").value = self.applicant.applicant_id
150        self.browser.getControl(name="form.password").value = 'apwd'
151        self.browser.getControl("Login").click()
152
153    def fill_correct_values(self):
154        # Fill the edit form with suitable values
155        self.browser.getControl(name="form.firstname").value = 'John'
156        self.browser.getControl(name="form.lastname").value = 'Tester'
157        self.browser.getControl(name="form.course1").value = ['CERT1']
158        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
159        self.browser.getControl(name="form.sex").value = ['m']
160        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
161
162    def tearDown(self):
163        super(ApplicantsFullSetup, self).tearDown()
164        clearSite()
165        shutil.rmtree(self.dc_root)
166
167class ApplicantsRootUITests(ApplicantsFullSetup):
168    # Tests for ApplicantsRoot class
169
170    layer = FunctionalLayer
171
172    def test_anonymous_access(self):
173        # Anonymous users can access applicants root
174        self.browser.open(self.root_path)
175        self.assertEqual(self.browser.headers['Status'], '200 Ok')
176        self.assertFalse(
177            'Manage ' in self.browser.contents)
178        return
179
180    def test_anonymous_no_actions(self):
181        # Make sure anonymous users cannot access actions
182        self.browser.open(self.root_path)
183        self.assertRaises(
184            LookupError, self.browser.getControl, "Add local role")
185        # Manage screen neither linked nor accessible for anonymous
186        self.assertRaises(
187            LinkNotFoundError,
188            self.browser.getLink, 'Manage application section')
189        self.assertRaises(
190            Unauthorized, self.browser.open, self.manage_root_path)
191        # Add container screen not accessible for anonymous
192        self.assertRaises(
193            Unauthorized, self.browser.open, self.add_container_path)
194        return
195
196    def test_manage_access(self):
197        # Managers can access the manage pages of applicants root
198        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
199        self.browser.open(self.root_path)
200        self.assertTrue('Manage application section' in self.browser.contents)
201        # There is a manage link
202        link = self.browser.getLink('Manage application section')
203        link.click()
204        self.assertEqual(self.browser.headers['Status'], '200 Ok')
205        self.assertEqual(self.browser.url, self.manage_root_path)
206        return
207
208    def test_manage_actions_access(self):
209        # Managers can access the action on manage screen
210        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
211        self.browser.open(self.manage_root_path)
212        self.browser.getControl("Add local role").click()
213        self.assertTrue('No user selected' in self.browser.contents)
214        return
215
216    # We have no local roles yet
217    #def test_local_roles_add_delete(self):
218    #    # Managers can assign and delete local roles of applicants root
219    #    myusers = self.app['users']
220    #    myusers.addUser('bob', 'bobssecret')
221    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
222    #    self.browser.open(self.manage_root_path)
223    #    self.browser.getControl(name="user").value = ['bob']
224    #    self.browser.getControl(name="local_role").value = [
225    #        'waeup.local.ApplicationsOfficer']
226    #    self.browser.getControl("Add local role").click()
227    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
228    #    # Remove the role assigned
229    #    ctrl = self.browser.getControl(name='role_id')
230    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
231    #    self.browser.getControl("Remove selected local roles").click()
232    #    self.assertTrue('Successfully removed:' in self.browser.contents)
233    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
234    #    return
235
236    def test_add_delete_container(self):
237        # Managers can add and delete applicants containers
238        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
239        self.browser.open(self.manage_root_path)
240        self.browser.getControl("Cancel").click()
241        self.assertEqual(self.browser.url, self.root_path)
242        self.browser.open(self.manage_root_path)
243        self.browser.getControl("Add applicants container").click()
244        self.assertEqual(self.browser.headers['Status'], '200 Ok')
245        self.assertEqual(self.browser.url, self.add_container_path)
246        self.browser.getControl(name="form.prefix").value = ['app']
247        self.browser.getControl("Add applicants container").click()
248        self.assertTrue(
249            'There were errors' in self.browser.contents)
250        self.browser.getControl(name="form.prefix").value = ['app']
251        self.browser.getControl(name="form.year").value = ['2010']
252        self.browser.getControl(name="form.mode").value = ['create']
253        self.browser.getControl(
254            name="form.application_category").value = ['basic']
255        self.browser.getControl("Add applicants container").click()
256        self.assertTrue('Added:' in self.browser.contents)
257        self.browser.getLink("app2010").click()
258        self.assertTrue('<h1>General Studies 2010/2011</h1>'
259            in self.browser.contents)
260        self.browser.open(self.add_container_path)
261        self.browser.getControl("Cancel").click()
262        self.assertEqual(self.browser.url, self.manage_root_path)
263        self.browser.open(self.add_container_path)
264        self.browser.getControl(name="form.prefix").value = ['app']
265        self.browser.getControl(name="form.year").value = ['2010']
266        self.browser.getControl(name="form.mode").value = ['create']
267        self.browser.getControl(
268            name="form.application_category").value = ['basic']
269        self.browser.getControl("Add applicants container").click()
270        self.assertTrue('exists already in the database'
271                        in self.browser.contents)
272        self.browser.open(self.manage_root_path)
273        ctrl = self.browser.getControl(name='val_id')
274        ctrl.getControl(value='app2010').selected = True
275        self.browser.getControl("Remove selected", index=0).click()
276        self.assertTrue('Successfully removed:' in self.browser.contents)
277        self.browser.open(self.add_container_path)
278        self.browser.getControl(name="form.prefix").value = ['app']
279        self.browser.getControl(name="form.year").value = ['2010']
280        self.browser.getControl(name="form.mode").value = ['create']
281        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
282        self.browser.getControl(
283            name="form.application_category").value = ['basic']
284        self.browser.getControl("Add applicants container").click()
285        del self.app['applicants']['app2010']
286        ctrl = self.browser.getControl(name='val_id')
287        ctrl.getControl(value='app2010').selected = True
288        self.browser.getControl("Remove selected", index=0).click()
289        self.assertMatches('...Could not delete...', self.browser.contents)
290        return
291
292class ApplicantsContainerUITests(ApplicantsFullSetup):
293    # Tests for ApplicantsContainer class views and pages
294
295    layer = FunctionalLayer
296
297    def test_anonymous_access(self):
298        # Anonymous users can access applicants containers
299        self.browser.open(self.container_path)
300        self.assertEqual(self.browser.headers['Status'], '200 Ok')
301        self.assertFalse(
302            'Manage ' in self.browser.contents)
303        return
304
305    def test_manage_access(self):
306        # Managers can access the manage pages of applicants
307        # containers and can perform actions
308        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
309        self.browser.open(self.manage_container_path)
310        self.assertEqual(self.browser.headers['Status'], '200 Ok')
311        self.assertEqual(self.browser.url, self.manage_container_path)
312        self.browser.getControl("Save").click()
313        self.assertTrue('Form has been saved' in self.browser.contents)
314        self.browser.getControl("Remove selected", index=0).click()
315        self.assertTrue('No applicant selected' in self.browser.contents)
316        self.browser.getControl("Add local role").click()
317        self.assertTrue('No user selected' in self.browser.contents)
318        self.browser.getControl("Cancel", index=0).click()
319        self.assertEqual(self.browser.url, self.container_path)
320        return
321
322    def test_add_delete_applicants(self):
323        # Managers can add and delete applicants
324        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
325        self.add_applicant_path = self.container_path + '/addapplicant'
326        self.container_manage_path = self.container_path + '/@@manage'
327        self.browser.open(self.container_manage_path)
328        self.browser.getControl("Add applicant").click()
329        self.assertEqual(self.browser.headers['Status'], '200 Ok')
330        self.assertEqual(self.browser.url, self.add_applicant_path)
331        self.browser.getControl(name="form.firstname").value = 'Alois'
332        self.browser.getControl(name="form.middlename").value = 'Kofi'
333        self.browser.getControl(name="form.lastname").value = 'Bettermann'
334        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
335        self.browser.getControl("Create application record").click()
336        self.assertTrue('Application initialized' in self.browser.contents)
337        self.browser.open(self.container_manage_path)
338        self.assertEqual(self.browser.headers['Status'], '200 Ok')
339        ctrl = self.browser.getControl(name='val_id')
340        value = ctrl.options[0]
341        ctrl.getControl(value=value).selected = True
342        self.browser.getControl("Remove selected", index=0).click()
343        self.assertTrue('Successfully removed:' in self.browser.contents)
344        self.browser.open(self.add_applicant_path)
345        self.browser.getControl(name="form.firstname").value = 'Albert'
346        self.browser.getControl(name="form.lastname").value = 'Einstein'
347        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
348        self.browser.getControl("Create application record").click()
349        self.assertTrue('Application initialized' in self.browser.contents)
350        return
351
352class ApplicantUITests(ApplicantsFullSetup):
353    # Tests for uploading/browsing the passport image of appplicants
354
355    layer = FunctionalLayer
356
357    def test_manage_and_view_applicant(self):
358        # Managers can manage applicants
359        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
360        self.slip_path = self.view_path + '/application_slip.pdf'
361        self.browser.open(self.manage_path)
362        self.assertEqual(self.browser.headers['Status'], '200 Ok')
363        self.fill_correct_values()
364        # Fire transition
365        self.browser.getControl(name="transition").value = ['start']
366        self.browser.getControl("Save").click()
367        # Be sure that the empty phone field does not show wrong error message
368        self.assertFalse('Required input is missing' in self.browser.contents)
369        self.assertMatches('...Form has been saved...', self.browser.contents)
370        self.assertMatches('...Application started by Manager...',
371                           self.browser.contents)
372        self.browser.open(self.view_path)
373        self.assertEqual(self.browser.headers['Status'], '200 Ok')
374        # Change course_admitted
375        self.browser.open(self.manage_path)
376        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
377        self.browser.getControl("Save").click()
378        self.assertMatches('...Form has been saved...', self.browser.contents)
379        # Change password
380        self.browser.getControl(name="password").value = 'secret'
381        self.browser.getControl(name="control_password").value = 'secre'
382        self.browser.getControl("Save").click()
383        self.assertMatches('...Passwords do not match...',
384                           self.browser.contents)
385        self.browser.getControl(name="password").value = 'secret'
386        self.browser.getControl(name="control_password").value = 'secret'
387        self.browser.getControl("Save").click()
388        self.assertMatches('...Form has been saved...', self.browser.contents)
389        # Open pdf slip
390        self.browser.open(self.slip_path)
391        self.assertEqual(self.browser.headers['Status'], '200 Ok')
392        self.assertEqual(self.browser.headers['Content-Type'],
393                         'application/pdf')
394        # Managers can view applicants even if certificate has been removed
395        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
396        self.browser.open(self.view_path)
397        self.assertEqual(self.browser.headers['Status'], '200 Ok')
398        self.browser.open(self.slip_path)
399        self.assertEqual(self.browser.headers['Status'], '200 Ok')
400        return
401
402    def test_passport_edit_view(self):
403        # We get a default image after login
404        self.browser.open(self.login_path)
405        self.login()
406        self.browser.open(self.browser.url + '/passport.jpg')
407        self.assertEqual(self.browser.headers['status'], '200 Ok')
408        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
409        self.assertTrue('JFIF' in self.browser.contents)
410        self.assertEqual(
411            self.browser.headers['content-length'], str(PH_LEN))
412
413    def test_edit_applicant(self):
414        # Applicants can edit their record
415        self.browser.open(self.login_path)
416        self.login()
417        self.browser.open(self.edit_path)
418        self.assertTrue(self.browser.url != self.login_path)
419        self.assertEqual(self.browser.headers['Status'], '200 Ok')
420        self.fill_correct_values()
421        self.browser.getControl("Save").click()
422        self.assertMatches('...Form has been saved...', self.browser.contents)
423        return
424
425    def image_url(self, filename):
426        return self.edit_path.replace('edit', filename)
427
428    def test_after_login_default_browsable(self):
429        # After login we see the placeholder image in the edit view
430        self.login()
431        self.assertEqual(self.browser.url, self.view_path)
432        self.browser.open(self.edit_path)
433        # There is a correct <img> link included
434        self.assertTrue(
435              '<img src="passport.jpg" height="180px" />' in self.browser.contents)
436        # Browsing the link shows a real image
437        self.browser.open(self.image_url('passport.jpg'))
438        self.assertEqual(
439            self.browser.headers['content-type'], 'image/jpeg')
440        self.assertEqual(len(self.browser.contents), PH_LEN)
441
442    def test_after_submit_default_browsable(self):
443        # After submitting an applicant form the default image is
444        # still visible
445        self.login()
446        self.browser.open(self.edit_path)
447        self.browser.getControl("Save").click() # submit form
448        # There is a correct <img> link included
449        self.assertTrue(
450            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
451        # Browsing the link shows a real image
452        self.browser.open(self.image_url('passport.jpg'))
453        self.assertEqual(
454            self.browser.headers['content-type'], 'image/jpeg')
455        self.assertEqual(len(self.browser.contents), PH_LEN)
456
457    def test_uploaded_image_respects_file_size_restriction(self):
458        # When we upload an image that is too big ( > 10 KB) we will
459        # get an error message
460        self.login()
461        self.browser.open(self.edit_path)
462        # Create a pseudo image file and select it to be uploaded in form
463        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
464        pseudo_image = StringIO(photo_content)
465        ctrl = self.browser.getControl(name='form.passport')
466        file_ctrl = ctrl.mech_control
467        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
468        self.browser.getControl("Save").click() # submit form
469        # There is a correct <img> link included
470        self.assertTrue(
471            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
472        # We get a warning message
473        self.assertTrue(
474            'Uploaded image is too big' in self.browser.contents)
475        # Browsing the image gives us the default image, not the
476        # uploaded one.
477        self.browser.open(self.image_url('passport.jpg'))
478        self.assertEqual(
479            self.browser.headers['content-type'], 'image/jpeg')
480        self.assertEqual(len(self.browser.contents), PH_LEN)
481        # There is really no file stored for the applicant
482        img = getUtility(IExtFileStore).getFile(
483            IFileStoreNameChooser(self.applicant).chooseName())
484        self.assertTrue(img is None)
485
486    def test_uploaded_image_browsable_w_errors(self):
487        # We can upload a different image and browse it after submit,
488        # even if there are still errors in the form
489        self.login()
490        self.browser.open(self.edit_path)
491        # Create a pseudo image file and select it to be uploaded in form
492        photo_content = 'I pretend to be a graphics file'
493        pseudo_image = StringIO(photo_content)
494        ctrl = self.browser.getControl(name='form.passport')
495        file_ctrl = ctrl.mech_control
496        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
497        self.browser.getControl("Save").click() # submit form
498        # There is a correct <img> link included
499        self.assertTrue(
500            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
501        # Browsing the link shows a real image
502        self.browser.open(self.image_url('passport.jpg'))
503        self.assertEqual(
504            self.browser.headers['content-type'], 'image/jpeg')
505        self.assertEqual(self.browser.contents, photo_content)
506
507    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
508        # After uploading a new passport pic the file is correctly
509        # stored in an imagestorage
510        self.login()
511        self.browser.open(self.edit_path)
512        # Create a pseudo image file and select it to be uploaded in form
513        pseudo_image = StringIO('I pretend to be a graphics file')
514        ctrl = self.browser.getControl(name='form.passport')
515        file_ctrl = ctrl.mech_control
516        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
517        self.browser.getControl("Save").click() # submit form
518        storage = getUtility(IExtFileStore)
519        file_id = IFileStoreNameChooser(self.applicant).chooseName()
520        pseudo_image.seek(0) # reset our file data source
521        self.assertEqual(
522            storage.getFile(file_id).read(), pseudo_image.read())
523        return
524
525    def test_uploaded_image_browsable_wo_errors(self):
526        # We can upload a different image and browse it after submit,
527        # if there are no errors in form
528        self.login()
529        self.browser.open(self.edit_path)
530        self.fill_correct_values() # fill other fields with correct values
531        # Create a pseudo image file and select it to be uploaded in form
532        pseudo_image = StringIO('I pretend to be a graphics file')
533        ctrl = self.browser.getControl(name='form.passport')
534        file_ctrl = ctrl.mech_control
535        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
536        self.browser.getControl("Save").click() # submit form
537        # There is a correct <img> link included
538        self.assertTrue(
539            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
540        # Browsing the link shows a real image
541        self.browser.open(self.image_url('passport.jpg'))
542        self.assertEqual(
543            self.browser.headers['content-type'], 'image/jpeg')
544        self.assertEqual(len(self.browser.contents), 31)
545
546    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
547        # After uploading a new passport pic the file is correctly
548        # stored in an imagestorage if form contains no errors
549        self.login()
550        self.browser.open(self.edit_path)
551        self.fill_correct_values() # fill other fields with correct values
552        # Create a pseudo image file and select it to be uploaded in form
553        pseudo_image = StringIO('I pretend to be a graphics file')
554        ctrl = self.browser.getControl(name='form.passport')
555        file_ctrl = ctrl.mech_control
556        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
557        self.browser.getControl("Save").click() # submit form
558        storage = getUtility(IExtFileStore)
559        file_id = IFileStoreNameChooser(self.applicant).chooseName()
560        # The stored image can be fetched
561        fd = storage.getFile(file_id)
562        file_len = len(fd.read())
563        self.assertEqual(file_len, 31)
564
565    def test_uploaded_images_equal(self):
566        # Make sure uploaded images do really differ if we eject a
567        # change notfication (and do not if we don't)
568        self.login()
569        self.browser.open(self.edit_path)
570        self.fill_correct_values() # fill other fields with correct values
571        self.browser.getControl("Save").click() # submit form
572        # Now go on as an officer
573        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
574        self.browser.open(self.manage_path)
575
576        # Create a pseudo image file and select it to be uploaded in form
577        pseudo_image = StringIO('I pretend to be a graphics file')
578        ctrl = self.browser.getControl(name='form.passport')
579        file_ctrl = ctrl.mech_control
580        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
581        file_id = IFileStoreNameChooser(self.applicant).chooseName()
582        setSite(self.app)
583        passport0 = getUtility(IExtFileStore).getFile(file_id)
584        self.browser.getControl("Save").click() # submit form with changed pic
585        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
586        self.browser.getControl("Save").click() # submit form w/o changes
587        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
588        self.assertTrue(passport0 is None)
589        self.assertTrue(passport0 != passport1)
590        self.assertTrue(passport1 == passport2)
591        return
592
593    def test_pay_application_fee(self):
594        self.login()
595        self.browser.open(self.edit_path)
596        # Payment tickets can't be created before the form has been validated
597        self.browser.getControl("Add online payment ticket").click()
598        self.assertTrue('Required input is missing' in self.browser.contents)
599        self.fill_correct_values()
600        # We have to save the form otherwise the filled fields will be cleared
601        # after adding an online payment, because adding an online payment
602        # requires a filled form but does not save it
603        self.browser.getControl("Save").click()
604        self.browser.getControl("Add online payment ticket").click()
605        # Session object missing
606        self.assertTrue(
607            'Session configuration object is not available'
608            in self.browser.contents)
609        configuration = SessionConfiguration()
610        configuration.academic_session = 2009
611        configuration.application_fee = 200.0
612        self.app['configuration'].addSessionConfiguration(configuration)
613        self.browser.open(self.edit_path)
614        self.fill_correct_values()
615        self.browser.getControl("Add online payment ticket").click()
616        self.assertMatches('...Payment ticket created...',
617                           self.browser.contents)
618        self.assertMatches('...Activation Code...',
619                           self.browser.contents)
620        # Payment ticket can be removed if they haven't received a
621        # valid callback
622        self.browser.open(self.edit_path)
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        self.browser.open(self.edit_path)
631        ctrl = self.browser.getControl(name='val_id')
632        value = ctrl.options[0]
633        self.browser.getLink(value).click()
634        self.assertMatches('...Amount Authorized...',
635                           self.browser.contents)
636        payment_url = self.browser.url
637        # The pdf payment slip can't yet be opened
638        #self.browser.open(payment_url + '/payment_receipt.pdf')
639        #self.assertMatches('...Ticket not yet paid...',
640        #                   self.browser.contents)
641        # Request callback
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 + '/simulate_callback')
647        self.assertMatches(
648            "...Transition 'pay' requires 'started' as source state...",
649            self.browser.contents)
650        # The payment slip can be downloaded now
651        self.browser.open(payment_url)
652        self.browser.getLink("Download payment slip").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
761class ApplicantRegisterTests(ApplicantsFullSetup):
762    # Tests for applicant registration
763
764    layer = FunctionalLayer
765
766    def test_register_applicant_create(self):
767        # An applicant can register himself.
768        self.browser.open(self.container_path)
769        self.browser.getLink("Register for application").click()
770        # Fill the edit form with suitable values
771        self.browser.getControl(name="form.firstname").value = 'Anna'
772        self.browser.getControl(name="form.lastname").value = 'Kurios'
773        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
774        self.browser.getControl(name="form.phone.country").value = ['+234']
775        self.browser.getControl(name="form.phone.area").value = '555'
776        self.browser.getControl(name="form.phone.ext").value = '6666666'
777        self.browser.getControl("Get login credentials").click()
778        self.assertEqual(self.browser.url,
779            self.container_path + '/registration_complete?email=xx%40yy.zz')
780        # The new applicant can be found in the catalog via the email address
781        cat = getUtility(ICatalog, name='applicants_catalog')
782        results = list(
783            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
784        applicant = results[0]
785        self.assertEqual(applicant.lastname,'Kurios')
786        # The application_id has been copied to the reg_number
787        self.assertEqual(applicant.applicant_id, applicant.reg_number)
788        # The applicant can be found in the catalog via the reg_number
789        results = list(
790            cat.searchResults(
791            reg_number=(applicant.reg_number, applicant.reg_number)))
792        self.assertEqual(applicant,results[0])
793        return
794
795    def test_register_applicant_update(self):
796        # We change the application mode and check if applicants
797        # can find and update imported records instead of creating new records.
798        # First we check what happens if record does not exist.
799        self.applicantscontainer.mode = 'update'
800        self.browser.open(self.container_path + '/register')
801        self.browser.getControl(name="form.firstname").value = 'John'
802        self.browser.getControl(name="form.reg_number").value = 'anynumber'
803        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
804        self.browser.getControl("Get login credentials").click()
805        self.assertTrue('No application record found.'
806            in self.browser.contents)
807        # Even with the correct reg_number we can't register
808        # because firstname attribute is not set.
809        self.applicantscontainer.mode = 'update'
810        self.browser.open(self.container_path + '/register')
811        self.browser.getControl(name="form.firstname").value = 'John'
812        self.browser.getControl(name="form.reg_number").value = '1234'
813        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
814        self.browser.getControl("Get login credentials").click()
815        self.assertTrue('An error occurred.' in self.browser.contents)
816        # Let's set this attribute manually
817        # and try to register with a wrong name.
818        self.applicant.firstname = u'John'
819        self.browser.open(self.container_path + '/register')
820        self.browser.getControl(name="form.firstname").value = 'Johnny'
821        self.browser.getControl(name="form.reg_number").value = '1234'
822        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
823        self.browser.getControl("Get login credentials").click()
824        # Anonymous is not informed that firstname verification failed.
825        # It seems that the record doesn't exist.
826        self.assertTrue('No application record found.'
827            in self.browser.contents)
828        # Even with the correct firstname we can't register because
829        # password has already been set.
830        self.browser.getControl(name="form.firstname").value = 'John'
831        self.browser.getControl(name="form.reg_number").value = '1234'
832        self.browser.getControl("Get login credentials").click()
833        self.assertTrue('Your password has already been set.'
834            in self.browser.contents)
835        # We unset the password and try to register again.
836        IUserAccount(
837            self.app['applicants']['app2009'][
838            self.applicant.application_number]).context.password = None
839        self.browser.open(self.container_path + '/register')
840        # The firstname field, used for verification, is not case-sensitive.
841        self.browser.getControl(name="form.firstname").value = 'jOhn'
842        self.browser.getControl(name="form.reg_number").value = '1234'
843        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
844        self.browser.getControl("Get login credentials").click()
845        # Yeah, we succeded ...
846        self.assertTrue('Your registration was successful.'
847            in self.browser.contents)
848        # ... and  applicant can be found in the catalog via the email address
849        cat = getUtility(ICatalog, name='applicants_catalog')
850        results = list(
851            cat.searchResults(
852            email=('xx@yy.zz', 'xx@yy.zz')))
853        self.assertEqual(self.applicant,results[0])
854        return
855
856    def test_register_applicant_wo_phone(self):
857        # We don't require the phone number when registering
858        self.browser.open(self.container_path)
859        self.browser.getLink("Register for application").click()
860        # Fill the edit form with suitable values
861        self.browser.getControl(name="form.firstname").value = 'John'
862        self.browser.getControl(name="form.lastname").value = 'Tester'
863        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
864        self.browser.getControl("Get login credentials").click()
865        self.assertEqual(self.browser.url,
866            self.container_path + '/registration_complete?email=xx%40yy.zz')
867        return
868
869    def test_change_password_request(self):
870        self.browser.open('http://localhost/app/sendpw')
871        self.browser.getControl(name="form.reg_number").value = '1234'
872        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
873        self.browser.getControl("Get new login credentials").click()
874        self.assertTrue('No record found' in self.browser.contents)
875        self.applicant.email = 'aa@aa.ng'
876        # Update the catalog
877        notify(grok.ObjectModifiedEvent(self.applicant))
878        self.browser.open('http://localhost/app/sendpw')
879        self.browser.getControl(name="form.reg_number").value = '1234'
880        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
881        self.browser.getControl("Get new login credentials").click()
882        self.assertTrue(
883            'An email with your user name and password has been sent'
884            in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.