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

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

Application is only allowed between start and end time. Show dates on login page and logout applicants if current time exceeds these limits.

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