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

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

Reenable test for image in erraneous applicant forms.

File size: 39.0 KB
Line 
1##
2## test_browser.py
3## Login : <uli@pu.smp.net>
4## Started on  Tue Mar 29 11:31:11 2011 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""
23Test the applicant-related UI components.
24"""
25import shutil
26import tempfile
27from StringIO import StringIO
28from datetime import datetime
29from zope.component import createObject
30from zope.component.hooks import setSite, clearSite
31from zope.testbrowser.testing import Browser
32from hurry.workflow.interfaces import IWorkflowInfo
33from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
34from waeup.sirp.app import University
35from waeup.sirp.applicants.container import ApplicantsContainer
36from waeup.sirp.applicants.applicants import Applicant
37from waeup.sirp.university.faculty import Faculty
38from waeup.sirp.university.department import Department
39
40PH_LEN = 2059  # Length of placeholder file
41
42class ApplicantsFullSetup(FunctionalTestCase):
43    # A test case that only contains a setup and teardown
44    #
45    # Complete setup for applicants handlings is rather complex and
46    # requires lots of things created before we can start. This is a
47    # setup that does all this, creates a university, creates PINs,
48    # etc.  so that we do not have to bother with that in different
49    # test cases.
50
51    layer = FunctionalLayer
52
53    def setUp(self):
54        super(ApplicantsFullSetup, self).setUp()
55
56        # Setup a sample site for each test
57        app = University()
58        self.dc_root = tempfile.mkdtemp()
59        app['datacenter'].setStoragePath(self.dc_root)
60
61        # Prepopulate the ZODB...
62        self.getRootFolder()['app'] = app
63        # we add the site immediately after creation to the
64        # ZODB. Catalogs and other local utilities are not setup
65        # before that step.
66        self.app = self.getRootFolder()['app']
67        # Set site here. Some of the following setup code might need
68        # to access grok.getSite() and should get our new app then
69        setSite(app)
70
71        self.root_path = 'http://localhost/app/applicants'
72        self.container_path = 'http://localhost/app/applicants/app2009'
73
74        # Add an applicants container
75        applicantscontainer = ApplicantsContainer()
76        applicantscontainer.ac_prefix = 'APP'
77        applicantscontainer.prefix = 'app'
78        applicantscontainer.year = 2009
79        applicantscontainer.application_category = 'basic'
80        self.app['applicants']['app2009'] = applicantscontainer
81
82        # Populate university
83        certificate = createObject('waeup.Certificate')
84        certificate.code = 'CERT1'
85        certificate.application_category = 'basic'
86        self.app['faculties']['fac1'] = Faculty()
87        self.app['faculties']['fac1']['dep1'] = Department()
88        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
89            certificate)
90
91        # Put the prepopulated site into test ZODB and prepare test
92        # browser
93        self.browser = Browser()
94        self.browser.handleErrors = False
95
96        # Create 5 access codes with prefix'FOO' and cost 9.99 each
97        pin_container = self.app['accesscodes']
98        pin_container.createBatch(
99            datetime.now(), 'some_userid', 'APP', 9.99, 5)
100        pins = pin_container[pin_container.keys()[0]].values()
101        self.pins = [x.representation for x in pins]
102        self.existing_pin = self.pins[0]
103        parts = self.existing_pin.split('-')[1:]
104        self.existing_series, self.existing_number = parts
105
106        # Add an applicant
107        self.applicant = Applicant()
108        self.pin_applicant = unicode(self.pins[1])
109        self.applicant.access_code = self.pin_applicant
110        app['applicants']['app2009'][self.pin_applicant] = self.applicant
111
112    def tearDown(self):
113        super(ApplicantsFullSetup, self).tearDown()
114        clearSite()
115        shutil.rmtree(self.dc_root)
116        #import pdb; pdb.set_trace()
117
118class ApplicantsUITests(ApplicantsFullSetup):
119    # Tests for ApplicantsRoot class
120
121    layer = FunctionalLayer
122
123    def test_anonymous_access(self):
124        # Anonymous users can access applicants root and applicants containers
125        self.browser.open(self.root_path)
126        self.assertEqual(self.browser.headers['Status'], '200 Ok')
127        self.assertFalse(
128            'Manage' in self.browser.contents)
129        self.browser.open(self.container_path)
130        self.assertEqual(self.browser.headers['Status'], '200 Ok')
131        self.assertFalse(
132            'Manage' in self.browser.contents)
133        return
134
135    def test_manage_cert_access(self):
136        # Managers can access CERT1
137        cert_path = 'http://localhost/app/faculties/fac1/dep1/certificates/CERT1'
138        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
139        self.browser.open(cert_path)
140        self.assertEqual(self.browser.headers['Status'], '200 Ok')
141
142    def test_manage_access(self):
143        # Managers can access the manage pages of applicants root and
144        # applicants containers and can perform actions
145        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
146        self.browser.open(self.root_path)
147        self.assertTrue(
148            'Manage application section' in self.browser.contents)
149        self.manage_root_path = self.root_path + '/@@manage'
150        self.manage_container_path = self.container_path + '/@@manage'
151        self.browser.open(self.manage_root_path)
152        self.assertEqual(self.browser.headers['Status'], '200 Ok')
153        self.assertEqual(self.browser.url, self.manage_root_path)
154        self.browser.getControl("Add local role").click()
155        self.assertTrue(
156            'No user selected' in self.browser.contents)
157        self.browser.open(self.manage_container_path)
158        self.assertEqual(self.browser.headers['Status'], '200 Ok')
159        self.assertEqual(self.browser.url, self.manage_container_path)
160        self.browser.getControl("Save").click()
161        self.assertTrue(
162            'Data saved' in self.browser.contents)
163        self.browser.getControl("Remove selected", index=0).click()
164        self.assertTrue(
165            'No applicant selected' in self.browser.contents)
166        self.browser.getControl("Add local role").click()
167        self.assertTrue(
168            'No user selected' in self.browser.contents)
169        self.browser.getControl("Cancel", index=0).click()
170        self.assertEqual(self.browser.url, self.container_path)
171        # Managers can can assign local roles
172        myusers = self.app['users']
173        myusers.addUser('bob', 'bobssecret')
174        self.browser.open(self.manage_root_path)
175        self.browser.getControl(name="user").value = ['bob']
176        self.browser.getControl(name="local_role").value = ['waeup.ApplicationsOfficer']
177        self.browser.getControl("Add local role").click()
178        self.assertTrue(
179            '<td>bob</td>' in self.browser.contents)
180        ctrl = self.browser.getControl(name='role_id')
181        ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
182        self.browser.getControl("Remove selected local roles").click()
183        self.assertTrue('Successfully removed:' in self.browser.contents)
184        self.assertFalse(
185            '<td>bob</td>' in self.browser.contents)
186        self.browser.open(self.manage_container_path)
187        self.browser.getControl(name="user").value = ['bob']
188        self.browser.getControl(name="local_role").value = ['waeup.ApplicationsOfficer']
189        self.browser.getControl("Add local role").click()
190        self.assertTrue(
191            '<td>bob</td>' in self.browser.contents)
192        ctrl = self.browser.getControl(name='role_id')
193        ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
194        self.browser.getControl("Remove selected local roles").click()
195        self.assertTrue('Successfully removed:' in self.browser.contents)
196        self.assertFalse(
197            '<td>bob</td>' in self.browser.contents)
198        return
199
200    def test_add_delete_container(self):
201        # Managers can add and delete applicants containers
202        self.manage_root_path = self.root_path + '/@@manage'
203        self.add_container_path = self.root_path + '/@@add'
204        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
205        self.browser.open(self.manage_root_path)
206        self.browser.getControl("Cancel").click()
207        self.assertEqual(self.browser.url, self.root_path)
208        self.browser.open(self.manage_root_path)
209        self.browser.getControl("Add applicants container").click()
210        self.assertEqual(self.browser.headers['Status'], '200 Ok')
211        self.assertEqual(self.browser.url, self.add_container_path)
212        self.browser.getControl(name="form.prefix").value = ['app']
213        self.browser.getControl("Add applicants container").click()
214        self.assertTrue(
215            'There were errors' in self.browser.contents)
216        self.browser.getControl(name="form.prefix").value = ['app']
217        self.browser.getControl(name="form.year").value = ['2010']
218        self.browser.getControl(name="form.provider").value = [
219            'waeup.sirp.applicants.ApplicantsContainer']
220        self.browser.getControl(name="form.ac_prefix").value = ['APP']
221        self.browser.getControl(name="form.application_category").value = ['basic']
222        self.browser.getControl("Add applicants container").click()
223        self.assertTrue('Added:' in self.browser.contents)
224        self.browser.open(self.add_container_path)
225        self.browser.getControl("Cancel").click()
226        self.assertEqual(self.browser.url, self.manage_root_path + '#tab-1')
227        self.browser.open(self.add_container_path)
228        self.browser.getControl(name="form.prefix").value = ['app']
229        self.browser.getControl(name="form.year").value = ['2010']
230        self.browser.getControl(name="form.provider").value = [
231            'waeup.sirp.applicants.ApplicantsContainer']
232        self.browser.getControl(name="form.ac_prefix").value = ['APP']
233        self.browser.getControl(name="form.application_category").value = ['basic']
234        self.browser.getControl("Add applicants container").click()
235        self.assertTrue('exists already in the database' in self.browser.contents)
236        self.browser.open(self.manage_root_path)
237        ctrl = self.browser.getControl(name='val_id')
238        ctrl.getControl(value='app2010').selected = True
239        self.browser.getControl("Remove selected", index=0).click()
240        self.assertTrue('Successfully removed:' in self.browser.contents)
241        self.browser.open(self.add_container_path)
242        self.browser.getControl(name="form.prefix").value = ['app']
243        self.browser.getControl(name="form.year").value = ['2010']
244        self.browser.getControl(name="form.provider").value = [
245            'waeup.sirp.applicants.ApplicantsContainer']
246        self.browser.getControl(name="form.ac_prefix").value = ['APP']
247        self.browser.getControl(name="form.application_category").value = ['basic']
248        self.browser.getControl("Add applicants container").click()
249        del self.app['applicants']['app2010']
250        ctrl = self.browser.getControl(name='val_id')
251        ctrl.getControl(value='app2010').selected = True
252        self.browser.getControl("Remove selected", index=0).click()
253        self.assertMatches('...Could not delete...', self.browser.contents)
254        return
255
256    def test_add_delete_applicants(self):
257        # Managers can add and delete applicants
258        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
259        self.add_applicant_path = self.container_path + '/addapplicant'
260        self.container_manage_path = self.container_path + '/@@manage'
261        self.browser.open(self.container_manage_path)
262        self.browser.getControl("Add applicant").click()
263        self.assertEqual(self.browser.headers['Status'], '200 Ok')
264        self.assertEqual(self.browser.url, self.add_applicant_path)
265        self.browser.getControl(name="form.ac_series").value = self.existing_series
266        self.browser.getControl(name="form.ac_number").value = self.existing_number
267        self.browser.getControl("Create application record").click()
268        self.assertTrue('Application initialized' in self.browser.contents)
269        self.browser.open(self.add_applicant_path)
270        self.browser.getControl(name="form.ac_series").value = '123'
271        self.browser.getControl(name="form.ac_number").value = '456'
272        self.browser.getControl("Create application record").click()
273        self.assertTrue('is not a valid access code' in self.browser.contents)
274        self.browser.open(self.container_manage_path)
275        self.assertEqual(self.browser.headers['Status'], '200 Ok')
276        ctrl = self.browser.getControl(name='val_id')
277        ctrl.getControl(value=self.existing_pin).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_applicant_path)
281        existing_pin = self.pins[2]
282        parts = existing_pin.split('-')[1:]
283        existing_series, existing_number = parts
284        self.browser.getControl(name="form.ac_series").value = existing_series
285        self.browser.getControl(name="form.ac_number").value = existing_number
286        self.browser.getControl("Create application record").click()
287        self.assertTrue('Application initialized' in self.browser.contents)
288        self.browser.open(self.container_manage_path)
289        self.assertTrue(existing_pin in self.browser.contents)
290        del self.app['applicants']['app2009'][existing_pin]
291        ctrl = self.browser.getControl(name='val_id')
292        ctrl.getControl(value=existing_pin).selected = True
293        self.browser.getControl("Remove selected", index=0).click()
294        self.assertMatches('...Could not delete...', self.browser.contents)
295        return
296
297    def test_manage_and_view_applicant(self):
298        # Managers can manage applicants
299        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
300        self.applicant_path = 'http://localhost/app/applicants/app2009/%s' % self.pin_applicant
301        self.applicant_view_path = self.applicant_path + '/index'
302        self.applicant_manage_path = self.applicant_path + '/edit_full'
303        self.applicant_slip_path = self.applicant_path + '/application_slip.pdf'
304        self.browser.open(self.applicant_manage_path)
305        self.assertEqual(self.browser.headers['Status'], '200 Ok')
306        self.browser.getControl(name="form.email").value = 'abc'
307        self.browser.getControl("Save").click()
308        self.assertMatches('...Invalid email address...', self.browser.contents)
309        self.browser.getControl(name="form.email").value = 'abc@def.gh'
310        self.browser.getControl(name="form.firstname").value = 'John'
311        self.browser.getControl(name="form.lastname").value = 'Tester'
312        self.browser.getControl(name="form.course1").value = ['CERT1']
313        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
314        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
315        self.browser.getControl(name="form.lga").value = ['foreigner']
316        self.browser.getControl(name="form.sex").value = ['m']
317        self.browser.getControl(name="transition").value = ['start']
318        self.browser.getControl("Save").click()
319        self.assertMatches('...Form has been saved...', self.browser.contents)
320        self.assertMatches('...Application started by zope.mgr...', self.browser.contents)
321        self.browser.open(self.applicant_view_path)
322        self.assertEqual(self.browser.headers['Status'], '200 Ok')
323        self.browser.open(self.applicant_slip_path)
324        self.assertEqual(self.browser.headers['Status'], '200 Ok')
325        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
326        self.browser.open(self.applicant_manage_path)
327        self.browser.getControl(name="form.course_admitted").value = []
328        self.browser.getControl("Save").click()
329        self.browser.open(self.applicant_slip_path)
330        self.assertEqual(self.browser.headers['Status'], '200 Ok')
331        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
332        return
333
334    def test_view_applicant(self):
335        # Applicants can login and view their application
336        self.login_path = 'http://localhost/app/applicants/app2009/login'
337        self.browser.open(self.login_path)
338        pin = self.pins[2]
339        parts = pin.split('-')[1:]
340        existing_series, existing_number = parts
341        ac_series = self.browser.getControl(name="form.ac_series")
342        ac_series.value = existing_series
343        ac_number = self.browser.getControl(name="form.ac_number")
344        ac_number.value = existing_number
345        self.browser.getControl(name="SUBMIT").click()
346        self.assertTrue(self.browser.url != self.login_path)
347        self.assertEqual(self.browser.headers['Status'], '200 Ok')
348        return
349
350    def test_passport_edit_view(self):
351        # We get a default image after login
352        login_path = 'http://localhost/app/applicants/app2009/login'
353        self.browser.open(login_path)
354        pin = self.pins[2]
355        parts = pin.split('-')[1:]
356        existing_series, existing_number = parts
357        ac_series = self.browser.getControl(name="form.ac_series")
358        ac_series.value = existing_series
359        ac_number = self.browser.getControl(name="form.ac_number")
360        ac_number.value = existing_number
361        self.browser.getControl(name="SUBMIT").click()
362        pin = self.pins[2]
363        appl = self.getRootFolder()['app']['applicants']['app2009']
364        appl = appl[pin]
365        passp = appl.passport
366        #import pdb; pdb.set_trace()
367        passp_len = len(passp.file.read())
368        self.assertEqual(passp_len, PH_LEN)
369        #image_url = "%s/%s" % (self.browser.url, 'placeholder.jpg')
370        image_url = "%s/%s" % (self.browser.url, 'passport.jpg')
371        #self.browser.open(image_url)
372        self.browser.open('passport.jpg')
373        self.assertEqual(self.browser.headers['status'], '200 Ok')
374        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
375        self.assertTrue('JFIF' in self.browser.contents)
376        self.assertEqual(
377            self.browser.headers['content-length'], str(PH_LEN))
378
379
380    def test_edit_applicant(self):
381        # Applicants can edit their record
382        self.login_path = 'http://localhost/app/applicants/app2009/login'
383        self.browser.open(self.login_path)
384        pin = self.pins[2]
385        parts = pin.split('-')[1:]
386        existing_series, existing_number = parts
387        ac_series = self.browser.getControl(name="form.ac_series")
388        ac_series.value = existing_series
389        ac_number = self.browser.getControl(name="form.ac_number")
390        ac_number.value = existing_number
391        self.browser.getControl(name="SUBMIT").click()
392        self.assertTrue(self.browser.url != self.login_path)
393        self.assertEqual(self.browser.headers['Status'], '200 Ok')
394        self.browser.getControl(name="form.firstname").value = 'John'
395        self.browser.getControl(name="form.lastname").value = 'Tester'
396        self.browser.getControl(name="form.course1").value = ['CERT1']
397        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
398        self.browser.getControl(name="form.lga").value = ['foreigner']
399        self.browser.getControl(name="form.sex").value = ['m']
400        self.browser.getControl("Save").click()
401        self.assertMatches('...Form has been saved...', self.browser.contents)
402        return
403
404class LoginTest(FunctionalTestCase):
405    # Here we check login view of applicants containers.
406    #
407    # Tests in here do only cover login attempts without any PINs
408    # created before.
409
410    layer = FunctionalLayer
411
412    def setUp(self):
413        super(LoginTest, self).setUp()
414
415        # Setup a sample site for each test
416        app = University()
417        self.dc_root = tempfile.mkdtemp()
418        app['datacenter'].setStoragePath(self.dc_root)
419        self.login_path = 'http://localhost/app/applicants/testapplicants/login'
420
421        # Add an applicants container where we can login (or not)
422        applicantscontainer = ApplicantsContainer()
423        applicantscontainer.ac_prefix = 'APP'
424        app['applicants']['testapplicants'] = applicantscontainer
425
426        # Put the prepopulated site into test ZODB and prepare test
427        # browser
428        self.getRootFolder()['app'] = app
429        self.browser = Browser()
430        self.browser.handleErrors = False
431
432    def tearDown(self):
433        super(LoginTest, self).tearDown()
434        shutil.rmtree(self.dc_root)
435
436    def test_anonymous_access(self):
437        # Anonymous users can access a login page
438        self.browser.open(self.login_path)
439        self.assertEqual(self.browser.headers['Status'], '200 Ok')
440        return
441
442    def test_anonymous_invalid_creds(self):
443        # Anonymous users giving invalid credentials stay at the page
444        self.browser.open(self.login_path)
445        # We do not give credentials but send the form as-is
446        submit = self.browser.getControl(name='SUBMIT')
447        submit.click()
448        # We are still at the same page...
449        self.assertEqual(self.browser.url, self.login_path)
450        self.assertEqual(self.browser.headers['Status'], '200 Ok')
451        return
452
453    def test_anonymous_invalid_creds_warning(self):
454        # Entering wrong credentials will yield a warning
455        self.browser.open(self.login_path)
456        # We do not give credentials but send the form as-is
457        submit = self.browser.getControl(name='SUBMIT')
458        submit.click()
459        self.assertTrue(
460            'Entered credentials are invalid' in self.browser.contents)
461        return
462
463    def test_manager_no_warnings(self):
464        # Browsing the login screen as a manager, won't raise warnings
465        # Authenticate ourself as manager
466        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
467        self.browser.open(self.login_path)
468        # Submit the form w/o any credentials
469        self.browser.getControl(name="SUBMIT").click()
470        self.assertTrue(
471            'Entered credentials are invalid' not in self.browser.contents)
472        return
473
474    def test_manager_no_redirect(self):
475        # Browsing the login screen as a manager won't trigger a redirect
476        # Authenticate ourself as manager
477        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
478        self.browser.open(self.login_path)
479        # Submit the form w/o any credentials
480        self.browser.getControl(name="SUBMIT").click()
481        self.assertEqual(self.browser.url, self.login_path)
482        return
483
484    def test_display_entered_values(self):
485        # After submit the entered values are displayed in the form
486        self.browser.open(self.login_path)
487        # Enter some value we can look for after submit
488        ac_series = self.browser.getControl(name="form.ac_series")
489        ac_series.value = '666'
490        self.browser.getControl(name="SUBMIT").click()
491        self.assertTrue('666' in self.browser.contents)
492        return
493
494class LoginTestWithPINs(LoginTest):
495    # Here we check login view of applicants containers with PINs provided.
496
497    # As setting up pins is time-consuming we only set them up when
498    # really needed (i.e. in this separate TestCase).
499
500    layer = FunctionalLayer
501
502    def setUp(self):
503        super(LoginTestWithPINs, self).setUp()
504
505        # Create 5 access codes with prefix'FOO' and cost 9.99 each
506        pin_container = self.getRootFolder()['app']['accesscodes']
507        pin_container.createBatch(
508            datetime.now(), 'some_userid', 'APP', 9.99, 5)
509        pins = pin_container[pin_container.keys()[0]].values()
510        self.pins = [x.representation for x in pins]
511        self.existing_pin = self.pins[0]
512        parts = self.existing_pin.split('-')[1:]
513        self.existing_series, self.existing_number = parts
514        self.browser.handleErrors = False
515
516    def tearDown(self):
517        super(LoginTestWithPINs, self).tearDown()
518
519    def test_anonymous_valid_login(self):
520        # If we enter valid credentials, we get to the applicants form
521        self.browser.open(self.login_path)
522        # Enter some value we can look for after submit
523        ac_series = self.browser.getControl(name="form.ac_series")
524        ac_series.value = self.existing_series
525        ac_number = self.browser.getControl(name="form.ac_number")
526        ac_number.value = self.existing_number
527        self.browser.getControl(name="SUBMIT").click()
528        # We should be redirected to applicants form.
529        self.assertTrue(self.browser.url != self.login_path)
530        return
531
532    def test_anonymous_invalid_login(self):
533        # If we enter wrong credentials we won't get far
534        self.browser.open(self.login_path)
535        # Enter some value we can look for after submit
536        ac_series = self.browser.getControl(name="form.ac_series")
537        ac_series.value = 'illegal series'
538        ac_number = self.browser.getControl(name="form.ac_number")
539        ac_number.value = 'invalid number'
540        self.browser.getControl(name="SUBMIT").click()
541        # We get a warning message
542        self.assertTrue(
543            'Entered credentials are invalid' in self.browser.contents)
544        # We stay at the login page (no redirect)
545        self.assertTrue(self.browser.url == self.login_path)
546        return
547
548class ApplicantsPassportTests(ApplicantsFullSetup):
549    # Tests for uploading/browsing the passport image of appplicants
550
551    layer = FunctionalLayer
552
553    def setUp(self):
554        super(ApplicantsPassportTests, self).setUp()
555        self.login_path = 'http://localhost/app/applicants/app2009/login'
556        self.pin = self.pins[2]
557        self.existing_series, self.existing_number = self.pin.split('-')[1:]
558        self.edit_path = 'http://localhost/app/applicants/app2009/%s/edit' % (
559            self.pin)
560        self.edit_full_path = 'http://localhost/app/applicants/%s/%s/%s' % (
561            'app2009', self.pin, 'edit_full')
562
563    def tearDown(self):
564        super(ApplicantsPassportTests, self).tearDown()
565
566    def login(self):
567        # Perform an applicant login. This creates an applicant record.
568        #
569        # This helper also sets `self.applicant`, which is the
570        # applicant object created.
571        self.browser.open(self.login_path)
572        ac_series = self.browser.getControl(name="form.ac_series")
573        ac_series.value = self.existing_series
574        ac_number = self.browser.getControl(name="form.ac_number")
575        ac_number.value = self.existing_number
576        self.browser.getControl(name="SUBMIT").click()
577        self.applicant = self.app['applicants']['app2009'][self.pin]
578
579    def fill_correct_values(self):
580        # Fill the edit form with suitable values
581        self.browser.getControl(name="form.firstname").value = 'John'
582        self.browser.getControl(name="form.lastname").value = 'Tester'
583        self.browser.getControl(name="form.course1").value = ['CERT1']
584        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
585        self.browser.getControl(name="form.lga").value = ['foreigner']
586        self.browser.getControl(name="form.sex").value = ['m']
587
588    def image_url(self, filename):
589        return self.edit_path.replace('edit', filename)
590
591    def test_after_login_default_browsable(self):
592        # After login we see the placeholder image in the edit view
593        self.login()
594        self.assertEqual(self.browser.url, self.edit_path)
595        # There is a correct <img> link included
596        self.assertTrue(
597            '<img src="placeholder_m.jpg" />' in self.browser.contents)
598        # Browsing the link shows a real image
599        self.browser.open(self.image_url('placeholder_m.jpg'))
600        self.assertEqual(
601            self.browser.headers['content-type'], 'image/jpeg')
602        self.assertEqual(len(self.browser.contents), PH_LEN)
603
604    def test_after_login_default_stored_in_imagestorage(self):
605        # After login the applicants placeholder image is stored in
606        # an imagestorage
607        storage = self.app['images']
608        # In the beginning, the storage is empty
609        self.assertEqual([x for x in storage.keys()], [])
610        self.login()
611        # After login, it is filled
612        self.assertEqual(
613            [x for x in storage.keys()],
614            [u'b48a1d39bbcb32e955d9ff2dea4ed0e6'])
615        file_id = self.applicant.passport.data
616        self.assertEqual(
617            file_id, u'b48a1d39bbcb32e955d9ff2dea4ed0e6-1')
618        # The stored image can be fetched
619        fd = storage.retrieveFile(file_id)
620        file_len = len(fd.read())
621        self.assertEqual(file_len, PH_LEN)
622
623    def test_after_submit_default_browsable(self):
624        # After submitting an applicant form the default image is
625        # still visible
626        self.login()
627        self.browser.getControl("Save").click() # submit form
628        # There is a correct <img> link included
629        self.assertTrue(
630            '<img src="placeholder_m.jpg" />' in self.browser.contents)
631        # Browsing the link shows a real image
632        self.browser.open(self.image_url('placeholder_m.jpg'))
633        self.assertEqual(
634            self.browser.headers['content-type'], 'image/jpeg')
635        self.assertEqual(len(self.browser.contents), PH_LEN)
636
637    def test_after_submit_default_stored_in_imagestorage(self):
638        # After submitting an applicant form the default image is
639        # correctly stored in an imagestorage
640        self.login()
641        self.browser.getControl("Save").click() # submit form
642        storage = self.app['images']
643        self.assertEqual(
644            [x for x in storage.keys()],
645            [u'b48a1d39bbcb32e955d9ff2dea4ed0e6'])
646        file_id = self.applicant.passport.data
647        self.assertEqual(
648            file_id, u'b48a1d39bbcb32e955d9ff2dea4ed0e6-1')
649        # The stored image can be fetched
650        fd = storage.retrieveFile(file_id)
651        file_len = len(fd.read())
652        self.assertEqual(file_len, PH_LEN)
653
654    def test_uploaded_image_browsable_w_errors(self):
655        # We can upload a different image and browse it after submit,
656        # even if there are still errors in the form
657        self.login()
658        # Create a pseudo image file and select it to be uploaded in form
659        photo_content = 'I pretend to be a graphics file'
660        pseudo_image = StringIO(photo_content)
661        ctrl = self.browser.getControl(name='form.passport')
662        file_ctrl = ctrl.mech_control
663        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
664        self.browser.getControl("Save").click() # submit form
665        # There is a correct <img> link included
666        self.assertTrue(
667            '<img src="myphoto.jpg" />' in self.browser.contents)
668        # Browsing the link shows a real image
669        self.browser.open(self.image_url('myphoto.jpg'))
670        self.assertEqual(
671            self.browser.headers['content-type'], 'image/jpeg')
672        self.assertEqual(self.browser.contents, photo_content)
673
674    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
675        # After uploading a new passport pic the file is correctly
676        # stored in an imagestorage
677        self.login()
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("Save").click() # submit form
684        storage = self.app['images']
685        self.assertTrue(
686            u'18e57c7eac6ca7fb15b54b5b2bd4106d' in storage.keys())
687        # The stored image can be fetched
688        fd = storage.retrieveFile(u'18e57c7eac6ca7fb15b54b5b2bd4106d-1')
689        #fd = storage.retrieveFile(file_id)
690        file_len = len(fd.read())
691        self.assertEqual(file_len, 31)
692        # The image uploaded belongs to the applicant
693        # XXX: When there are errors in form, then the applicant is not
694        #      changed. This (failing) test is here to remember us that
695        #      we have to care for images when form submits fail.
696        file_id = self.applicant.passport.data
697        self.assertEqual(
698            file_id, u'18e57c7eac6ca7fb15b54b5b2bd4106d-1')
699
700    def test_uploaded_image_browsable_wo_errors(self):
701        # We can upload a different image and browse it after submit,
702        # if there are no errors in form
703        self.login()
704        self.fill_correct_values() # fill other fields with correct values
705        # Create a pseudo image file and select it to be uploaded in form
706        pseudo_image = StringIO('I pretend to be a graphics file')
707        ctrl = self.browser.getControl(name='form.passport')
708        file_ctrl = ctrl.mech_control
709        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
710        self.browser.getControl("Save").click() # submit form
711        # There is a correct <img> link included
712        self.assertTrue(
713            '<img src="myphoto.jpg" />' in self.browser.contents)
714        # Browsing the link shows a real image
715        self.browser.open(self.image_url('myphoto.jpg'))
716        self.assertEqual(
717            self.browser.headers['content-type'], 'image/jpeg')
718        self.assertEqual(len(self.browser.contents), 31)
719
720    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
721        # After uploading a new passport pic the file is correctly
722        # stored in an imagestorage if form contains no errors
723        self.login()
724        self.fill_correct_values() # fill other fields with correct values
725        # Create a pseudo image file and select it to be uploaded in form
726        pseudo_image = StringIO('I pretend to be a graphics file')
727        ctrl = self.browser.getControl(name='form.passport')
728        file_ctrl = ctrl.mech_control
729        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
730        self.browser.getControl("Save").click() # submit form
731        storage = self.app['images']
732        self.assertTrue(
733            u'18e57c7eac6ca7fb15b54b5b2bd4106d' in storage.keys())
734        # The stored image can be fetched
735        fd = storage.retrieveFile(u'18e57c7eac6ca7fb15b54b5b2bd4106d-1')
736        #fd = storage.retrieveFile(file_id)
737        file_len = len(fd.read())
738        self.assertEqual(file_len, 31)
739        # The image uploaded belongs to the applicant
740        file_id = self.applicant.passport.data
741        self.assertEqual(
742            file_id, u'18e57c7eac6ca7fb15b54b5b2bd4106d-1')
743
744    def test_uploaded_images_equal(self):
745        # Make sure uploaded images do really differ if we eject a
746        # change notfication (and do not if we don't)
747        self.login() # Create applicant form
748        self.fill_correct_values() # fill other fields with correct values
749        self.browser.getControl("Save").click() # submit form
750        # Now go on as an officer
751        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
752        self.browser.open(self.edit_full_path)
753
754        # Create a pseudo image file and select it to be uploaded in form
755        pseudo_image = StringIO('I pretend to be a graphics file')
756        ctrl = self.browser.getControl(name='form.passport')
757        file_ctrl = ctrl.mech_control
758        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
759        passport0 = self.applicant.passport
760        self.browser.getControl("Save").click() # submit form with changed pic
761        passport1 = self.applicant.passport
762        self.browser.getControl("Save").click() # submit form w/o changes
763        passport2 = self.applicant.passport
764        self.assertTrue(passport0 != passport1)
765        self.assertTrue(passport1 == passport2)
766        self.assertTrue(passport1 is passport2)
767        return
768
769    def test_final_submit(self):
770        # Make sure that a correctly filled form with passport picture
771        # can be submitted
772        self.login() # Create applicant form
773        self.fill_correct_values() # fill other fields with correct values
774        # Create a pseudo image file and select it to be uploaded in form
775        pseudo_image = StringIO('I pretend to be a graphics file')
776        ctrl = self.browser.getControl(name='form.passport')
777        file_ctrl = ctrl.mech_control
778        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
779        self.browser.getControl("Final Submit").click() # (finally) submit form
780        self.assertEqual(self.browser.headers['Status'], '200 Ok')
781        self.assertTrue(
782            'Passport confirmation box not ticked' in self.browser.contents)
783        self.browser.getControl(name="confirm_passport").value = True
784        IWorkflowInfo(self.applicant).fireTransition('submit')
785        self.browser.getControl("Final Submit").click() # submit form again
786        self.assertTrue(
787            'Wrong state' in self.browser.contents)
788        IWorkflowInfo(self.applicant).fireTransition('reset1')
789        # Now do the whole thing again but with correct state
790        self.login()
791        self.fill_correct_values()
792        pseudo_image = StringIO('I pretend to be a graphics file')
793        ctrl = self.browser.getControl(name='form.passport')
794        file_ctrl = ctrl.mech_control
795        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
796        self.browser.getControl(name="confirm_passport").value = True
797        self.browser.getControl("Final Submit").click()
798        self.assertTrue(
799            '... submitted ...' in self.browser.contents)
800        self.browser.goBack(count=1)
801        self.browser.getControl("Save").click()
802        self.assertTrue(
803            'The requested form is locked' in self.browser.contents)
804        self.browser.goBack(count=1)
805        #import pdb; pdb.set_trace()
806        self.browser.getControl("Final Submit").click()
807        self.assertTrue(
808            'The requested form is locked' in self.browser.contents)
809        return
810
811    def test_locking(self):
812        # Make sure that locked forms can't be submitted
813        self.login() # Create applicant form
814        self.fill_correct_values() # fill other fields with correct values
815        # Create a pseudo image file and select it to be uploaded in form
816        pseudo_image = StringIO('I pretend to be a graphics file')
817        ctrl = self.browser.getControl(name='form.passport')
818        file_ctrl = ctrl.mech_control
819        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
820        self.browser.getControl("Save").click()
821        self.browser.getLink("Logout").click()
822
823        # Login as manager and lock the form
824        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
825        self.browser.open(self.edit_full_path)
826        self.browser.getControl(name="form.locked").value = True
827        self.browser.getControl("Save").click()
828        self.browser.getLink("Logout").click()
829
830        # Login as applicant again and try to open the edit form
831        self.login()
832        self.browser.open(self.edit_path)
833        self.assertEqual(self.browser.headers['Status'], '200 Ok')
834        #print self.browser.contents
835        self.assertTrue(
836            'The requested form is locked' in self.browser.contents)
837        return
Note: See TracBrowser for help on using the repository browser.