source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/tests/test_browser.py @ 7372

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

Fix tests.

  • Property svn:keywords set to Id
File size: 33.5 KB
Line 
1## $Id: test_browser.py 7372 2011-12-18 10:50:21Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19Test the applicant-related UI components.
20"""
21import shutil
22import tempfile
23from StringIO import StringIO
24from datetime import datetime, date, timedelta
25from mechanize import LinkNotFoundError
26from zope.component import createObject, getUtility
27from zope.component.hooks import setSite, clearSite
28from zope.security.interfaces import Unauthorized
29from zope.testbrowser.testing import Browser
30from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
31from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
32from waeup.sirp.app import University
33from waeup.sirp.configuration import SessionConfiguration
34from waeup.sirp.applicants.container import ApplicantsContainer
35from waeup.sirp.applicants.applicant import Applicant
36from waeup.sirp.interfaces import (
37    IExtFileStore, IFileStoreNameChooser, IUserAccount)
38from waeup.sirp.university.faculty import Faculty
39from waeup.sirp.university.department import Department
40
41PH_LEN = 2059  # Length of placeholder file
42
43class ApplicantsFullSetup(FunctionalTestCase):
44    # A test case that only contains a setup and teardown
45    #
46    # Complete setup for applicants handlings is rather complex and
47    # requires lots of things created before we can start. This is a
48    # setup that does all this, creates a university, creates PINs,
49    # etc.  so that we do not have to bother with that in different
50    # test cases.
51
52    layer = FunctionalLayer
53
54    def setUp(self):
55        super(ApplicantsFullSetup, self).setUp()
56
57        # Setup a sample site for each test
58        app = University()
59        self.dc_root = tempfile.mkdtemp()
60        app['datacenter'].setStoragePath(self.dc_root)
61
62        # Prepopulate the ZODB...
63        self.getRootFolder()['app'] = app
64        # we add the site immediately after creation to the
65        # ZODB. Catalogs and other local utilities are not setup
66        # before that step.
67        self.app = self.getRootFolder()['app']
68        # Set site here. Some of the following setup code might need
69        # to access grok.getSite() and should get our new app then
70        setSite(app)
71
72        self.login_path = 'http://localhost/app/login'
73        self.root_path = 'http://localhost/app/applicants'
74        self.manage_root_path = self.root_path + '/@@manage'
75        self.add_container_path = self.root_path + '/@@add'
76        self.container_path = 'http://localhost/app/applicants/app2009'
77        self.manage_container_path = self.container_path + '/@@manage'
78
79        # Add an applicants container
80        applicantscontainer = ApplicantsContainer()
81        applicantscontainer.ac_prefix = 'APP'
82        applicantscontainer.code = u'app2009'
83        applicantscontainer.prefix = 'app'
84        applicantscontainer.year = 2009
85        applicantscontainer.application_category = 'basic'
86        delta = timedelta(days=10)
87        applicantscontainer.startdate = date.today() - delta
88        applicantscontainer.enddate = date.today() + delta
89        self.app['applicants']['app2009'] = applicantscontainer
90        self.applicantscontainer = self.app['applicants']['app2009']
91
92        # Populate university
93        certificate = createObject('waeup.Certificate')
94        certificate.code = 'CERT1'
95        certificate.application_category = 'basic'
96        self.certificate = certificate
97        self.app['faculties']['fac1'] = Faculty()
98        self.app['faculties']['fac1']['dep1'] = Department()
99        self.department = self.app['faculties']['fac1']['dep1']
100        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
101            certificate)
102
103        # Put the prepopulated site into test ZODB and prepare test
104        # browser
105        self.browser = Browser()
106        self.browser.handleErrors = False
107
108        # Create 5 access codes with prefix'FOO' and cost 9.99 each
109        pin_container = self.app['accesscodes']
110        pin_container.createBatch(
111            datetime.now(), 'some_userid', 'APP', 9.99, 5)
112        pins = pin_container[pin_container.keys()[0]].values()
113        self.pins = [x.representation for x in pins]
114        self.existing_pin = self.pins[0]
115        parts = self.existing_pin.split('-')[1:]
116        self.existing_series, self.existing_number = parts
117
118        # Add an applicant
119        self.applicant = Applicant()
120        # reg_number is the only field which has to be preset here
121        # because managers are allowed to edit this required field
122        self.applicant.reg_number = u'1234'
123        app['applicants']['app2009'].addApplicant(self.applicant)
124        IUserAccount(
125            self.app['applicants']['app2009'][
126            self.applicant.application_number]).setPassword('apwd')
127        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
128            'app2009', self.applicant.application_number, 'manage')
129        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
130            'app2009', self.applicant.application_number, 'edit')
131        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
132            'app2009', self.applicant.application_number)
133
134    def login(self):
135        # Perform an applicant login. This creates an applicant record.
136        #
137        # This helper also sets `self.applicant`, which is the
138        # applicant object created.
139        self.browser.open(self.login_path)
140        self.browser.getControl(name="form.login").value = self.applicant.applicant_id
141        self.browser.getControl(name="form.password").value = 'apwd'
142        self.browser.getControl("Login").click()
143
144    def fill_correct_values(self):
145        # Fill the edit form with suitable values
146        self.browser.getControl(name="form.firstname").value = 'John'
147        self.browser.getControl(name="form.lastname").value = 'Tester'
148        self.browser.getControl(name="form.course1").value = ['CERT1']
149        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
150        self.browser.getControl(name="form.lga").value = ['foreigner']
151        self.browser.getControl(name="form.sex").value = ['m']
152        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
153
154    def tearDown(self):
155        super(ApplicantsFullSetup, self).tearDown()
156        clearSite()
157        shutil.rmtree(self.dc_root)
158
159class ApplicantsRootUITests(ApplicantsFullSetup):
160    # Tests for ApplicantsRoot class
161
162    layer = FunctionalLayer
163
164    def test_anonymous_access(self):
165        # Anonymous users can access applicants root
166        self.browser.open(self.root_path)
167        self.assertEqual(self.browser.headers['Status'], '200 Ok')
168        self.assertFalse(
169            'Manage' in self.browser.contents)
170
171   
172    def test_anonymous_no_actions(self):
173        # Make sure anonymous users cannot access actions
174        self.browser.open(self.root_path)
175        self.assertRaises(
176            LookupError, self.browser.getControl, "Add local role")
177        # Manage screen neither linked nor accessible for anonymous
178        self.assertRaises(
179            LinkNotFoundError,
180            self.browser.getLink, 'Manage application section')
181        self.assertRaises(
182            Unauthorized, self.browser.open, self.manage_root_path)
183        # Add container screen not accessible for anonymous
184        self.assertRaises(
185            Unauthorized, self.browser.open, self.add_container_path)
186        return
187
188    def test_manage_access(self):
189        # Managers can access the manage pages of applicants root
190        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
191        self.browser.open(self.root_path)
192        self.assertTrue('Manage application section' in self.browser.contents)
193        # There is a manage link
194        link = self.browser.getLink('Manage application section')
195        link.click()
196        self.assertEqual(self.browser.headers['Status'], '200 Ok')
197        self.assertEqual(self.browser.url, self.manage_root_path)
198
199    def test_manage_actions_access(self):
200        # Managers can access the action on manage screen
201        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
202        self.browser.open(self.manage_root_path)
203        self.browser.getControl("Add local role").click()
204        self.assertTrue('No user selected' in self.browser.contents)
205        return
206
207    # We have no local roles yet
208    #def test_local_roles_add_delete(self):
209    #    # Managers can assign and delete local roles of applicants root
210    #    myusers = self.app['users']
211    #    myusers.addUser('bob', 'bobssecret')
212    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
213    #    self.browser.open(self.manage_root_path)
214    #    self.browser.getControl(name="user").value = ['bob']
215    #    self.browser.getControl(name="local_role").value = [
216    #        'waeup.local.ApplicationsOfficer']
217    #    self.browser.getControl("Add local role").click()
218    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
219    #    # Remove the role assigned
220    #    ctrl = self.browser.getControl(name='role_id')
221    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
222    #    self.browser.getControl("Remove selected local roles").click()
223    #    self.assertTrue('Successfully removed:' in self.browser.contents)
224    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
225    #    return
226
227    def test_add_delete_container(self):
228        # Managers can add and delete applicants containers
229        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
230        self.browser.open(self.manage_root_path)
231        self.browser.getControl("Cancel").click()
232        self.assertEqual(self.browser.url, self.root_path)
233        self.browser.open(self.manage_root_path)
234        self.browser.getControl("Add applicants container").click()
235        self.assertEqual(self.browser.headers['Status'], '200 Ok')
236        self.assertEqual(self.browser.url, self.add_container_path)
237        self.browser.getControl(name="form.prefix").value = ['app']
238        self.browser.getControl("Add applicants container").click()
239        self.assertTrue(
240            'There were errors' in self.browser.contents)
241        self.browser.getControl(name="form.prefix").value = ['app']
242        self.browser.getControl(name="form.year").value = ['2010']
243        self.browser.getControl(name="form.provider").value = [
244            'waeup.sirp.applicants.ApplicantsContainer']
245        self.browser.getControl(name="form.ac_prefix").value = ['APP']
246        self.browser.getControl(name="form.application_category").value = ['basic']
247        self.browser.getControl("Add applicants container").click()
248        self.assertTrue('Added:' in self.browser.contents)
249        self.browser.open(self.add_container_path)
250        self.browser.getControl("Cancel").click()
251        self.assertEqual(self.browser.url, self.manage_root_path + '#tab-1')
252        self.browser.open(self.add_container_path)
253        self.browser.getControl(name="form.prefix").value = ['app']
254        self.browser.getControl(name="form.year").value = ['2010']
255        self.browser.getControl(name="form.provider").value = [
256            'waeup.sirp.applicants.ApplicantsContainer']
257        self.browser.getControl(name="form.ac_prefix").value = ['APP']
258        self.browser.getControl(name="form.application_category").value = ['basic']
259        self.browser.getControl("Add applicants container").click()
260        self.assertTrue('exists already in the database' in self.browser.contents)
261        self.browser.open(self.manage_root_path)
262        ctrl = self.browser.getControl(name='val_id')
263        ctrl.getControl(value='app2010').selected = True
264        self.browser.getControl("Remove selected", index=0).click()
265        self.assertTrue('Successfully removed:' in self.browser.contents)
266        self.browser.open(self.add_container_path)
267        self.browser.getControl(name="form.prefix").value = ['app']
268        self.browser.getControl(name="form.year").value = ['2010']
269        self.browser.getControl(name="form.provider").value = [
270            'waeup.sirp.applicants.ApplicantsContainer']
271        self.browser.getControl(name="form.ac_prefix").value = ['APP']
272        self.browser.getControl(name="form.application_category").value = ['basic']
273        self.browser.getControl("Add applicants container").click()
274        del self.app['applicants']['app2010']
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.assertMatches('...Could not delete...', self.browser.contents)
279        return
280
281    def test_add_delete_applicants(self):
282        # Managers can add and delete applicants
283        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
284        self.add_applicant_path = self.container_path + '/addapplicant'
285        self.container_manage_path = self.container_path + '/@@manage'
286        self.browser.open(self.container_manage_path)
287        self.browser.getControl("Add applicant").click()
288        self.assertEqual(self.browser.headers['Status'], '200 Ok')
289        self.assertEqual(self.browser.url, self.add_applicant_path)
290        self.browser.getControl(name="form.firstname").value = 'Alois'
291        self.browser.getControl(name="form.middlename").value = 'Kofi'
292        self.browser.getControl(name="form.lastname").value = 'Bettermann'
293        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
294        self.browser.getControl("Create application record").click()
295        self.assertTrue('Application initialized' in self.browser.contents)
296        self.browser.open(self.container_manage_path)
297        self.assertEqual(self.browser.headers['Status'], '200 Ok')
298        ctrl = self.browser.getControl(name='val_id')
299        value = ctrl.options[0]
300        ctrl.getControl(value=value).selected = True
301        self.browser.getControl("Remove selected", index=0).click()
302        self.assertTrue('Successfully removed:' in self.browser.contents)
303        self.browser.open(self.add_applicant_path)
304        self.browser.getControl(name="form.firstname").value = 'Albert'
305        self.browser.getControl(name="form.lastname").value = 'Einstein'
306        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
307        self.browser.getControl("Create application record").click()
308        self.assertTrue('Application initialized' in self.browser.contents)
309        return
310
311    def test_manage_and_view_applicant(self):
312        # Managers can manage applicants
313        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
314        self.slip_path = self.view_path + '/application_slip.pdf'
315        self.browser.open(self.manage_path)
316        self.assertEqual(self.browser.headers['Status'], '200 Ok')
317        self.fill_correct_values()
318        # Fire transition
319        self.browser.getControl(name="transition").value = ['start']
320        self.browser.getControl("Save").click()
321        self.assertMatches('...Form has been saved...', self.browser.contents)
322        self.assertMatches('...Application started by Manager...', self.browser.contents)
323        self.browser.open(self.view_path)
324        self.assertEqual(self.browser.headers['Status'], '200 Ok')
325        # Change course_admitted
326        self.browser.open(self.manage_path)
327        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
328        self.browser.getControl("Save").click()
329        self.assertMatches('...Form has been saved...', self.browser.contents)
330        # Change password
331        self.browser.getControl(name="password").value = 'secret'
332        self.browser.getControl(name="control_password").value = 'secre'
333        self.browser.getControl("Save").click()
334        self.assertMatches('...Passwords do not match...', self.browser.contents)
335        self.browser.getControl(name="password").value = 'secret'
336        self.browser.getControl(name="control_password").value = 'secret'
337        self.browser.getControl("Save").click()
338        self.assertMatches('...Form has been saved...', self.browser.contents)
339        # Open pdf slip
340        self.browser.open(self.slip_path)
341        self.assertEqual(self.browser.headers['Status'], '200 Ok')
342        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
343        # Managers can view applicants even if certificate has been removed
344        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
345        self.browser.open(self.view_path)
346        self.assertEqual(self.browser.headers['Status'], '200 Ok')
347        self.browser.open(self.slip_path)
348        self.assertEqual(self.browser.headers['Status'], '200 Ok')
349        return
350
351    def test_passport_edit_view(self):
352        # We get a default image after login
353        self.browser.open(self.login_path)
354        self.login()
355        self.browser.open(self.browser.url + '/passport.jpg')
356        self.assertEqual(self.browser.headers['status'], '200 Ok')
357        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
358        self.assertTrue('JFIF' in self.browser.contents)
359        self.assertEqual(
360            self.browser.headers['content-length'], str(PH_LEN))
361
362    def test_edit_applicant(self):
363        # Applicants can edit their record
364        self.browser.open(self.login_path)
365        self.login()
366        self.browser.open(self.edit_path)
367        self.assertTrue(self.browser.url != self.login_path)
368        self.assertEqual(self.browser.headers['Status'], '200 Ok')
369        self.fill_correct_values()
370        self.browser.getControl("Save").click()
371        self.assertMatches('...Form has been saved...', self.browser.contents)
372        return
373
374class ApplicantsContainerUITests(ApplicantsFullSetup):
375    # Tests for ApplicantsContainer class views and pages
376
377    layer = FunctionalLayer
378
379    def test_anonymous_access(self):
380        # Anonymous users can access applicants containers
381        self.browser.open(self.container_path)
382        self.assertEqual(self.browser.headers['Status'], '200 Ok')
383        self.assertFalse(
384            'Manage' in self.browser.contents)
385        return
386
387    def test_manage_access(self):
388        # Managers can access the manage pages of applicants
389        # containers and can perform actions
390        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
391        self.browser.open(self.manage_container_path)
392        self.assertEqual(self.browser.headers['Status'], '200 Ok')
393        self.assertEqual(self.browser.url, self.manage_container_path)
394        self.browser.getControl("Save").click()
395        self.assertTrue('Data saved' in self.browser.contents)
396        self.browser.getControl("Remove selected", index=0).click()
397        self.assertTrue('No applicant selected' in self.browser.contents)
398        self.browser.getControl("Add local role").click()
399        self.assertTrue('No user selected' in self.browser.contents)
400        self.browser.getControl("Cancel", index=0).click()
401        self.assertEqual(self.browser.url, self.container_path)
402        return
403
404class ApplicantsPassportTests(ApplicantsFullSetup):
405    # Tests for uploading/browsing the passport image of appplicants
406
407    layer = FunctionalLayer
408
409    def image_url(self, filename):
410        return self.edit_path.replace('edit', filename)
411
412    def test_after_login_default_browsable(self):
413        # After login we see the placeholder image in the edit view
414        #import pdb; pdb.set_trace()
415        self.login()
416        self.assertEqual(self.browser.url, self.view_path)
417        self.browser.open(self.edit_path)
418        # There is a correct <img> link included
419        self.assertTrue(
420              '<img src="passport.jpg" />' in self.browser.contents)
421        # Browsing the link shows a real image
422        self.browser.open(self.image_url('passport.jpg'))
423        self.assertEqual(
424            self.browser.headers['content-type'], 'image/jpeg')
425        self.assertEqual(len(self.browser.contents), PH_LEN)
426
427    def test_after_submit_default_browsable(self):
428        # After submitting an applicant form the default image is
429        # still visible
430        self.login()
431        self.browser.open(self.edit_path)
432        self.browser.getControl("Save").click() # submit form
433        # There is a correct <img> link included
434        self.assertTrue(
435            '<img src="passport.jpg" />' in self.browser.contents)
436        # Browsing the link shows a real image
437        self.browser.open(self.image_url('passport.jpg'))
438        self.assertEqual(
439            self.browser.headers['content-type'], 'image/jpeg')
440        self.assertEqual(len(self.browser.contents), PH_LEN)
441
442    def test_uploaded_image_respects_file_size_restriction(self):
443        # When we upload an image that is too big ( > 10 KB) we will
444        # get an error message
445        self.login()
446        self.browser.open(self.edit_path)
447        # Create a pseudo image file and select it to be uploaded in form
448        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
449        pseudo_image = StringIO(photo_content)
450        ctrl = self.browser.getControl(name='form.passport')
451        file_ctrl = ctrl.mech_control
452        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
453        self.browser.getControl("Save").click() # submit form
454        # There is a correct <img> link included
455        self.assertTrue(
456            '<img src="passport.jpg" />' in self.browser.contents)
457        # We get a warning message
458        self.assertTrue(
459            'Uploaded image is too big' in self.browser.contents)
460        # Browsing the image gives us the default image, not the
461        # uploaded one.
462        self.browser.open(self.image_url('passport.jpg'))
463        self.assertEqual(
464            self.browser.headers['content-type'], 'image/jpeg')
465        self.assertEqual(len(self.browser.contents), PH_LEN)
466        # There is really no file stored for the applicant
467        img = getUtility(IExtFileStore).getFile(
468            IFileStoreNameChooser(self.applicant).chooseName())
469        self.assertTrue(img is None)
470
471    def test_uploaded_image_browsable_w_errors(self):
472        # We can upload a different image and browse it after submit,
473        # even if there are still errors in the form
474        self.login()
475        self.browser.open(self.edit_path)
476        # Create a pseudo image file and select it to be uploaded in form
477        photo_content = 'I pretend to be a graphics file'
478        pseudo_image = StringIO(photo_content)
479        ctrl = self.browser.getControl(name='form.passport')
480        file_ctrl = ctrl.mech_control
481        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
482        self.browser.getControl("Save").click() # submit form
483        # There is a correct <img> link included
484        self.assertTrue(
485            '<img src="passport.jpg" />' in self.browser.contents)
486        # Browsing the link shows a real image
487        self.browser.open(self.image_url('passport.jpg'))
488        self.assertEqual(
489            self.browser.headers['content-type'], 'image/jpeg')
490        self.assertEqual(self.browser.contents, photo_content)
491
492    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
493        # After uploading a new passport pic the file is correctly
494        # stored in an imagestorage
495        self.login()
496        self.browser.open(self.edit_path)
497        # Create a pseudo image file and select it to be uploaded in form
498        pseudo_image = StringIO('I pretend to be a graphics file')
499        ctrl = self.browser.getControl(name='form.passport')
500        file_ctrl = ctrl.mech_control
501        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
502        self.browser.getControl("Save").click() # submit form
503        storage = getUtility(IExtFileStore)
504        file_id = IFileStoreNameChooser(self.applicant).chooseName()
505        pseudo_image.seek(0) # reset our file data source
506        self.assertEqual(
507            storage.getFile(file_id).read(), pseudo_image.read())
508        return
509
510    def test_uploaded_image_browsable_wo_errors(self):
511        # We can upload a different image and browse it after submit,
512        # if there are no errors in form
513        self.login()
514        self.browser.open(self.edit_path)
515        self.fill_correct_values() # fill other fields with correct values
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        # There is a correct <img> link included
523        self.assertTrue(
524            '<img src="passport.jpg" />' in self.browser.contents)
525        # Browsing the link shows a real image
526        self.browser.open(self.image_url('passport.jpg'))
527        self.assertEqual(
528            self.browser.headers['content-type'], 'image/jpeg')
529        self.assertEqual(len(self.browser.contents), 31)
530
531    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
532        # After uploading a new passport pic the file is correctly
533        # stored in an imagestorage if form contains no errors
534        self.login()
535        self.browser.open(self.edit_path)
536        self.fill_correct_values() # fill other fields with correct values
537        # Create a pseudo image file and select it to be uploaded in form
538        pseudo_image = StringIO('I pretend to be a graphics file')
539        ctrl = self.browser.getControl(name='form.passport')
540        file_ctrl = ctrl.mech_control
541        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
542        self.browser.getControl("Save").click() # submit form
543        storage = getUtility(IExtFileStore)
544        file_id = IFileStoreNameChooser(self.applicant).chooseName()
545        # The stored image can be fetched
546        fd = storage.getFile(file_id)
547        file_len = len(fd.read())
548        self.assertEqual(file_len, 31)
549
550    def test_uploaded_images_equal(self):
551        # Make sure uploaded images do really differ if we eject a
552        # change notfication (and do not if we don't)
553        self.login()
554        self.browser.open(self.edit_path)
555        self.fill_correct_values() # fill other fields with correct values
556        self.browser.getControl("Save").click() # submit form
557        # Now go on as an officer
558        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
559        self.browser.open(self.manage_path)
560
561        # Create a pseudo image file and select it to be uploaded in form
562        pseudo_image = StringIO('I pretend to be a graphics file')
563        ctrl = self.browser.getControl(name='form.passport')
564        file_ctrl = ctrl.mech_control
565        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
566        file_id = IFileStoreNameChooser(self.applicant).chooseName()
567        setSite(self.app)
568        passport0 = getUtility(IExtFileStore).getFile(file_id)
569        self.browser.getControl("Save").click() # submit form with changed pic
570        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
571        self.browser.getControl("Save").click() # submit form w/o changes
572        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
573        self.assertTrue(passport0 is None)
574        self.assertTrue(passport0 != passport1)
575        self.assertTrue(passport1 == passport2)
576        return
577
578    def test_pay_acceptance_fee(self):
579        self.login()
580        self.browser.open(self.edit_path)
581        # Payment tickets can't be created before the form has been validated
582        self.browser.getControl("Add online payment ticket").click()
583        self.assertTrue('Required input is missing' in self.browser.contents)
584        self.fill_correct_values()
585        # We have to savethe form otherwise the filled fields will be cleared
586        # after adding an online payment, because adding an online payment
587        # requires a filled form but does not save it
588        self.browser.getControl("Save").click()
589        self.browser.getControl("Add online payment ticket").click()
590        # Session object missing
591        self.assertTrue(
592            'Session configuration object is not available'
593            in self.browser.contents)
594        configuration = SessionConfiguration()
595        configuration.academic_session = 2009
596        configuration.acceptance_fee = 200
597        self.app['configuration'].addSessionConfiguration(configuration)
598        self.browser.open(self.edit_path)
599        self.fill_correct_values()
600        self.browser.getControl("Add online payment ticket").click()
601        self.assertMatches('...Payment ticket created...', self.browser.contents)
602        # Payment ticket can be removed if they haven't received a valid callback
603        ctrl = self.browser.getControl(name='val_id')
604        value = ctrl.options[0]
605        ctrl.getControl(value=value).selected = True
606        self.browser.getControl("Remove selected", index=0).click()
607        self.assertMatches('...Successfully removed...', self.browser.contents)
608        # We will try the callback request view
609        self.browser.getControl("Add online payment ticket").click()
610        ctrl = self.browser.getControl(name='val_id')
611        value = ctrl.options[0]
612        self.browser.getLink(value).click()
613        self.assertMatches('...Amount Authorized...',
614                           self.browser.contents)
615        payment_url = self.browser.url
616        # The pdf payment receipt can't yet be opened
617        self.browser.open(payment_url + '/payment_receipt.pdf')
618        self.assertMatches('...Ticket not yet paid...',
619                           self.browser.contents)
620        # Request callback
621        self.browser.open(payment_url)
622        self.browser.getLink("Request callback").click()
623        self.assertMatches('...Valid callback received...',
624                          self.browser.contents)
625        # Callback can't be applied twice
626        self.browser.open(payment_url + '/callback')
627        self.assertMatches(
628            "...Transition 'pay' requires 'started' as source state...",
629            self.browser.contents)
630        # The payment receipt can be downloaded now
631        self.browser.open(payment_url)
632        self.browser.getLink("Download payment receipt").click()
633        self.assertEqual(self.browser.headers['Status'], '200 Ok')
634        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
635        # Applicant is is in state 'paid'
636        self.browser.open(self.view_path)
637        self.assertMatches('...paid...',
638                           self.browser.contents)
639        state = IWorkflowState(self.applicant).getState()
640        self.assertTrue(state == 'paid')
641
642    def test_final_submit(self):
643        # Make sure that a correctly filled form with passport picture
644        # can be submitted (only) after payment
645        self.login()
646        self.browser.getLink("Edit application record").click()
647        self.assertFalse('Final Submit' in self.browser.contents)
648        IWorkflowInfo(self.applicant).fireTransition('pay')
649        self.browser.open(self.edit_path)
650        self.assertTrue('Final Submit' in self.browser.contents)
651        self.fill_correct_values() # fill other fields with correct values
652        self.browser.getControl("Final Submit").click()
653        # We forgot to upload a passport picture
654        self.assertTrue(
655            'No passport picture uploaded' in self.browser.contents)
656        # Create a pseudo image file and select it to be uploaded in form
657        pseudo_image = StringIO('I pretend to be a graphics file')
658        ctrl = self.browser.getControl(name='form.passport')
659        file_ctrl = ctrl.mech_control
660        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
661        self.browser.getControl("Final Submit").click() # (finally) submit form
662        # The picture has been uploaded but the form cannot be submitted
663        # since the passport confirmation box was not ticked
664        self.assertTrue(
665            'Passport picture confirmation box not ticked' in self.browser.contents)
666        self.browser.getControl(name="confirm_passport").value = True
667        self.browser.getControl("Final Submit").click()
668        self.assertTrue(
669            '... submitted ...' in self.browser.contents)
670        self.browser.goBack(count=1)
671        self.browser.getControl("Save").click()
672        self.assertTrue(
673            'The requested form is locked' in self.browser.contents)
674        self.browser.goBack(count=1)
675        #import pdb; pdb.set_trace()
676        self.browser.getControl("Final Submit").click()
677        self.assertTrue(
678            'The requested form is locked' in self.browser.contents)
679        return
680
681    def test_locking(self):
682        # Make sure that locked forms can't be submitted
683        self.login()
684        self.browser.open(self.edit_path)
685        self.fill_correct_values() # fill other fields with correct values
686        # Create a pseudo image file and select it to be uploaded in form
687        pseudo_image = StringIO('I pretend to be a graphics file')
688        ctrl = self.browser.getControl(name='form.passport')
689        file_ctrl = ctrl.mech_control
690        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
691        self.browser.getControl("Save").click()
692        # Now we lock the form
693        self.applicant.locked = True
694        self.browser.open(self.edit_path)
695        self.assertEqual(self.browser.headers['Status'], '200 Ok')
696        #print self.browser.contents
697        self.assertTrue(
698            'The requested form is locked' in self.browser.contents)
699        return
Note: See TracBrowser for help on using the repository browser.