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

Last change on this file since 10131 was 10098, checked in by Henrik Bettermann, 12 years ago

Show containers by default. Only anonymous users must not see hidden containers.

  • Property svn:keywords set to Id
File size: 53.3 KB
Line 
1## $Id: test_browser.py 10098 2013-04-24 05:52:18Z 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 os
22import pytz
23import shutil
24import tempfile
25import grok
26from datetime import datetime
27from StringIO import StringIO
28from datetime import datetime, date, timedelta
29from mechanize import LinkNotFoundError
30from zope.event import notify
31from zope.catalog.interfaces import ICatalog
32from zope.component import createObject, getUtility
33from zope.component.hooks import setSite, clearSite
34from zope.security.interfaces import Unauthorized
35from zope.testbrowser.testing import Browser
36from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
37from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
38from waeup.kofa.app import University
39from waeup.kofa.payments.interfaces import IPayer
40from waeup.kofa.configuration import SessionConfiguration
41from waeup.kofa.applicants.container import ApplicantsContainer
42from waeup.kofa.applicants.applicant import Applicant
43from waeup.kofa.interfaces import (
44    IExtFileStore, IFileStoreNameChooser, IUserAccount)
45from waeup.kofa.university.faculty import Faculty
46from waeup.kofa.university.department import Department
47
48PH_LEN = 15911  # Length of placeholder file
49
50session_1 = datetime.now().year - 2
51container_name_1 = u'app%s' % session_1
52session_2 = datetime.now().year - 1
53container_name_2 = u'app%s' % session_2
54
55class ApplicantsFullSetup(FunctionalTestCase):
56    # A test case that only contains a setup and teardown
57    #
58    # Complete setup for applicants handlings is rather complex and
59    # requires lots of things created before we can start. This is a
60    # setup that does all this, creates a university, creates PINs,
61    # etc.  so that we do not have to bother with that in different
62    # test cases.
63
64    layer = FunctionalLayer
65
66    def setUp(self):
67        super(ApplicantsFullSetup, self).setUp()
68
69        # Setup a sample site for each test
70        app = University()
71        self.dc_root = tempfile.mkdtemp()
72        app['datacenter'].setStoragePath(self.dc_root)
73
74        # Prepopulate the ZODB...
75        self.getRootFolder()['app'] = app
76        # we add the site immediately after creation to the
77        # ZODB. Catalogs and other local utilities are not setup
78        # before that step.
79        self.app = self.getRootFolder()['app']
80        # Set site here. Some of the following setup code might need
81        # to access grok.getSite() and should get our new app then
82        setSite(app)
83
84        self.login_path = 'http://localhost/app/login'
85        self.root_path = 'http://localhost/app/applicants'
86        self.search_path = 'http://localhost/app/applicants/search'
87        self.manage_root_path = self.root_path + '/@@manage'
88        self.add_container_path = self.root_path + '/@@add'
89        self.container_path = 'http://localhost/app/applicants/%s' % container_name_1
90        self.manage_container_path = self.container_path + '/@@manage'
91
92        # Add an applicants container
93        applicantscontainer = ApplicantsContainer()
94        applicantscontainer.code = container_name_1
95        applicantscontainer.prefix = 'app'
96        applicantscontainer.year = session_1
97        applicantscontainer.title = u'This is the %s container' % container_name_1
98        applicantscontainer.application_category = 'basic'
99        applicantscontainer.mode = 'create'
100        applicantscontainer.strict_deadline = True
101        delta = timedelta(days=10)
102        applicantscontainer.startdate = datetime.now(pytz.utc) - delta
103        applicantscontainer.enddate = datetime.now(pytz.utc) + delta
104        self.app['applicants'][container_name_1] = applicantscontainer
105        self.applicantscontainer = self.app['applicants'][container_name_1]
106
107        # Populate university
108        certificate = createObject('waeup.Certificate')
109        certificate.code = 'CERT1'
110        certificate.application_category = 'basic'
111        certificate.start_level = 100
112        certificate.end_level = 500
113        certificate.study_mode = u'ug_ft'
114        self.certificate = certificate
115        self.app['faculties']['fac1'] = Faculty()
116        # The code has explicitely to be set, otherwise we don't
117        # find created students in their department
118        self.app['faculties']['fac1']['dep1'] = Department(code='dep1')
119        self.department = self.app['faculties']['fac1']['dep1']
120        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
121            certificate)
122
123        # Put the prepopulated site into test ZODB and prepare test
124        # browser
125        self.browser = Browser()
126        self.browser.handleErrors = False
127
128        # Create 5 access codes with prefix'FOO' and cost 9.99 each
129        pin_container = self.app['accesscodes']
130        pin_container.createBatch(
131            datetime.now(), 'some_userid', 'APP', 9.99, 5)
132        pins = pin_container[pin_container.keys()[0]].values()
133        self.pins = [x.representation for x in pins]
134        self.existing_pin = self.pins[0]
135        parts = self.existing_pin.split('-')[1:]
136        self.existing_series, self.existing_number = parts
137
138        # Add an applicant
139        self.applicant = createObject('waeup.Applicant')
140        # reg_number is the only field which has to be preset here
141        # because managers are allowed to edit this required field
142        self.applicant.reg_number = u'1234'
143        self.applicant.course1 = certificate
144        app['applicants'][container_name_1].addApplicant(self.applicant)
145        IUserAccount(
146            self.app['applicants'][container_name_1][
147            self.applicant.application_number]).setPassword('apwd')
148        self.manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
149            container_name_1, self.applicant.application_number, 'manage')
150        self.edit_path = 'http://localhost/app/applicants/%s/%s/%s' % (
151            container_name_1, self.applicant.application_number, 'edit')
152        self.view_path = 'http://localhost/app/applicants/%s/%s' % (
153            container_name_1, self.applicant.application_number)
154
155    def login(self):
156        # Perform an applicant login. This creates an applicant record.
157        #
158        # This helper also sets `self.applicant`, which is the
159        # applicant object created.
160        self.browser.open(self.login_path)
161        self.browser.getControl(
162            name="form.login").value = self.applicant.applicant_id
163        self.browser.getControl(name="form.password").value = 'apwd'
164        self.browser.getControl("Login").click()
165
166    def fill_correct_values(self):
167        # Fill the edit form with suitable values
168        self.browser.getControl(name="form.firstname").value = 'John'
169        self.browser.getControl(name="form.middlename").value = 'Anthony'
170        self.browser.getControl(name="form.lastname").value = 'Tester'
171        self.browser.getControl(name="form.course1").value = ['CERT1']
172        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
173        self.browser.getControl(name="form.sex").value = ['m']
174        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
175
176    def tearDown(self):
177        super(ApplicantsFullSetup, self).tearDown()
178        clearSite()
179        shutil.rmtree(self.dc_root)
180
181class ApplicantsRootUITests(ApplicantsFullSetup):
182    # Tests for ApplicantsRoot class
183
184    layer = FunctionalLayer
185
186    def test_anonymous_access(self):
187        # Anonymous users can access applicants root
188        self.browser.open(self.root_path)
189        self.assertEqual(self.browser.headers['Status'], '200 Ok')
190        self.assertFalse(
191            'Manage ' in self.browser.contents)
192        return
193
194    def test_anonymous_no_actions(self):
195        # Make sure anonymous users cannot access actions
196        self.browser.open(self.root_path)
197        self.assertRaises(
198            LookupError, self.browser.getControl, "Add local role")
199        # Manage screen neither linked nor accessible for anonymous
200        self.assertRaises(
201            LinkNotFoundError,
202            self.browser.getLink, 'Manage application section')
203        self.assertRaises(
204            Unauthorized, self.browser.open, self.manage_root_path)
205        # Add container screen not accessible for anonymous
206        self.assertRaises(
207            Unauthorized, self.browser.open, self.add_container_path)
208        return
209
210    def test_manage_access(self):
211        # Managers can access the manage pages of applicants root
212        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
213        self.browser.open(self.root_path)
214        self.assertTrue('Manage application section' in self.browser.contents)
215        # There is a manage link
216        link = self.browser.getLink('Manage application section')
217        link.click()
218        self.assertEqual(self.browser.headers['Status'], '200 Ok')
219        self.assertEqual(self.browser.url, self.manage_root_path)
220        return
221
222    def test_hide_container(self):
223        self.browser.open(self.root_path)
224        self.assertTrue(
225            '<a href="http://localhost/app/applicants/app2011">'
226            'This is the app2011 container</a>' in self.browser.contents)
227        self.app['applicants']['app2011'].hidden = True
228        self.browser.open(self.root_path)
229        # Anonymous users can't see hidden containers
230        self.assertFalse(
231            '<a href="http://localhost/app/applicants/app2011">'
232            'This is the app2011 container</a>' in self.browser.contents)
233        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
234        self.browser.open(self.root_path)
235        self.assertTrue(
236            '<a href="http://localhost/app/applicants/app2011">'
237            'This is the app2011 container</a>' in self.browser.contents)
238        return
239
240    def test_search(self):
241        # Managers can access the manage pages of applicants root
242        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
243        self.browser.open(self.manage_path)
244        self.fill_correct_values()
245        self.browser.getControl("Save").click()
246        self.browser.open(self.root_path)
247        self.assertTrue('Manage application section' in self.browser.contents)
248        # There is a search link
249        link = self.browser.getLink('Search applicants')
250        link.click()
251        self.assertEqual(self.browser.headers['Status'], '200 Ok')
252        # We can find an applicant ...
253        # ... via his name
254        self.browser.getControl(name="searchtype").value = ['fullname']
255        self.browser.getControl(name="searchterm").value = 'John'
256        self.browser.getControl("Search").click()
257        self.assertTrue('John Anthony Tester' in self.browser.contents)
258        self.browser.getControl(name="searchtype").value = ['fullname']
259        self.browser.getControl(name="searchterm").value = 'Tester'
260        self.browser.getControl("Search").click()
261        self.assertTrue('John Anthony Tester' in self.browser.contents)
262        self.browser.open(self.search_path)
263        # ... and via his reg_number ...
264        self.browser.getControl(name="searchtype").value = ['reg_number']
265        self.browser.getControl(name="searchterm").value = '2345'
266        self.browser.getControl("Search").click()
267        self.assertFalse('John Anthony Tester' in self.browser.contents)
268        self.browser.getControl(name="searchtype").value = ['reg_number']
269        self.browser.getControl(name="searchterm").value = '1234'
270        self.browser.getControl("Search").click()
271        self.assertTrue('John Anthony Tester' in self.browser.contents)
272        # ... and not via his application_number ...
273        self.browser.getControl(name="searchtype").value = ['applicant_id']
274        self.browser.getControl(
275            name="searchterm").value = self.applicant.application_number
276        self.browser.getControl("Search").click()
277        self.assertFalse('John Anthony Tester' in self.browser.contents)
278        # ... but ia his applicant_id ...
279        self.browser.getControl(name="searchtype").value = ['applicant_id']
280        self.browser.getControl(
281            name="searchterm").value = self.applicant.applicant_id
282        self.browser.getControl("Search").click()
283        self.assertTrue('John Anthony Tester' in self.browser.contents)
284        # ... and via his email
285        self.browser.getControl(name="searchtype").value = ['email']
286        self.browser.getControl(name="searchterm").value = 'xx@yy.zz'
287        self.browser.getControl("Search").click()
288        self.assertTrue('John Anthony Tester' in self.browser.contents)
289        return
290
291    def test_manage_actions_access(self):
292        # Managers can access the action on manage screen
293        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
294        self.browser.open(self.manage_root_path)
295        self.browser.getControl("Add local role").click()
296        self.assertTrue('No user selected' in self.browser.contents)
297        return
298
299    # We have no local roles yet
300    #def test_local_roles_add_delete(self):
301    #    # Managers can assign and delete local roles of applicants root
302    #    myusers = self.app['users']
303    #    myusers.addUser('bob', 'bobssecret')
304    #    self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
305    #    self.browser.open(self.manage_root_path)
306    #    self.browser.getControl(name="user").value = ['bob']
307    #    self.browser.getControl(name="local_role").value = [
308    #        'waeup.local.ApplicationsOfficer']
309    #    self.browser.getControl("Add local role").click()
310    #    self.assertTrue('<td>bob</td>' in self.browser.contents)
311    #    # Remove the role assigned
312    #    ctrl = self.browser.getControl(name='role_id')
313    #    ctrl.getControl(value='bob|waeup.ApplicationsOfficer').selected = True
314    #    self.browser.getControl("Remove selected local roles").click()
315    #    self.assertTrue('Successfully removed:' in self.browser.contents)
316    #    self.assertFalse('<td>bob</td>' in self.browser.contents)
317    #    return
318
319    def test_add_delete_container(self):
320        # Managers can add and delete applicants containers
321        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
322        self.browser.open(self.manage_root_path)
323        self.browser.getControl("Add applicants container").click()
324        self.assertEqual(self.browser.headers['Status'], '200 Ok')
325        self.assertEqual(self.browser.url, self.add_container_path)
326        self.browser.getControl(name="form.prefix").value = ['app']
327        self.browser.getControl("Add applicants container").click()
328        self.assertTrue(
329            'There were errors' in self.browser.contents)
330        self.browser.getControl(name="form.prefix").value = ['app']
331        self.browser.getControl(name="form.year").value = [str(session_2)]
332        self.browser.getControl(name="form.mode").value = ['create']
333        self.browser.getControl(
334            name="form.application_category").value = ['basic']
335        self.browser.getControl("Add applicants container").click()
336        self.assertTrue('Added:' in self.browser.contents)
337        self.browser.getLink("app2011").click()
338        self.assertTrue('Manage applicants container'
339            in self.browser.contents)
340        self.browser.open(self.add_container_path)
341        self.browser.getControl("Cancel").click()
342        self.assertEqual(self.browser.url, self.manage_root_path)
343        self.browser.open(self.add_container_path)
344        self.browser.getControl(name="form.prefix").value = ['app']
345        self.browser.getControl(name="form.year").value = [str(session_2)]
346        self.browser.getControl(name="form.mode").value = ['create']
347        self.browser.getControl(
348            name="form.application_category").value = ['basic']
349        self.browser.getControl("Add applicants container").click()
350        self.assertTrue('exists already in the database'
351                        in self.browser.contents)
352        self.browser.open(self.manage_root_path)
353        ctrl = self.browser.getControl(name='val_id')
354        ctrl.getControl(value=container_name_2).selected = True
355        self.browser.getControl("Remove selected", index=0).click()
356        self.assertTrue('Successfully removed:' in self.browser.contents)
357        self.browser.open(self.add_container_path)
358        self.browser.getControl(name="form.prefix").value = ['app']
359        self.browser.getControl(name="form.year").value = [str(session_2)]
360        self.browser.getControl(name="form.mode").value = ['create']
361        #self.browser.getControl(name="form.ac_prefix").value = ['APP']
362        self.browser.getControl(
363            name="form.application_category").value = ['basic']
364        self.browser.getControl("Add applicants container").click()
365        del self.app['applicants'][container_name_2]
366        ctrl = self.browser.getControl(name='val_id')
367        ctrl.getControl(value=container_name_2).selected = True
368        self.browser.getControl("Remove selected", index=0).click()
369        self.assertMatches('...Could not delete...', self.browser.contents)
370        return
371
372class ApplicantsContainerUITests(ApplicantsFullSetup):
373    # Tests for ApplicantsContainer class views and pages
374
375    layer = FunctionalLayer
376
377    def test_anonymous_access(self):
378        # Anonymous users can access applicants containers
379        self.browser.open(self.container_path)
380        self.assertEqual(self.browser.headers['Status'], '200 Ok')
381        self.assertFalse(
382            'Manage ' in self.browser.contents)
383        return
384
385    def test_manage_access(self):
386        # Managers can access the manage pages of applicants
387        # containers and can perform actions
388        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
389        self.browser.open(self.manage_container_path)
390        self.assertEqual(self.browser.headers['Status'], '200 Ok')
391        self.assertEqual(self.browser.url, self.manage_container_path)
392        self.browser.getControl(name="form.application_fee").value = '200'
393        self.browser.getControl("Save").click()
394        self.assertTrue('Form has been saved' in self.browser.contents)
395        logfile = os.path.join(
396            self.app['datacenter'].storage, 'logs', 'applicants.log')
397        logcontent = open(logfile).read()
398        self.assertTrue(
399            'zope.mgr - applicants.browser.ApplicantsContainerManageFormPage - '
400            'app2011 - saved: application_fee\n' in logcontent)
401        self.browser.getControl("Remove selected", index=0).click()
402        self.assertTrue('No applicant selected' in self.browser.contents)
403        self.browser.getControl("Add local role").click()
404        self.assertTrue('No user selected' in self.browser.contents)
405        self.browser.getControl("Cancel", index=0).click()
406        self.assertEqual(self.browser.url, self.container_path)
407        return
408
409    def test_statistics(self):
410        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
411        self.browser.open(self.container_path)
412        self.browser.getLink("Container statistics").click()
413        self.assertTrue('<td>initialized</td>' in self.browser.contents)
414        self.assertTrue('<td>1</td>' in self.browser.contents)
415        self.assertEqual(self.applicantscontainer.statistics[0],
416            {'not admitted': 0, 'started': 0, 'created': 0,
417            'admitted': 0, 'submitted': 0, 'initialized': 1, 'paid': 0})
418        #self.assertEqual(self.applicantscontainer.statistics[1],
419        #    {u'fac1': 0})
420        IWorkflowState(self.applicant).setState('submitted')
421        notify(grok.ObjectModifiedEvent(self.applicant))
422        self.assertEqual(self.applicantscontainer.statistics[0],
423            {'not admitted': 0, 'started': 0, 'created': 0,
424            'admitted': 0, 'submitted': 1, 'initialized': 0, 'paid': 0})
425        #self.assertEqual(self.applicantscontainer.statistics[1],
426        #    {u'fac1': 1})
427        return
428
429    def test_add_delete_applicants(self):
430        # Managers can add and delete applicants
431        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
432        self.add_applicant_path = self.container_path + '/addapplicant'
433        self.container_manage_path = self.container_path + '/@@manage'
434        self.browser.open(self.container_manage_path)
435        self.browser.getLink("Add applicant").click()
436        self.assertEqual(self.browser.headers['Status'], '200 Ok')
437        self.assertEqual(self.browser.url, self.add_applicant_path)
438        self.browser.getControl(name="form.firstname").value = 'Alois'
439        self.browser.getControl(name="form.middlename").value = 'Kofi'
440        self.browser.getControl(name="form.lastname").value = 'Bettermann'
441        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
442        self.browser.getControl("Create application record").click()
443        self.assertTrue('Application initialized' in self.browser.contents)
444        self.browser.open(self.container_manage_path)
445        self.assertEqual(self.browser.headers['Status'], '200 Ok')
446        ctrl = self.browser.getControl(name='val_id')
447        value = ctrl.options[0]
448        ctrl.getControl(value=value).selected = True
449        self.browser.getControl("Remove selected", index=0).click()
450        self.assertTrue('Successfully removed:' in self.browser.contents)
451        self.browser.open(self.add_applicant_path)
452        self.browser.getControl(name="form.firstname").value = 'Albert'
453        self.browser.getControl(name="form.lastname").value = 'Einstein'
454        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
455        self.browser.getControl("Create application record").click()
456        self.assertTrue('Application initialized' in self.browser.contents)
457        return
458
459class ApplicantUITests(ApplicantsFullSetup):
460    # Tests for uploading/browsing the passport image of appplicants
461
462    layer = FunctionalLayer
463
464    def test_manage_and_view_applicant(self):
465        # Managers can manage applicants
466        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
467        self.slip_path = self.view_path + '/application_slip.pdf'
468        self.browser.open(self.manage_path)
469        self.assertEqual(self.browser.headers['Status'], '200 Ok')
470        self.fill_correct_values()
471        # Fire transition
472        self.browser.getControl(name="transition").value = ['start']
473        self.browser.getControl("Save").click()
474        # Be sure that the empty phone field does not show wrong error message
475        self.assertFalse('Required input is missing' in self.browser.contents)
476        self.assertMatches('...Form has been saved...', self.browser.contents)
477        self.assertMatches('...Application started by Manager...',
478                           self.browser.contents)
479        self.browser.open(self.view_path)
480        self.assertEqual(self.browser.headers['Status'], '200 Ok')
481        # Change course_admitted
482        self.browser.open(self.manage_path)
483        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
484        self.browser.getControl("Save").click()
485        self.assertMatches('...Form has been saved...', self.browser.contents)
486        # Change password
487        self.browser.getControl(name="password").value = 'secret'
488        self.browser.getControl(name="control_password").value = 'secre'
489        self.browser.getControl("Save").click()
490        self.assertMatches('...Passwords do not match...',
491                           self.browser.contents)
492        self.browser.getControl(name="password").value = 'secret'
493        self.browser.getControl(name="control_password").value = 'secret'
494        self.browser.getControl("Save").click()
495        self.assertMatches('...Form has been saved...', self.browser.contents)
496        # Pdf slip can't be opened and download button is not available
497        self.assertFalse('Download application slip' in self.browser.contents)
498        self.browser.open(self.slip_path)
499        self.assertTrue(
500            'Please pay and submit before trying to download the application slip.'
501            in self.browser.contents)
502        # If applicant is in correct state the pdf slip can be opened.
503        IWorkflowState(self.applicant).setState('submitted')
504        self.browser.open(self.manage_path)
505        self.browser.getLink("Download application slip").click()
506        self.assertEqual(self.browser.headers['Status'], '200 Ok')
507        self.assertEqual(self.browser.headers['Content-Type'],
508                         'application/pdf')
509        # Managers can view applicants even if certificate has been removed
510        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
511        self.browser.open(self.view_path)
512        self.assertEqual(self.browser.headers['Status'], '200 Ok')
513        self.browser.open(self.slip_path)
514        self.assertEqual(self.browser.headers['Status'], '200 Ok')
515        return
516
517    def test_passport_edit_view(self):
518        # We get a default image after login
519        self.browser.open(self.login_path)
520        self.login()
521        self.browser.open(self.browser.url + '/passport.jpg')
522        self.assertEqual(self.browser.headers['status'], '200 Ok')
523        self.assertEqual(self.browser.headers['content-type'], 'image/jpeg')
524        self.assertTrue('JFIF' in self.browser.contents)
525        self.assertEqual(
526            self.browser.headers['content-length'], str(PH_LEN))
527
528    def test_applicant_login(self):
529        self.applicant.suspended = True
530        self.login()
531        self.assertTrue(
532            'You entered invalid credentials.' in self.browser.contents)
533        self.applicant.suspended = False
534        self.browser.getControl("Login").click()
535        self.assertTrue(
536            'You logged in.' in self.browser.contents)
537
538    def test_applicant_access(self):
539        # Applicants can edit their record
540        self.browser.open(self.login_path)
541        self.login()
542        self.assertTrue(
543            'You logged in.' in self.browser.contents)
544        self.browser.open(self.edit_path)
545        self.assertTrue(self.browser.url != self.login_path)
546        self.assertEqual(self.browser.headers['Status'], '200 Ok')
547        self.fill_correct_values()
548        self.assertTrue(IUserAccount(self.applicant).checkPassword('apwd'))
549        self.browser.getControl("Save").click()
550        self.assertMatches('...Form has been saved...', self.browser.contents)
551        # Applicants don't see manage and search links ...
552        self.browser.open(self.root_path)
553        self.assertEqual(self.browser.headers['Status'], '200 Ok')
554        self.assertFalse('Search' in self.browser.contents)
555        self.assertFalse('Manage application section' in self.browser.contents)
556        # ... and can't access the manage page
557        self.assertRaises(
558            Unauthorized, self.browser.open, self.manage_path)
559        return
560
561    def image_url(self, filename):
562        return self.edit_path.replace('edit', filename)
563
564    def test_after_login_default_browsable(self):
565        # After login we see the placeholder image in the edit view
566        self.login()
567        self.assertEqual(self.browser.url, self.view_path)
568        self.browser.open(self.edit_path)
569        # There is a correct <img> link included
570        self.assertTrue(
571              '<img src="passport.jpg" height="180px" />' in self.browser.contents)
572        # Browsing the link shows a real image
573        self.browser.open(self.image_url('passport.jpg'))
574        self.assertEqual(
575            self.browser.headers['content-type'], 'image/jpeg')
576        self.assertEqual(len(self.browser.contents), PH_LEN)
577
578    def test_after_submit_default_browsable(self):
579        # After submitting an applicant form the default image is
580        # still visible
581        self.login()
582        self.browser.open(self.edit_path)
583        self.browser.getControl("Save").click() # submit form
584        # There is a correct <img> link included
585        self.assertTrue(
586            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
587        # Browsing the link shows a real image
588        self.browser.open(self.image_url('passport.jpg'))
589        self.assertEqual(
590            self.browser.headers['content-type'], 'image/jpeg')
591        self.assertEqual(len(self.browser.contents), PH_LEN)
592
593    def test_uploaded_image_respects_file_size_restriction(self):
594        # When we upload an image that is too big ( > 10 KB) we will
595        # get an error message
596        self.login()
597        self.browser.open(self.edit_path)
598        # Create a pseudo image file and select it to be uploaded in form
599        photo_content = 'A' * 1024 * 21  # A string of 21 KB size
600        pseudo_image = StringIO(photo_content)
601        ctrl = self.browser.getControl(name='form.passport')
602        file_ctrl = ctrl.mech_control
603        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
604        self.browser.getControl("Save").click() # submit form
605        # There is a correct <img> link included
606        self.assertTrue(
607            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
608        # We get a warning message
609        self.assertTrue(
610            'Uploaded image is too big' in self.browser.contents)
611        # Browsing the image gives us the default image, not the
612        # uploaded one.
613        self.browser.open(self.image_url('passport.jpg'))
614        self.assertEqual(
615            self.browser.headers['content-type'], 'image/jpeg')
616        self.assertEqual(len(self.browser.contents), PH_LEN)
617        # There is really no file stored for the applicant
618        img = getUtility(IExtFileStore).getFile(
619            IFileStoreNameChooser(self.applicant).chooseName())
620        self.assertTrue(img is None)
621
622    def test_uploaded_image_browsable_w_errors(self):
623        # We can upload a different image and browse it after submit,
624        # even if there are still errors in the form
625        self.login()
626        self.browser.open(self.edit_path)
627        # Create a pseudo image file and select it to be uploaded in form
628        photo_content = 'I pretend to be a graphics file'
629        pseudo_image = StringIO(photo_content)
630        ctrl = self.browser.getControl(name='form.passport')
631        file_ctrl = ctrl.mech_control
632        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
633        self.browser.getControl("Save").click() # submit form
634        # There is a correct <img> link included
635        self.assertTrue(
636            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
637        # Browsing the link shows a real image
638        self.browser.open(self.image_url('passport.jpg'))
639        self.assertEqual(
640            self.browser.headers['content-type'], 'image/jpeg')
641        self.assertEqual(self.browser.contents, photo_content)
642
643    def test_uploaded_image_stored_in_imagestorage_w_errors(self):
644        # After uploading a new passport pic the file is correctly
645        # stored in an imagestorage
646        self.login()
647        self.browser.open(self.edit_path)
648        # Create a pseudo image file and select it to be uploaded in form
649        pseudo_image = StringIO('I pretend to be a graphics file')
650        ctrl = self.browser.getControl(name='form.passport')
651        file_ctrl = ctrl.mech_control
652        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
653        self.browser.getControl("Save").click() # submit form
654        storage = getUtility(IExtFileStore)
655        file_id = IFileStoreNameChooser(self.applicant).chooseName()
656        pseudo_image.seek(0) # reset our file data source
657        self.assertEqual(
658            storage.getFile(file_id).read(), pseudo_image.read())
659        return
660
661    def test_uploaded_image_browsable_wo_errors(self):
662        # We can upload a different image and browse it after submit,
663        # if there are no errors in form
664        self.login()
665        self.browser.open(self.edit_path)
666        self.fill_correct_values() # fill other fields with correct values
667        # Create a pseudo image file and select it to be uploaded in form
668        pseudo_image = StringIO('I pretend to be a graphics file')
669        ctrl = self.browser.getControl(name='form.passport')
670        file_ctrl = ctrl.mech_control
671        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
672        self.browser.getControl("Save").click() # submit form
673        # There is a correct <img> link included
674        self.assertTrue(
675            '<img src="passport.jpg" height="180px" />' in self.browser.contents)
676        # Browsing the link shows a real image
677        self.browser.open(self.image_url('passport.jpg'))
678        self.assertEqual(
679            self.browser.headers['content-type'], 'image/jpeg')
680        self.assertEqual(len(self.browser.contents), 31)
681
682    def test_uploaded_image_stored_in_imagestorage_wo_errors(self):
683        # After uploading a new passport pic the file is correctly
684        # stored in an imagestorage if form contains no errors
685        self.login()
686        self.browser.open(self.edit_path)
687        self.fill_correct_values() # fill other fields with correct values
688        # Create a pseudo image file and select it to be uploaded in form
689        pseudo_image = StringIO('I pretend to be a graphics file')
690        ctrl = self.browser.getControl(name='form.passport')
691        file_ctrl = ctrl.mech_control
692        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
693        self.browser.getControl("Save").click() # submit form
694        storage = getUtility(IExtFileStore)
695        file_id = IFileStoreNameChooser(self.applicant).chooseName()
696        # The stored image can be fetched
697        fd = storage.getFile(file_id)
698        file_len = len(fd.read())
699        self.assertEqual(file_len, 31)
700
701    def test_uploaded_images_equal(self):
702        # Make sure uploaded images do really differ if we eject a
703        # change notfication (and do not if we don't)
704        self.login()
705        self.browser.open(self.edit_path)
706        self.fill_correct_values() # fill other fields with correct values
707        self.browser.getControl("Save").click() # submit form
708        # Now go on as an officer
709        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
710        self.browser.open(self.manage_path)
711
712        # Create a pseudo image file and select it to be uploaded in form
713        pseudo_image = StringIO('I pretend to be a graphics file')
714        ctrl = self.browser.getControl(name='form.passport')
715        file_ctrl = ctrl.mech_control
716        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
717        file_id = IFileStoreNameChooser(self.applicant).chooseName()
718        setSite(self.app)
719        passport0 = getUtility(IExtFileStore).getFile(file_id)
720        self.browser.getControl("Save").click() # submit form with changed pic
721        passport1 = getUtility(IExtFileStore).getFile(file_id).read()
722        self.browser.getControl("Save").click() # submit form w/o changes
723        passport2 = getUtility(IExtFileStore).getFile(file_id).read()
724        self.assertTrue(passport0 is None)
725        self.assertTrue(passport0 != passport1)
726        self.assertTrue(passport1 == passport2)
727        return
728
729    def test_upload_image_by_manager_with_logging(self):
730        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
731        self.browser.open(self.manage_path)
732        # Create a pseudo image file and select it to be uploaded in form
733        photo_content = 'A' * 1024 * 5  # A string of 5 KB size
734        pseudo_image = StringIO(photo_content)
735        ctrl = self.browser.getControl(name='form.passport')
736        file_ctrl = ctrl.mech_control
737        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
738        self.browser.getControl("Save").click() # submit form
739        # Even though the form could not be saved ...
740        self.assertTrue(
741            'Required input is missing' in self.browser.contents)
742        # ... the file has been successfully uploaded
743        logfile = os.path.join(
744            self.app['datacenter'].storage, 'logs', 'applicants.log')
745        logcontent = open(logfile).read()
746        self.assertTrue(
747            'zope.mgr - applicants.browser.ApplicantManageFormPage - '
748            '%s - saved: passport'
749            % (self.applicant.applicant_id)
750            in logcontent)
751
752    def test_pay_application_fee(self):
753        self.login()
754        self.browser.open(self.edit_path)
755        # Payment tickets can't be created before the form has been validated
756        self.browser.getControl("Add online payment ticket").click()
757        self.assertTrue('Required input is missing' in self.browser.contents)
758        self.fill_correct_values()
759        # We have to save the form otherwise the filled fields will be cleared
760        # after adding an online payment, because adding an online payment
761        # requires a filled form but does not save it
762        self.browser.getControl("Save").click()
763        self.browser.getControl("Add online payment ticket").click()
764        # Session object missing
765        self.assertTrue(
766            'Session configuration object is not available'
767            in self.browser.contents)
768        configuration = SessionConfiguration()
769        configuration.academic_session = session_1
770        configuration.application_fee = 200.0
771        self.app['configuration'].addSessionConfiguration(configuration)
772        self.browser.open(self.edit_path)
773        self.browser.getControl("Add online payment ticket").click()
774        self.assertMatches('...Payment ticket created...',
775                           self.browser.contents)
776        self.assertMatches('...Activation Code...',
777                           self.browser.contents)
778        # Payment ticket can be removed if they haven't received a
779        # valid callback
780        self.browser.open(self.edit_path)
781        ctrl = self.browser.getControl(name='val_id')
782        value = ctrl.options[0]
783        ctrl.getControl(value=value).selected = True
784        self.browser.getControl("Remove selected", index=0).click()
785        self.assertMatches('...Successfully removed...', self.browser.contents)
786        # We will try the callback request view
787        self.browser.getControl("Add online payment ticket").click()
788        self.browser.open(self.edit_path)
789        ctrl = self.browser.getControl(name='val_id')
790        value = ctrl.options[0]
791        self.browser.getLink(value).click()
792        self.assertMatches('...Amount Authorized...',
793                           self.browser.contents)
794        payment_url = self.browser.url
795        payment_id = self.applicant.keys()[0]
796        payment = self.applicant[payment_id]
797        self.assertEqual(payment.p_item,'This is the %s container' % container_name_1)
798        self.assertEqual(payment.p_session, session_1)
799        self.assertEqual(payment.p_category,'application')
800        self.assertEqual(payment.amount_auth,200.0)
801        # Applicant is payer of the payment ticket.
802        self.assertEqual(
803            IPayer(payment).display_fullname, 'John Anthony Tester')
804        self.assertEqual(
805            IPayer(payment).id, self.applicant.applicant_id)
806        self.assertEqual(IPayer(payment).faculty, '')
807        self.assertEqual(IPayer(payment).department, '')
808        # The pdf payment slip can't yet be opened
809        #self.browser.open(payment_url + '/payment_receipt.pdf')
810        #self.assertMatches('...Ticket not yet paid...',
811        #                   self.browser.contents)
812        # Approve payment
813        # Applicants can't approve payments
814        self.assertRaises(
815            Unauthorized, self.browser.open, payment_url + '/approve')
816        # We approve the payment by bypassing the view
817        payment.approve()
818        # The payment slip can be downloaded now
819        self.browser.open(payment_url)
820        self.browser.getLink("Download payment slip").click()
821        self.assertEqual(self.browser.headers['Status'], '200 Ok')
822        self.assertEqual(self.browser.headers['Content-Type'],
823                         'application/pdf')
824        # Applicant is is not yet in state 'paid' because it was only
825        # the payment which we set to paid
826        self.browser.open(self.view_path)
827        self.assertMatches('...started...',
828                           self.browser.contents)
829        self.assertTrue(self.applicant.state == 'started')
830        # Let's logout and approve the payment as manager
831        self.browser.getLink("Logout").click()
832        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
833        # First we reset the payment
834        payment.r_amount_approved = 0.0
835        payment.r_code = u''
836        payment.p_state = 'unpaid'
837        payment.r_desc = u''
838        payment.payment_date = None
839        self.browser.open(payment_url)
840        self.browser.getLink("Approve payment").click()
841        self.assertEqual(payment.p_state, 'paid')
842        self.assertEqual(payment.r_amount_approved, 200.0)
843        self.assertEqual(payment.r_code, 'AP')
844        self.assertTrue(self.applicant.state == 'paid')
845        # Approval is logged in students.log ...
846        logfile = os.path.join(
847            self.app['datacenter'].storage, 'logs', 'applicants.log')
848        logcontent = open(logfile).read()
849        self.assertTrue(
850            'zope.mgr - applicants.browser.OnlinePaymentApprovePage - '
851            '%s - payment approved' % self.applicant.applicant_id
852            in logcontent)
853        # ... and in payments.log
854        logfile = os.path.join(
855            self.app['datacenter'].storage, 'logs', 'payments.log')
856        logcontent = open(logfile).read()
857        self.assertTrue(
858            '"zope.mgr",%s,%s,application,200.0,AP,,,,,,\n'
859            % (self.applicant.applicant_id, payment.p_id)
860            in logcontent)
861        return
862
863    def test_final_submit(self):
864        # Make sure that a correctly filled form with passport picture
865        # can be submitted (only) after payment
866        self.login()
867        self.browser.getLink("Edit application record").click()
868        self.assertFalse('Final Submit' in self.browser.contents)
869        IWorkflowInfo(self.applicant).fireTransition('pay')
870        self.browser.open(self.edit_path)
871        self.assertTrue('Final Submit' in self.browser.contents)
872        self.fill_correct_values() # fill other fields with correct values
873        self.browser.getControl("Save").click()
874        self.browser.getControl("Final Submit").click()
875        # We forgot to upload a passport picture
876        self.assertTrue(
877            'No passport picture uploaded' in self.browser.contents)
878        # Create a pseudo image file and select it to be uploaded in form
879        pseudo_image = StringIO('I pretend to be a graphics file')
880        ctrl = self.browser.getControl(name='form.passport')
881        file_ctrl = ctrl.mech_control
882        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
883        self.browser.getControl("Final Submit").click() # (finally) submit form
884        # The picture has been uploaded but the form cannot be submitted
885        # since the passport confirmation box was not ticked
886        self.assertTrue(
887            'Passport picture confirmation box not ticked'
888            in self.browser.contents)
889        self.browser.getControl(name="confirm_passport").value = True
890        # If application period has expired and strict-deadline is set
891        # applicants do notsee edit button and can't open
892        # the edit form.
893        self.applicantscontainer.enddate = datetime.now(pytz.utc)
894        self.browser.open(self.view_path)
895        self.assertFalse(
896            'Edit application record' in self.browser.contents)
897        self.browser.open(self.edit_path)
898        self.assertTrue(
899            'form is locked' in self.browser.contents)
900        # We can either postpone the enddate ...
901        self.applicantscontainer.enddate = datetime.now(
902            pytz.utc) + timedelta(days=10)
903        self.browser.open(self.edit_path)
904        self.browser.getControl(name="confirm_passport").value = True
905        self.browser.getControl("Final Submit").click()
906        self.assertTrue(
907            'Application submitted' in self.browser.contents)
908        # ... or allow submission after deadline.
909        IWorkflowState(self.applicant).setState('paid')
910        self.applicant.locked = False
911        self.applicantscontainer.strict_deadline = False
912        self.browser.open(self.edit_path)
913        self.browser.getControl(name="confirm_passport").value = True
914        self.browser.getControl("Final Submit").click()
915        self.assertTrue(
916            'Application submitted' in self.browser.contents)
917        self.browser.goBack(count=1)
918        self.browser.getControl("Save").click()
919        # The form is locked.
920        self.assertTrue(self.applicant.locked)
921        self.assertTrue(
922            'The requested form is locked' in self.browser.contents)
923        self.browser.goBack(count=1)
924        self.browser.getControl("Final Submit").click()
925        self.assertTrue(
926            'The requested form is locked' in self.browser.contents)
927        return
928
929    def test_locking(self):
930        # Make sure that locked forms can't be submitted
931        self.login()
932        self.browser.open(self.edit_path)
933        self.fill_correct_values() # fill other fields with correct values
934        # Create a pseudo image file and select it to be uploaded in form
935        pseudo_image = StringIO('I pretend to be a graphics file')
936        ctrl = self.browser.getControl(name='form.passport')
937        file_ctrl = ctrl.mech_control
938        file_ctrl.add_file(pseudo_image, filename='myphoto.jpg')
939        self.browser.getControl("Save").click()
940        # Now we lock the form
941        self.applicant.locked = True
942        self.browser.open(self.edit_path)
943        self.assertEqual(self.browser.headers['Status'], '200 Ok')
944        self.assertTrue(
945            'The requested form is locked' in self.browser.contents)
946        return
947
948    def test_certificate_removed(self):
949        self.login()
950        self.browser.open(self.edit_path)
951        self.fill_correct_values()
952        self.browser.getControl("Save").click()
953        self.browser.open(self.view_path)
954        self.assertTrue(
955            'Unnamed Certificate' in self.browser.contents)
956        self.browser.open(self.edit_path)
957        self.assertTrue(
958            '<option selected="selected" value="CERT1">' in self.browser.contents)
959        # Now we remove the certificate
960        del self.app['faculties']['fac1']['dep1'].certificates['CERT1']
961        # The certificate is still shown in display mode
962        self.browser.open(self.view_path)
963        self.assertTrue(
964            'Unnamed Certificate' in self.browser.contents)
965        # The certificate is still selectable in edit mode so that it won't
966        # be automatically replaced by another (arbitrary) certificate
967        self.browser.open(self.edit_path)
968        self.assertTrue(
969            '<option selected="selected" value="CERT1">' in self.browser.contents)
970        # Consequently, the certificate is still shown after saving the form
971        self.browser.getControl("Save").click()
972        self.browser.open(self.view_path)
973        self.assertTrue(
974            'Unnamed Certificate' in self.browser.contents)
975        # Even if we add a new certificate the previous (removed)
976        # certificate is shown
977        certificate = createObject('waeup.Certificate')
978        certificate.code = 'CERT2'
979        certificate.title = 'New Certificate'
980        certificate.application_category = 'basic'
981        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
982            certificate)
983        self.browser.open(self.edit_path)
984        self.assertTrue(
985            '<option selected="selected" value="CERT1">'
986            in self.browser.contents)
987
988class ApplicantRegisterTests(ApplicantsFullSetup):
989    # Tests for applicant registration
990
991    layer = FunctionalLayer
992
993    def test_register_applicant_create(self):
994        # An applicant can register himself.
995        self.browser.open(self.container_path)
996        self.browser.getLink("Register for application").click()
997        # Fill the edit form with suitable values
998        self.browser.getControl(name="form.firstname").value = 'Anna'
999        self.browser.getControl(name="form.lastname").value = 'Kurios'
1000        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1001        self.browser.getControl(name="form.phone.country").value = ['+234']
1002        self.browser.getControl(name="form.phone.area").value = '555'
1003        self.browser.getControl(name="form.phone.ext").value = '6666666'
1004        self.browser.getControl("Send login credentials").click()
1005        self.assertEqual(self.browser.url,
1006            self.container_path + '/registration_complete?email=xx%40yy.zz')
1007        # The new applicant can be found in the catalog via the email address
1008        cat = getUtility(ICatalog, name='applicants_catalog')
1009        results = list(
1010            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
1011        applicant = results[0]
1012        self.assertEqual(applicant.lastname,'Kurios')
1013        # The application_id has been copied to the reg_number
1014        self.assertEqual(applicant.applicant_id, applicant.reg_number)
1015        # The applicant can be found in the catalog via the reg_number
1016        results = list(
1017            cat.searchResults(
1018            reg_number=(applicant.reg_number, applicant.reg_number)))
1019        self.assertEqual(applicant,results[0])
1020        return
1021
1022    def test_register_applicant_update(self):
1023        # We change the application mode and check if applicants
1024        # can find and update imported records instead of creating new records.
1025        # First we check what happens if record does not exist.
1026        self.applicantscontainer.mode = 'update'
1027        self.browser.open(self.container_path + '/register')
1028        self.browser.getControl(name="form.firstname").value = 'John'
1029        self.browser.getControl(name="form.reg_number").value = 'anynumber'
1030        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1031        self.browser.getControl("Send login credentials").click()
1032        self.assertTrue('No application record found.'
1033            in self.browser.contents)
1034        # Even with the correct reg_number we can't register
1035        # because firstname attribute is not set.
1036        self.applicantscontainer.mode = 'update'
1037        self.browser.open(self.container_path + '/register')
1038        self.browser.getControl(name="form.firstname").value = 'John'
1039        self.browser.getControl(name="form.reg_number").value = '1234'
1040        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1041        self.browser.getControl("Send login credentials").click()
1042        self.assertTrue('An error occurred.' in self.browser.contents)
1043        # Let's set this attribute manually
1044        # and try to register with a wrong name.
1045        self.applicant.firstname = u'John'
1046        self.browser.open(self.container_path + '/register')
1047        self.browser.getControl(name="form.firstname").value = 'Johnny'
1048        self.browser.getControl(name="form.reg_number").value = '1234'
1049        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
1050        self.browser.getControl("Send login credentials").click()
1051        # Anonymous is not informed that firstname verification failed.
1052        # It seems that the record doesn't exist.
1053        self.assertTrue('No application record found.'
1054            in self.browser.contents)
1055        # Even with the correct firstname we can't register if a
1056        # password has been set and used.
1057        IWorkflowState(self.applicant).setState('started')
1058        self.browser.getControl(name="form.firstname").value = 'John'
1059        self.browser.getControl(name="form.reg_number").value = '1234'
1060        self.browser.getControl("Send login credentials").click()
1061        self.assertTrue('Your password has already been set and used.'
1062            in self.browser.contents)
1063        #IUserAccount(
1064        #    self.app['applicants'][container_name_1][
1065        #    self.applicant.application_number]).context.password = None
1066        # Even without unsetting the password we can re-register if state
1067        # is 'initialized'
1068        IWorkflowState(self.applicant).setState('initialized')
1069        self.browser.open(self.container_path + '/register')
1070        # The firstname field, used for verification, is not case-sensitive.
1071        self.browser.getControl(name="form.firstname").value = 'jOhn'
1072        self.browser.getControl(name="form.reg_number").value = '1234'
1073        self.browser.getControl(name="form.email").value = 'new@yy.zz'
1074        self.browser.getControl("Send login credentials").click()
1075        # Yeah, we succeded ...
1076        self.assertTrue('Your registration was successful.'
1077            in self.browser.contents)
1078        # ... and  applicant can be found in the catalog via the email address
1079        cat = getUtility(ICatalog, name='applicants_catalog')
1080        results = list(
1081            cat.searchResults(
1082            email=('new@yy.zz', 'new@yy.zz')))
1083        self.assertEqual(self.applicant,results[0])
1084        return
1085
1086    def test_change_password_request(self):
1087        self.browser.open('http://localhost/app/changepw')
1088        self.browser.getControl(name="form.identifier").value = '1234'
1089        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1090        self.browser.getControl("Send login credentials").click()
1091        self.assertTrue('No record found' in self.browser.contents)
1092        self.applicant.email = 'aa@aa.ng'
1093        # Update the catalog
1094        notify(grok.ObjectModifiedEvent(self.applicant))
1095        self.browser.open('http://localhost/app/changepw')
1096        self.browser.getControl(name="form.identifier").value = '1234'
1097        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
1098        self.browser.getControl("Send login credentials").click()
1099        self.assertTrue(
1100            'An email with your user name and password has been sent'
1101            in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.