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

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

Remove Nigerian lgas from base package. LGAs are not core data.

Use the COUNTRIES instead of NATS.

  • Property svn:keywords set to Id
File size: 42.5 KB
Line 
1## $Id: test_browser.py 8069 2012-04-09 06:34:38Z 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
23import grok
24from StringIO import StringIO
25from datetime import datetime, date, timedelta
26from mechanize import LinkNotFoundError
27from zope.event import notify
28from zope.catalog.interfaces import ICatalog
29from zope.component import createObject, getUtility
30from zope.component.hooks import setSite, clearSite
31from zope.security.interfaces import Unauthorized
32from zope.testbrowser.testing import Browser
33from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
34from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
35from waeup.kofa.app import University
36from waeup.kofa.configuration import SessionConfiguration
37from waeup.kofa.applicants.container import ApplicantsContainer
38from waeup.kofa.applicants.applicant import Applicant
39from waeup.kofa.interfaces import (
40    IExtFileStore, IFileStoreNameChooser, IUserAccount)
41from waeup.kofa.university.faculty import Faculty
42from waeup.kofa.university.department import Department
43
44PH_LEN = 2059  # Length of placeholder file
45
46class ApplicantsFullSetup(FunctionalTestCase):
47    # A test case that only contains a setup and teardown
48    #
49    # Complete setup for applicants handlings is rather complex and
50    # requires lots of things created before we can start. This is a
51    # setup that does all this, creates a university, creates PINs,
52    # etc.  so that we do not have to bother with that in different
53    # test cases.
54
55    layer = FunctionalLayer
56
57    def setUp(self):
58        super(ApplicantsFullSetup, self).setUp()
59
60        # Setup a sample site for each test
61        app = University()
62        self.dc_root = tempfile.mkdtemp()
63        app['datacenter'].setStoragePath(self.dc_root)
64
65        # Prepopulate the ZODB...
66        self.getRootFolder()['app'] = app
67        # we add the site immediately after creation to the
68        # ZODB. Catalogs and other local utilities are not setup
69        # before that step.
70        self.app = self.getRootFolder()['app']
71        # Set site here. Some of the following setup code might need
72        # to access grok.getSite() and should get our new app then
73        setSite(app)
74
75        self.login_path = 'http://localhost/app/login'
76        self.root_path = 'http://localhost/app/applicants'
77        self.manage_root_path = self.root_path + '/@@manage'
78        self.add_container_path = self.root_path + '/@@add'
79        self.container_path = 'http://localhost/app/applicants/app2009'
80        self.manage_container_path = self.container_path + '/@@manage'
81
82        # Add an applicants container
83        applicantscontainer = ApplicantsContainer()
84        applicantscontainer.code = u'app2009'
85        applicantscontainer.prefix = 'app'
86        applicantscontainer.year = 2009
87        applicantscontainer.entry_level = 100
88        applicantscontainer.application_category = 'basic'
89        applicantscontainer.mode = 'create'
90        delta = timedelta(days=10)
91        applicantscontainer.startdate = date.today() - delta
92        applicantscontainer.enddate = date.today() + 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 = 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.entry_level").value = ['100']
253        self.browser.getControl(name="form.mode").value = ['create']
254        self.browser.getControl(
255            name="form.application_category").value = ['basic']
256        self.browser.getControl("Add applicants container").click()
257        self.assertTrue('Added:' in self.browser.contents)
258        self.browser.getLink("app2010").click()
259        self.assertTrue('<h1>General Studies 2010/2011</h1>'
260            in self.browser.contents)
261        self.browser.open(self.add_container_path)
262        self.browser.getControl("Cancel").click()
263        self.assertEqual(self.browser.url, self.manage_root_path)
264        self.browser.open(self.add_container_path)
265        self.browser.getControl(name="form.prefix").value = ['app']
266        self.browser.getControl(name="form.year").value = ['2010']
267        self.browser.getControl(name="form.entry_level").value = ['100']
268        self.browser.getControl(name="form.mode").value = ['create']
269        self.browser.getControl(
270            name="form.application_category").value = ['basic']
271        self.browser.getControl("Add applicants container").click()
272        self.assertTrue('exists already in the database'
273                        in self.browser.contents)
274        self.browser.open(self.manage_root_path)
275        ctrl = self.browser.getControl(name='val_id')
276        ctrl.getControl(value='app2010').selected = True
277        self.browser.getControl("Remove selected", index=0).click()
278        self.assertTrue('Successfully removed:' in self.browser.contents)
279        self.browser.open(self.add_container_path)
280        self.browser.getControl(name="form.prefix").value = ['app']
281        self.browser.getControl(name="form.year").value = ['2010']
282        self.browser.getControl(name="form.entry_level").value = ['100']
283        self.browser.getControl(name="form.mode").value = ['create']
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 + '/simulate_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
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.