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

Last change on this file since 8057 was 8048, checked in by uli, 13 years ago

No school grades, no tests for it.

  • Property svn:keywords set to Id
File size: 42.6 KB
Line 
1## $Id: test_browser.py 8048 2012-04-05 14:51:27Z uli $
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.lga").value = ['foreigner']
160        self.browser.getControl(name="form.sex").value = ['m']
161        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
162
163    def tearDown(self):
164        super(ApplicantsFullSetup, self).tearDown()
165        clearSite()
166        shutil.rmtree(self.dc_root)
167
168class ApplicantsRootUITests(ApplicantsFullSetup):
169    # Tests for ApplicantsRoot class
170
171    layer = FunctionalLayer
172
173    def test_anonymous_access(self):
174        # Anonymous users can access applicants root
175        self.browser.open(self.root_path)
176        self.assertEqual(self.browser.headers['Status'], '200 Ok')
177        self.assertFalse(
178            'Manage ' in self.browser.contents)
179        return
180
181    def test_anonymous_no_actions(self):
182        # Make sure anonymous users cannot access actions
183        self.browser.open(self.root_path)
184        self.assertRaises(
185            LookupError, self.browser.getControl, "Add local role")
186        # Manage screen neither linked nor accessible for anonymous
187        self.assertRaises(
188            LinkNotFoundError,
189            self.browser.getLink, 'Manage application section')
190        self.assertRaises(
191            Unauthorized, self.browser.open, self.manage_root_path)
192        # Add container screen not accessible for anonymous
193        self.assertRaises(
194            Unauthorized, self.browser.open, self.add_container_path)
195        return
196
197    def test_manage_access(self):
198        # Managers can access the manage pages of applicants root
199        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
200        self.browser.open(self.root_path)
201        self.assertTrue('Manage application section' in self.browser.contents)
202        # There is a manage link
203        link = self.browser.getLink('Manage application section')
204        link.click()
205        self.assertEqual(self.browser.headers['Status'], '200 Ok')
206        self.assertEqual(self.browser.url, self.manage_root_path)
207        return
208
209    def test_manage_actions_access(self):
210        # Managers can access the action on manage screen
211        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
212        self.browser.open(self.manage_root_path)
213        self.browser.getControl("Add local role").click()
214        self.assertTrue('No user selected' in self.browser.contents)
215        return
216
217    # We have no local roles yet
218    #def test_local_roles_add_delete(self):
219    #    # Managers can assign and delete local roles of applicants root
220    #    myusers = self.app['users']
221    #    myusers.addUser('bob', 'bobssecret')
222    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
223    #    self.browser.open(self.manage_root_path)
224    #    self.browser.getControl(name="user").value = ['bob']
225    #    self.browser.getControl(name="local_role").value = [
226    #        'waeup.local.ApplicationsOfficer']
227    #    self.browser.getControl("Add local role").click()
228    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
229    #    # Remove the role assigned
230    #    ctrl = self.browser.getControl(name='role_id')
231    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
232    #    self.browser.getControl("Remove selected local roles").click()
233    #    self.assertTrue('Successfully removed:' in self.browser.contents)
234    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
235    #    return
236
237    def test_add_delete_container(self):
238        # Managers can add and delete applicants containers
239        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
240        self.browser.open(self.manage_root_path)
241        self.browser.getControl("Cancel").click()
242        self.assertEqual(self.browser.url, self.root_path)
243        self.browser.open(self.manage_root_path)
244        self.browser.getControl("Add applicants container").click()
245        self.assertEqual(self.browser.headers['Status'], '200 Ok')
246        self.assertEqual(self.browser.url, self.add_container_path)
247        self.browser.getControl(name="form.prefix").value = ['app']
248        self.browser.getControl("Add applicants container").click()
249        self.assertTrue(
250            'There were errors' in self.browser.contents)
251        self.browser.getControl(name="form.prefix").value = ['app']
252        self.browser.getControl(name="form.year").value = ['2010']
253        self.browser.getControl(name="form.entry_level").value = ['100']
254        self.browser.getControl(name="form.mode").value = ['create']
255        self.browser.getControl(
256            name="form.application_category").value = ['basic']
257        self.browser.getControl("Add applicants container").click()
258        self.assertTrue('Added:' in self.browser.contents)
259        self.browser.getLink("app2010").click()
260        self.assertTrue('<h1>General Studies 2010/2011</h1>'
261            in self.browser.contents)
262        self.browser.open(self.add_container_path)
263        self.browser.getControl("Cancel").click()
264        self.assertEqual(self.browser.url, self.manage_root_path)
265        self.browser.open(self.add_container_path)
266        self.browser.getControl(name="form.prefix").value = ['app']
267        self.browser.getControl(name="form.year").value = ['2010']
268        self.browser.getControl(name="form.entry_level").value = ['100']
269        self.browser.getControl(name="form.mode").value = ['create']
270        self.browser.getControl(
271            name="form.application_category").value = ['basic']
272        self.browser.getControl("Add applicants container").click()
273        self.assertTrue('exists already in the database'
274                        in self.browser.contents)
275        self.browser.open(self.manage_root_path)
276        ctrl = self.browser.getControl(name='val_id')
277        ctrl.getControl(value='app2010').selected = True
278        self.browser.getControl("Remove selected", index=0).click()
279        self.assertTrue('Successfully removed:' in self.browser.contents)
280        self.browser.open(self.add_container_path)
281        self.browser.getControl(name="form.prefix").value = ['app']
282        self.browser.getControl(name="form.year").value = ['2010']
283        self.browser.getControl(name="form.entry_level").value = ['100']
284        self.browser.getControl(name="form.mode").value = ['create']
285        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
286        self.browser.getControl(
287            name="form.application_category").value = ['basic']
288        self.browser.getControl("Add applicants container").click()
289        del self.app['applicants']['app2010']
290        ctrl = self.browser.getControl(name='val_id')
291        ctrl.getControl(value='app2010').selected = True
292        self.browser.getControl("Remove selected", index=0).click()
293        self.assertMatches('...Could not delete...', self.browser.contents)
294        return
295
296class ApplicantsContainerUITests(ApplicantsFullSetup):
297    # Tests for ApplicantsContainer class views and pages
298
299    layer = FunctionalLayer
300
301    def test_anonymous_access(self):
302        # Anonymous users can access applicants containers
303        self.browser.open(self.container_path)
304        self.assertEqual(self.browser.headers['Status'], '200 Ok')
305        self.assertFalse(
306            'Manage ' in self.browser.contents)
307        return
308
309    def test_manage_access(self):
310        # Managers can access the manage pages of applicants
311        # containers and can perform actions
312        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
313        self.browser.open(self.manage_container_path)
314        self.assertEqual(self.browser.headers['Status'], '200 Ok')
315        self.assertEqual(self.browser.url, self.manage_container_path)
316        self.browser.getControl("Save").click()
317        self.assertTrue('Form has been saved' in self.browser.contents)
318        self.browser.getControl("Remove selected", index=0).click()
319        self.assertTrue('No applicant selected' in self.browser.contents)
320        self.browser.getControl("Add local role").click()
321        self.assertTrue('No user selected' in self.browser.contents)
322        self.browser.getControl("Cancel", index=0).click()
323        self.assertEqual(self.browser.url, self.container_path)
324        return
325
326    def test_add_delete_applicants(self):
327        # Managers can add and delete applicants
328        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
329        self.add_applicant_path = self.container_path + '/addapplicant'
330        self.container_manage_path = self.container_path + '/@@manage'
331        self.browser.open(self.container_manage_path)
332        self.browser.getControl("Add applicant").click()
333        self.assertEqual(self.browser.headers['Status'], '200 Ok')
334        self.assertEqual(self.browser.url, self.add_applicant_path)
335        self.browser.getControl(name="form.firstname").value = 'Alois'
336        self.browser.getControl(name="form.middlename").value = 'Kofi'
337        self.browser.getControl(name="form.lastname").value = 'Bettermann'
338        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
339        self.browser.getControl("Create application record").click()
340        self.assertTrue('Application initialized' in self.browser.contents)
341        self.browser.open(self.container_manage_path)
342        self.assertEqual(self.browser.headers['Status'], '200 Ok')
343        ctrl = self.browser.getControl(name='val_id')
344        value = ctrl.options[0]
345        ctrl.getControl(value=value).selected = True
346        self.browser.getControl("Remove selected", index=0).click()
347        self.assertTrue('Successfully removed:' in self.browser.contents)
348        self.browser.open(self.add_applicant_path)
349        self.browser.getControl(name="form.firstname").value = 'Albert'
350        self.browser.getControl(name="form.lastname").value = 'Einstein'
351        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
352        self.browser.getControl("Create application record").click()
353        self.assertTrue('Application initialized' in self.browser.contents)
354        return
355
356class ApplicantUITests(ApplicantsFullSetup):
357    # Tests for uploading/browsing the passport image of appplicants
358
359    layer = FunctionalLayer
360
361    def test_manage_and_view_applicant(self):
362        # Managers can manage applicants
363        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
364        self.slip_path = self.view_path + '/application_slip.pdf'
365        self.browser.open(self.manage_path)
366        self.assertEqual(self.browser.headers['Status'], '200 Ok')
367        self.fill_correct_values()
368        # Fire transition
369        self.browser.getControl(name="transition").value = ['start']
370        self.browser.getControl("Save").click()
371        # Be sure that the empty phone field does not show wrong error message
372        self.assertFalse('Required input is missing' in self.browser.contents)
373        self.assertMatches('...Form has been saved...', self.browser.contents)
374        self.assertMatches('...Application started by Manager...',
375                           self.browser.contents)
376        self.browser.open(self.view_path)
377        self.assertEqual(self.browser.headers['Status'], '200 Ok')
378        # Change course_admitted
379        self.browser.open(self.manage_path)
380        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
381        self.browser.getControl("Save").click()
382        self.assertMatches('...Form has been saved...', self.browser.contents)
383        # Change password
384        self.browser.getControl(name="password").value = 'secret'
385        self.browser.getControl(name="control_password").value = 'secre'
386        self.browser.getControl("Save").click()
387        self.assertMatches('...Passwords do not match...',
388                           self.browser.contents)
389        self.browser.getControl(name="password").value = 'secret'
390        self.browser.getControl(name="control_password").value = 'secret'
391        self.browser.getControl("Save").click()
392        self.assertMatches('...Form has been saved...', self.browser.contents)
393        # Open pdf slip
394        self.browser.open(self.slip_path)
395        self.assertEqual(self.browser.headers['Status'], '200 Ok')
396        self.assertEqual(self.browser.headers['Content-Type'],
397                         'application/pdf')
398        # Managers can view applicants even if certificate has been removed
399        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
400        self.browser.open(self.view_path)
401        self.assertEqual(self.browser.headers['Status'], '200 Ok')
402        self.browser.open(self.slip_path)
403        self.assertEqual(self.browser.headers['Status'], '200 Ok')
404        return
405
406    def test_passport_edit_view(self):
407        # We get a default image after login
408        self.browser.open(self.login_path)
409        self.login()
410        self.browser.open(self.browser.url + '/passport.jpg')
411        self.assertEqual(self.browser.headers['status'], '200 Ok')
412        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
413        self.assertTrue('JFIF' in self.browser.contents)
414        self.assertEqual(
415            self.browser.headers['content-length'], str(PH_LEN))
416
417    def test_edit_applicant(self):
418        # Applicants can edit their record
419        self.browser.open(self.login_path)
420        self.login()
421        self.browser.open(self.edit_path)
422        self.assertTrue(self.browser.url != self.login_path)
423        self.assertEqual(self.browser.headers['Status'], '200 Ok')
424        self.fill_correct_values()
425        self.browser.getControl("Save").click()
426        self.assertMatches('...Form has been saved...', self.browser.contents)
427        return
428
429    def image_url(self, filename):
430        return self.edit_path.replace('edit', filename)
431
432    def test_after_login_default_browsable(self):
433        # After login we see the placeholder image in the edit view
434        self.login()
435        self.assertEqual(self.browser.url, self.view_path)
436        self.browser.open(self.edit_path)
437        # There is a correct <img> link included
438        self.assertTrue(
439              '<img src="passport.jpg" />' in self.browser.contents)
440        # Browsing the link shows a real image
441        self.browser.open(self.image_url('passport.jpg'))
442        self.assertEqual(
443            self.browser.headers['content-type'], 'image/jpeg')
444        self.assertEqual(len(self.browser.contents), PH_LEN)
445
446    def test_after_submit_default_browsable(self):
447        # After submitting an applicant form the default image is
448        # still visible
449        self.login()
450        self.browser.open(self.edit_path)
451        self.browser.getControl("Save").click() # submit form
452        # There is a correct <img> link included
453        self.assertTrue(
454            '<img src="passport.jpg" />' in self.browser.contents)
455        # Browsing the link shows a real image
456        self.browser.open(self.image_url('passport.jpg'))
457        self.assertEqual(
458            self.browser.headers['content-type'], 'image/jpeg')
459        self.assertEqual(len(self.browser.contents), PH_LEN)
460
461    def test_uploaded_image_respects_file_size_restriction(self):
462        # When we upload an image that is too big ( > 10 KB) we will
463        # get an error message
464        self.login()
465        self.browser.open(self.edit_path)
466        # Create a pseudo image file and select it to be uploaded in form
467        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
468        pseudo_image = StringIO(photo_content)
469        ctrl = self.browser.getControl(name='form.passport')
470        file_ctrl = ctrl.mech_control
471        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
472        self.browser.getControl("Save").click() # submit form
473        # There is a correct <img> link included
474        self.assertTrue(
475            '<img src="passport.jpg" />' in self.browser.contents)
476        # We get a warning message
477        self.assertTrue(
478            'Uploaded image is too big' in self.browser.contents)
479        # Browsing the image gives us the default image, not the
480        # uploaded one.
481        self.browser.open(self.image_url('passport.jpg'))
482        self.assertEqual(
483            self.browser.headers['content-type'], 'image/jpeg')
484        self.assertEqual(len(self.browser.contents), PH_LEN)
485        # There is really no file stored for the applicant
486        img = getUtility(IExtFileStore).getFile(
487            IFileStoreNameChooser(self.applicant).chooseName())
488        self.assertTrue(img is None)
489
490    def test_uploaded_image_browsable_w_errors(self):
491        # We can upload a different image and browse it after submit,
492        # even if there are still errors in the form
493        self.login()
494        self.browser.open(self.edit_path)
495        # Create a pseudo image file and select it to be uploaded in form
496        photo_content = 'I pretend to be a graphics file'
497        pseudo_image = StringIO(photo_content)
498        ctrl = self.browser.getControl(name='form.passport')
499        file_ctrl = ctrl.mech_control
500        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
501        self.browser.getControl("Save").click() # submit form
502        # There is a correct <img> link included
503        self.assertTrue(
504            '<img src="passport.jpg" />' in self.browser.contents)
505        # Browsing the link shows a real image
506        self.browser.open(self.image_url('passport.jpg'))
507        self.assertEqual(
508            self.browser.headers['content-type'], 'image/jpeg')
509        self.assertEqual(self.browser.contents, photo_content)
510
511    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
512        # After uploading a new passport pic the file is correctly
513        # stored in an imagestorage
514        self.login()
515        self.browser.open(self.edit_path)
516        # Create a pseudo image file and select it to be uploaded in form
517        pseudo_image = StringIO('I pretend to be a graphics file')
518        ctrl = self.browser.getControl(name='form.passport')
519        file_ctrl = ctrl.mech_control
520        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
521        self.browser.getControl("Save").click() # submit form
522        storage = getUtility(IExtFileStore)
523        file_id = IFileStoreNameChooser(self.applicant).chooseName()
524        pseudo_image.seek(0) # reset our file data source
525        self.assertEqual(
526            storage.getFile(file_id).read(), pseudo_image.read())
527        return
528
529    def test_uploaded_image_browsable_wo_errors(self):
530        # We can upload a different image and browse it after submit,
531        # if there are no errors in form
532        self.login()
533        self.browser.open(self.edit_path)
534        self.fill_correct_values() # fill other fields with correct values
535        # Create a pseudo image file and select it to be uploaded in form
536        pseudo_image = StringIO('I pretend to be a graphics file')
537        ctrl = self.browser.getControl(name='form.passport')
538        file_ctrl = ctrl.mech_control
539        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
540        self.browser.getControl("Save").click() # submit form
541        # There is a correct <img> link included
542        self.assertTrue(
543            '<img src="passport.jpg" />' in self.browser.contents)
544        # Browsing the link shows a real image
545        self.browser.open(self.image_url('passport.jpg'))
546        self.assertEqual(
547            self.browser.headers['content-type'], 'image/jpeg')
548        self.assertEqual(len(self.browser.contents), 31)
549
550    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
551        # After uploading a new passport pic the file is correctly
552        # stored in an imagestorage if form contains no errors
553        self.login()
554        self.browser.open(self.edit_path)
555        self.fill_correct_values() # fill other fields with correct values
556        # Create a pseudo image file and select it to be uploaded in form
557        pseudo_image = StringIO('I pretend to be a graphics file')
558        ctrl = self.browser.getControl(name='form.passport')
559        file_ctrl = ctrl.mech_control
560        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
561        self.browser.getControl("Save").click() # submit form
562        storage = getUtility(IExtFileStore)
563        file_id = IFileStoreNameChooser(self.applicant).chooseName()
564        # The stored image can be fetched
565        fd = storage.getFile(file_id)
566        file_len = len(fd.read())
567        self.assertEqual(file_len, 31)
568
569    def test_uploaded_images_equal(self):
570        # Make sure uploaded images do really differ if we eject a
571        # change notfication (and do not if we don't)
572        self.login()
573        self.browser.open(self.edit_path)
574        self.fill_correct_values() # fill other fields with correct values
575        self.browser.getControl("Save").click() # submit form
576        # Now go on as an officer
577        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
578        self.browser.open(self.manage_path)
579
580        # Create a pseudo image file and select it to be uploaded in form
581        pseudo_image = StringIO('I pretend to be a graphics file')
582        ctrl = self.browser.getControl(name='form.passport')
583        file_ctrl = ctrl.mech_control
584        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
585        file_id = IFileStoreNameChooser(self.applicant).chooseName()
586        setSite(self.app)
587        passport0 = getUtility(IExtFileStore).getFile(file_id)
588        self.browser.getControl("Save").click() # submit form with changed pic
589        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
590        self.browser.getControl("Save").click() # submit form w/o changes
591        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
592        self.assertTrue(passport0 is None)
593        self.assertTrue(passport0 != passport1)
594        self.assertTrue(passport1 == passport2)
595        return
596
597    def test_pay_acceptance_fee(self):
598        self.login()
599        self.browser.open(self.edit_path)
600        # Payment tickets can't be created before the form has been validated
601        self.browser.getControl("Add online payment ticket").click()
602        self.assertTrue('Required input is missing' in self.browser.contents)
603        self.fill_correct_values()
604        # We have to save the form otherwise the filled fields will be cleared
605        # after adding an online payment, because adding an online payment
606        # requires a filled form but does not save it
607        self.browser.getControl("Save").click()
608        self.browser.getControl("Add online payment ticket").click()
609        # Session object missing
610        self.assertTrue(
611            'Session configuration object is not available'
612            in self.browser.contents)
613        configuration = SessionConfiguration()
614        configuration.academic_session = 2009
615        configuration.acceptance_fee = 200.0
616        self.app['configuration'].addSessionConfiguration(configuration)
617        self.browser.open(self.edit_path)
618        self.fill_correct_values()
619        self.browser.getControl("Add online payment ticket").click()
620        self.assertMatches('...Payment ticket created...',
621                           self.browser.contents)
622        # Payment ticket can be removed if they haven't received a
623        # valid callback
624        ctrl = self.browser.getControl(name='val_id')
625        value = ctrl.options[0]
626        ctrl.getControl(value=value).selected = True
627        self.browser.getControl("Remove selected", index=0).click()
628        self.assertMatches('...Successfully removed...', self.browser.contents)
629        # We will try the callback request view
630        self.browser.getControl("Add online payment ticket").click()
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 receipt 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.open(payment_url)
643        self.browser.getLink("Request callback").click()
644        self.assertMatches('...Valid callback received...',
645                          self.browser.contents)
646        # Callback can't be applied twice
647        self.browser.open(payment_url + '/simulate_callback')
648        self.assertMatches(
649            "...Transition 'pay' requires 'started' as source state...",
650            self.browser.contents)
651        # The payment receipt can be downloaded now
652        self.browser.open(payment_url)
653        self.browser.getLink("Download payment receipt").click()
654        self.assertEqual(self.browser.headers['Status'], '200 Ok')
655        self.assertEqual(self.browser.headers['Content-Type'],
656                         'application/pdf')
657        # Applicant is is in state 'paid'
658        self.browser.open(self.view_path)
659        self.assertMatches('...paid...',
660                           self.browser.contents)
661        state = IWorkflowState(self.applicant).getState()
662        self.assertTrue(state == 'paid')
663
664    def test_final_submit(self):
665        # Make sure that a correctly filled form with passport picture
666        # can be submitted (only) after payment
667        self.login()
668        self.browser.getLink("Edit application record").click()
669        self.assertFalse('Final Submit' in self.browser.contents)
670        IWorkflowInfo(self.applicant).fireTransition('pay')
671        self.browser.open(self.edit_path)
672        self.assertTrue('Final Submit' in self.browser.contents)
673        self.fill_correct_values() # fill other fields with correct values
674        self.browser.getControl("Final Submit").click()
675        # We forgot to upload a passport picture
676        self.assertTrue(
677            'No passport picture uploaded' in self.browser.contents)
678        # Create a pseudo image file and select it to be uploaded in form
679        pseudo_image = StringIO('I pretend to be a graphics file')
680        ctrl = self.browser.getControl(name='form.passport')
681        file_ctrl = ctrl.mech_control
682        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
683        self.browser.getControl("Final Submit").click() # (finally) submit form
684        # The picture has been uploaded but the form cannot be submitted
685        # since the passport confirmation box was not ticked
686        self.assertTrue(
687            'Passport picture confirmation box not ticked'
688            in self.browser.contents)
689        self.browser.getControl(name="confirm_passport").value = True
690        self.browser.getControl("Final Submit").click()
691        self.assertTrue(
692            '... submitted ...' in self.browser.contents)
693        self.browser.goBack(count=1)
694        self.browser.getControl("Save").click()
695        self.assertTrue(
696            'The requested form is locked' in self.browser.contents)
697        self.browser.goBack(count=1)
698        self.browser.getControl("Final Submit").click()
699        self.assertTrue(
700            'The requested form is locked' in self.browser.contents)
701        return
702
703    def test_locking(self):
704        # Make sure that locked forms can't be submitted
705        self.login()
706        self.browser.open(self.edit_path)
707        self.fill_correct_values() # fill other fields with correct values
708        # Create a pseudo image file and select it to be uploaded in form
709        pseudo_image = StringIO('I pretend to be a graphics file')
710        ctrl = self.browser.getControl(name='form.passport')
711        file_ctrl = ctrl.mech_control
712        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
713        self.browser.getControl("Save").click()
714        # Now we lock the form
715        self.applicant.locked = True
716        self.browser.open(self.edit_path)
717        self.assertEqual(self.browser.headers['Status'], '200 Ok')
718        self.assertTrue(
719            'The requested form is locked' in self.browser.contents)
720        return
721
722    def test_certificate_removed(self):
723        self.login()
724        self.browser.open(self.edit_path)
725        self.fill_correct_values()
726        self.browser.getControl("Save").click()
727        self.browser.open(self.view_path)
728        self.assertTrue(
729            'Unnamed Certificate' in self.browser.contents)
730        self.browser.open(self.edit_path)
731        self.assertTrue(
732            '<option selected="selected" value="CERT1">' in self.browser.contents)
733        # Now we remove the certificate
734        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
735        # The certificate is still shown in display mode
736        self.browser.open(self.view_path)
737        self.assertTrue(
738            'Unnamed Certificate' in self.browser.contents)
739        # The certificate is still selectable in edit mode so that it won't
740        # be automatically replaced by another (arbitrary) certificate
741        self.browser.open(self.edit_path)
742        self.assertTrue(
743            '<option selected="selected" value="CERT1">' in self.browser.contents)
744        # Consequently, the certificate is still shown after saving the form
745        self.browser.getControl("Save").click()
746        self.browser.open(self.view_path)
747        self.assertTrue(
748            'Unnamed Certificate' in self.browser.contents)
749        # Even if we add a new certificate the previous (removed)
750        # certificate is shown
751        certificate = createObject('waeup.Certificate')
752        certificate.code = 'CERT2'
753        certificate.title = 'New Certificate'
754        certificate.application_category = 'basic'
755        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
756            certificate)
757        self.browser.open(self.edit_path)
758        self.assertTrue(
759            '<option selected="selected" value="CERT1">'
760            in self.browser.contents)
761
762class ApplicantRegisterTests(ApplicantsFullSetup):
763    # Tests for applicant registration
764
765    layer = FunctionalLayer
766
767    def test_register_applicant_create(self):
768        # An applicant can register himself.
769        self.browser.open(self.container_path)
770        self.browser.getLink("Register for application").click()
771        # Fill the edit form with suitable values
772        self.browser.getControl(name="form.firstname").value = 'Anna'
773        self.browser.getControl(name="form.lastname").value = 'Kurios'
774        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
775        self.browser.getControl(name="form.phone.country").value = ['+234']
776        self.browser.getControl(name="form.phone.area").value = '555'
777        self.browser.getControl(name="form.phone.ext").value = '6666666'
778        self.browser.getControl("Get login credentials").click()
779        self.assertEqual(self.browser.url,
780            self.container_path + '/registration_complete?email=xx%40yy.zz')
781        # The new applicant can be found in the catalog via the email address
782        cat = getUtility(ICatalog, name='applicants_catalog')
783        results = list(
784            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
785        applicant = results[0]
786        self.assertEqual(applicant.lastname,'Kurios')
787        # The application_id has been copied to the reg_number
788        self.assertEqual(applicant.applicant_id, applicant.reg_number)
789        # The applicant can be found in the catalog via the reg_number
790        results = list(
791            cat.searchResults(
792            reg_number=(applicant.reg_number, applicant.reg_number)))
793        self.assertEqual(applicant,results[0])
794        return
795
796    def test_register_applicant_update(self):
797        # We change the application mode and check if applicants
798        # can find and update imported records instead of creating new records.
799        # First we check what happens if record does not exist.
800        self.applicantscontainer.mode = 'update'
801        self.browser.open(self.container_path + '/register')
802        self.browser.getControl(name="form.firstname").value = 'John'
803        self.browser.getControl(name="form.reg_number").value = 'anynumber'
804        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
805        self.browser.getControl("Get login credentials").click()
806        self.assertTrue('No application record found.'
807            in self.browser.contents)
808        # Even with the correct reg_number we can't register
809        # because firstname attribute is not set.
810        self.applicantscontainer.mode = 'update'
811        self.browser.open(self.container_path + '/register')
812        self.browser.getControl(name="form.firstname").value = 'John'
813        self.browser.getControl(name="form.reg_number").value = '1234'
814        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
815        self.browser.getControl("Get login credentials").click()
816        self.assertTrue('An error occurred.' in self.browser.contents)
817        # Let's set this attribute manually
818        # and try to register with a wrong name.
819        self.applicant.firstname = u'John'
820        self.browser.open(self.container_path + '/register')
821        self.browser.getControl(name="form.firstname").value = 'Johnny'
822        self.browser.getControl(name="form.reg_number").value = '1234'
823        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
824        self.browser.getControl("Get login credentials").click()
825        # Anonymous is not informed that firstname verification failed.
826        # It seems that the record doesn't exist.
827        self.assertTrue('No application record found.'
828            in self.browser.contents)
829        # Even with the correct firstname we can't register because
830        # password has already been set.
831        self.browser.getControl(name="form.firstname").value = 'John'
832        self.browser.getControl(name="form.reg_number").value = '1234'
833        self.browser.getControl("Get login credentials").click()
834        self.assertTrue('Your password has already been set.'
835            in self.browser.contents)
836        # We unset the password and try to register again.
837        IUserAccount(
838            self.app['applicants']['app2009'][
839            self.applicant.application_number]).context.password = None
840        self.browser.open(self.container_path + '/register')
841        # The firstname field, used for verification, is not case-sensitive.
842        self.browser.getControl(name="form.firstname").value = 'jOhn'
843        self.browser.getControl(name="form.reg_number").value = '1234'
844        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
845        self.browser.getControl("Get login credentials").click()
846        # Yeah, we succeded ...
847        self.assertTrue('Your registration was successful.'
848            in self.browser.contents)
849        # ... and  applicant can be found in the catalog via the email address
850        cat = getUtility(ICatalog, name='applicants_catalog')
851        results = list(
852            cat.searchResults(
853            email=('xx@yy.zz', 'xx@yy.zz')))
854        self.assertEqual(self.applicant,results[0])
855        return
856
857    def test_register_applicant_wo_phone(self):
858        # We don't require the phone number when registering
859        self.browser.open(self.container_path)
860        self.browser.getLink("Register for application").click()
861        # Fill the edit form with suitable values
862        self.browser.getControl(name="form.firstname").value = 'John'
863        self.browser.getControl(name="form.lastname").value = 'Tester'
864        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
865        self.browser.getControl("Get login credentials").click()
866        self.assertEqual(self.browser.url,
867            self.container_path + '/registration_complete?email=xx%40yy.zz')
868        return
869
870    def test_change_password_request(self):
871        self.browser.open('http://localhost/app/sendpw')
872        self.browser.getControl(name="form.reg_number").value = '1234'
873        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
874        self.browser.getControl("Get new login credentials").click()
875        self.assertTrue('No record found' in self.browser.contents)
876        self.applicant.email = 'aa@aa.ng'
877        # Update the catalog
878        notify(grok.ObjectModifiedEvent(self.applicant))
879        self.browser.open('http://localhost/app/sendpw')
880        self.browser.getControl(name="form.reg_number").value = '1234'
881        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
882        self.browser.getControl("Get new login credentials").click()
883        self.assertTrue(
884            'An email with your user name and password has been sent'
885            in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.