source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/applicants/tests/test_browser.py @ 11260

Last change on this file since 11260 was 10899, checked in by Henrik Bettermann, 11 years ago

Fix tests.

  • Property svn:keywords set to Id
File size: 20.9 KB
Line 
1## $Id: test_browser.py 10899 2014-01-13 08:55:58Z 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##
18import os
19import shutil
20import tempfile
21import datetime
22import grok
23import pytz
24from zope.event import notify
25from zope.intid.interfaces import IIntIds
26from zope.interface.verify import verifyClass, verifyObject
27from zope.schema.interfaces import ConstraintNotSatisfied
28from zope.component.hooks import setSite, clearSite
29from zope.component import createObject, getUtility
30from zope.catalog.interfaces import ICatalog
31from zope.testbrowser.testing import Browser
32from hurry.workflow.interfaces import IWorkflowState
33from waeup.kofa.app import University
34from waeup.kofa.university.faculty import Faculty
35from waeup.kofa.university.department import Department
36from waeup.kofa.testing import FunctionalTestCase
37from waeup.kofa.configuration import SessionConfiguration
38from waeup.kofa.applicants.container import ApplicantsContainer
39from waeup.kofa.applicants.tests.test_batching import ApplicantImportExportSetup
40from waeup.kofa.interfaces import IBatchProcessor
41from kofacustom.nigeria.testing import FunctionalLayer
42from kofacustom.nigeria.applicants.export import NigeriaApplicantsExporter
43from kofacustom.nigeria.applicants.batching import NigeriaApplicantProcessor
44
45session_1 = datetime.datetime.now().year - 2
46app_container_name = u'app%s' % session_1
47pgft_container_name = u'pgft%s' % session_1
48
49class ApplicantUITest(FunctionalTestCase):
50    """Perform some browser tests.
51    """
52    layer = FunctionalLayer
53
54    def setUp(self):
55        super(ApplicantUITest, self).setUp()
56        # Setup a sample site for each test
57        app = University()
58        self.dc_root = tempfile.mkdtemp()
59        app['datacenter'].setStoragePath(self.dc_root)
60
61        # Prepopulate the ZODB...
62        self.getRootFolder()['app'] = app
63        # we add the site immediately after creation to the
64        # ZODB. Catalogs and other local utilities are not setup
65        # before that step.
66        self.app = self.getRootFolder()['app']
67        # Set site here. Some of the following setup code might need
68        # to access grok.getSite() and should get our new app then
69        setSite(app)
70
71        # Add an two different applicants containers
72        self.pgcontainer = ApplicantsContainer()
73        self.pgcontainer.code = pgft_container_name
74        self.pgcontainer.prefix = u'pgft'
75        self.pgcontainer.application_category = u'pg_ft'
76        self.pgcontainer.year = session_1
77        self.pgcontainer.application_fee = 300.0
78        self.pgcontainer.title = u'This is the %s container' % pgft_container_name
79        self.app['applicants'][pgft_container_name] = self.pgcontainer
80        self.ugcontainer = ApplicantsContainer()
81        self.ugcontainer.code = app_container_name
82        self.ugcontainer.prefix = u'app'
83        self.ugcontainer.application_category = u'basic'
84        self.ugcontainer.year = session_1
85        self.ugcontainer.application_fee = 200.0
86        self.ugcontainer.title = u'This is the %s container' % app_container_name
87        self.app['applicants'][app_container_name] = self.ugcontainer
88
89        self.ugcontainer.mode = 'update'
90        delta = datetime.timedelta(days=10)
91        self.ugcontainer.startdate = datetime.datetime.now(pytz.utc) - delta
92        self.ugcontainer.enddate = datetime.datetime.now(pytz.utc) + delta
93
94        # Populate university
95        self.certificate = createObject('waeup.Certificate')
96        self.certificate.code = 'CERT1'
97        self.certificate.application_category = 'basic'
98        self.certificate.start_level = 100
99        self.certificate.end_level = 500
100        self.certificate.study_mode = u'ug_ft'
101        self.app['faculties']['fac1'] = Faculty()
102        self.app['faculties']['fac1']['dep1'] = Department()
103        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
104            self.certificate)
105        self.certificate2 = createObject('waeup.Certificate')
106        self.certificate2.code = 'CERT2'
107        self.certificate2.application_category = 'pg_ft'
108        self.certificate2.start_level = 100
109        self.certificate2.end_level = 500
110        self.certificate.study_mode = u'pg_ft'
111        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
112            self.certificate2)
113
114        # Add (customized) applicants
115        pgapplicant = createObject(u'waeup.Applicant')
116        pgapplicant.firstname = u'Anna'
117        pgapplicant.lastname = u'Post'
118        self.app['applicants'][pgft_container_name].addApplicant(pgapplicant)
119        self.pgapplication_number = pgapplicant.application_number
120        self.pgapplicant = self.app['applicants'][pgft_container_name][
121            self.pgapplication_number]
122
123        ugapplicant = createObject(u'waeup.Applicant')
124        ugapplicant.firstname = u'Klaus'
125        ugapplicant.lastname = u'Under'
126        self.app['applicants'][app_container_name].addApplicant(ugapplicant)
127        self.ugapplication_number = ugapplicant.application_number
128        self.ugapplicant = self.app['applicants'][app_container_name][
129            self.ugapplication_number]
130        self.pgapplicant_path = ('http://localhost/app/applicants/%s/%s'
131            % (pgft_container_name, self.pgapplication_number))
132        self.ugapplicant_path = ('http://localhost/app/applicants/%s/%s'
133            % (app_container_name, self.ugapplication_number))
134
135        self.browser = Browser()
136        self.browser.handleErrors = False
137
138        configuration = SessionConfiguration()
139        configuration.academic_session = session_1
140        configuration.application_fee = 200.0
141        self.app['configuration'].addSessionConfiguration(configuration)
142
143    def tearDown(self):
144        super(ApplicantUITest, self).tearDown()
145        shutil.rmtree(self.dc_root)
146        clearSite()
147        return
148
149    def fill_correct_values(self):
150        self.browser.getControl(name="form.reg_number").value = '1234'
151        self.browser.getControl(name="form.firstname").value = 'John'
152        self.browser.getControl(name="form.lastname").value = 'Tester'
153        self.browser.getControl(name="form.date_of_birth").value = '09/09/1988'
154        self.browser.getControl(name="form.lga").value = ['foreigner']
155        self.browser.getControl(name="form.nationality").value = ['NG']
156        self.browser.getControl(name="form.sex").value = ['m']
157        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
158
159    def test_manage_and_view_applicant(self):
160        # Managers can manage pg applicants.
161        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
162        # The IPGApplicant interface is really used in all pages.
163        self.browser.open(self.pgapplicant_path)
164        self.assertEqual(self.browser.headers['Status'], '200 Ok')
165        self.assertTrue('Employer' in self.browser.contents)
166        self.browser.open(self.pgapplicant_path + '/manage')
167        self.assertEqual(self.browser.headers['Status'], '200 Ok')
168        self.assertTrue('Employer' in self.browser.contents)
169        self.browser.open(self.pgapplicant_path + '/edit')
170        self.assertEqual(self.browser.headers['Status'], '200 Ok')
171        self.assertTrue('Employer' in self.browser.contents)
172        self.browser.open(self.pgapplicant_path + '/application_slip.pdf')
173        self.assertEqual(self.browser.headers['Status'], '200 Ok')
174        # If we view the applicant in the ug container,
175        # the employer field doesn't appear.
176        self.browser.open(self.ugapplicant_path)
177        self.assertEqual(self.browser.headers['Status'], '200 Ok')
178        self.assertFalse('Employer' in self.browser.contents)
179        self.browser.open(self.ugapplicant_path + '/manage')
180        self.assertEqual(self.browser.headers['Status'], '200 Ok')
181        # We can save the applicant.
182        self.fill_correct_values()
183        self.browser.getControl(name="form.course1").value = ['CERT1']
184        self.browser.getControl("Save").click()
185        self.assertMatches('...Form has been saved...', self.browser.contents)
186        self.assertFalse('Employer' in self.browser.contents)
187        self.browser.open(self.ugapplicant_path + '/edit')
188        self.assertEqual(self.browser.headers['Status'], '200 Ok')
189        self.assertFalse('Employer' in self.browser.contents)
190        self.browser.open(self.ugapplicant_path + '/application_slip.pdf')
191        self.assertEqual(self.browser.headers['Status'], '200 Ok')
192        return
193
194    def test_set_wrong_course1(self):
195        self.ugapplicant.course1 = self.certificate
196        self.assertRaises(
197            ConstraintNotSatisfied,
198            setattr, self.ugapplicant, 'course1', self.certificate2)
199        self.pgapplicant.course1 = self.certificate2
200        self.assertRaises(
201            ConstraintNotSatisfied,
202            setattr, self.pgapplicant, 'course1', self.certificate)
203        return
204
205    def test_application_payment(self):
206        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
207
208        # UG (UTME) applicant
209        self.browser.open(self.ugapplicant_path)
210        self.browser.open(self.ugapplicant_path + '/manage')
211        self.assertEqual(self.browser.headers['Status'], '200 Ok')
212        self.fill_correct_values()
213        self.browser.getControl(name="form.course1").value = ['CERT1']
214        self.browser.getControl("Save").click()
215        self.assertMatches('...Form has been saved...', self.browser.contents)
216        self.browser.getControl("Add online payment ticket").click()
217        self.assertMatches('...Payment ticket created...',
218                           self.browser.contents)
219        self.assertMatches('...Amount Authorized...',
220                           self.browser.contents)
221        payment_id = self.ugapplicant.keys()[0]
222        payment = self.ugapplicant[payment_id]
223        self.assertEqual(payment.p_item,'This is the %s container' % app_container_name)
224        self.assertEqual(payment.p_session,session_1)
225        self.assertEqual(payment.p_category,'application')
226        self.assertEqual(payment.amount_auth, 200.0)
227
228        # PG applicants pay more
229        self.browser.open(self.pgapplicant_path)
230        self.browser.open(self.pgapplicant_path + '/manage')
231        self.assertEqual(self.browser.headers['Status'], '200 Ok')
232        self.fill_correct_values()
233        self.browser.getControl(name="form.course1").value = ['CERT2']
234        self.browser.getControl(name="form.reg_number").value = '2345'
235        self.browser.getControl(name="form.firstname").value = 'Anna'
236        self.browser.getControl("Save").click()
237        self.assertMatches('...Form has been saved...', self.browser.contents)
238        self.browser.getControl("Add online payment ticket").click()
239        self.assertMatches('...Payment ticket created...',
240                           self.browser.contents)
241        self.assertMatches('...Amount Authorized...',
242                           self.browser.contents)
243        payment_id = self.pgapplicant.keys()[0]
244        payment = self.pgapplicant[payment_id]
245        self.assertEqual(payment.p_item,'This is the %s container' % pgft_container_name)
246        self.assertEqual(payment.p_session,session_1)
247        self.assertEqual(payment.p_category,'application')
248        self.assertEqual(payment.amount_auth, 300.0)
249        return
250
251    def test_hide_screening_data(self):
252        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
253        self.browser.open(self.ugapplicant_path + '/manage')
254        self.assertEqual(self.browser.headers['Status'], '200 Ok')
255        self.fill_correct_values()
256        self.browser.getControl(name="form.screening_venue").value = 'Mensa'
257        self.browser.getControl(name="form.screening_date").value = 'Easter'
258        self.browser.getControl(name="form.course1").value = ['CERT1']
259        self.browser.getControl("Save").click()
260        self.assertMatches('...Form has been saved...', self.browser.contents)
261        self.browser.getControl("Save").click()
262        # Venue and date are not shown
263        self.browser.open(self.ugapplicant_path)
264        self.assertFalse('Screening' in self.browser.contents)
265        IWorkflowState(self.ugapplicant).setState('paid')
266        # Venue and date are shown if applicant has paid
267        self.browser.open(self.ugapplicant_path)
268        self.assertTrue('Screening' in self.browser.contents)
269        return
270
271    def test_register_applicant_update(self):
272        # An applicant can register himself.
273        self.ugapplicant.reg_number = u'1234'
274        notify(grok.ObjectModifiedEvent(self.ugapplicant))
275        self.browser.open('http://localhost/app/applicants/%s/' % app_container_name)
276        self.browser.getLink("Register for application").click()
277        # Fill the edit form with suitable values
278        self.browser.getControl(name="form.firstname").value = 'Klaus'
279        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
280        self.browser.getControl(name="form.reg_number").value = '1234'
281        self.browser.getControl("Send login credentials").click()
282        self.assertMatches('...Your registration was successful...',
283            self.browser.contents)
284        self.assertFalse('...<td>Password:</td>...' in self.browser.contents)
285        # The new applicant can be found in the catalog via the email address
286        cat = getUtility(ICatalog, name='applicants_catalog')
287        results = list(
288            cat.searchResults(email=('xx@yy.zz', 'xx@yy.zz')))
289        applicant = results[0]
290        self.assertEqual(applicant.lastname,'Under')
291        # The applicant can be found in the catalog via the reg_number
292        results = list(
293            cat.searchResults(
294            reg_number=(applicant.reg_number, applicant.reg_number)))
295        self.assertEqual(applicant,results[0])
296        return
297
298    def test_create_ugstudent(self):
299        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
300        manage_path = 'http://localhost/app/applicants/%s/%s/%s' % (
301            app_container_name, self.ugapplicant.application_number, 'manage')
302        self.browser.open(manage_path)
303        self.fill_correct_values()
304        self.browser.getControl("Save").click()
305        IWorkflowState(self.ugapplicant).setState('admitted')
306        self.browser.getControl(name="form.course1").value = ['CERT1']
307        self.browser.getControl(name="form.course_admitted").value = ['CERT1']
308        self.browser.getControl("Save").click()
309        self.browser.getLink("Create student").click()
310        student_id =  self.app['students'].keys()[0]
311        self.assertTrue(('Student %s created' % student_id)
312            in self.browser.contents)
313        student = self.app['students'][student_id]
314        self.assertEqual(student.email, 'xx@yy.zz')
315        self.assertEqual(student.firstname, 'John')
316        self.assertEqual(student.lastname, 'Tester')
317        # Also additional attributes have been copied.
318        self.assertEqual(student.lga, 'foreigner')
319        self.assertEqual(student.nationality, 'NG')
320        return
321
322class ApplicantsExporterTest(ApplicantImportExportSetup):
323
324    layer = FunctionalLayer
325
326    def setUp(self):
327        super(ApplicantsExporterTest, self).setUp()
328        self.outfile = os.path.join(self.workdir, 'myoutput.csv')
329        self.cat = getUtility(ICatalog, name='applicants_catalog')
330        self.intids = getUtility(IIntIds)
331        return
332
333    def setup_applicant(self, applicant):
334        # set predictable values for `applicant`
335        applicant.reg_number = u'123456'
336        applicant.applicant_id = u'dp2011_654321'
337        applicant.firstname = u'Anna'
338        applicant.lastname = u'Tester'
339        applicant.middlename = u'M.'
340        applicant.nationality = u'NG'
341        applicant.date_of_birth = datetime.date(1981, 2, 4)
342        applicant.sex = 'f'
343        applicant.email = 'anna@sample.com'
344        applicant.phone = u'+234-123-12345'
345        applicant.course1 = self.certificate
346        applicant.course2 = self.certificate
347        applicant.course_admitted = self.certificate
348        applicant.notice = u'Some notice\nin lines.'
349        applicant.screening_score = 98
350        applicant.screening_venue = u'Exam Room'
351        applicant.screening_date = u'Saturday, 16th June 2012 2:00:00 PM'
352        applicant.password = 'any password'
353        return applicant
354
355    def test_export_reimport_all(self):
356        # we can export all applicants in a portal
357        # set values we can expect in export file
358        self.applicant = self.setup_applicant(self.applicant)
359        exporter = NigeriaApplicantsExporter()
360        exporter.export_all(self.app, self.outfile)
361        result = open(self.outfile, 'rb').read()
362        self.assertMatches(result,
363            'aggregate,applicant_id,application_date,application_number,'
364            'course1,course2,course_admitted,date_of_birth,display_fullname,'
365            'email,emp2_end,emp2_position,emp2_reason,emp2_start,emp_end,'
366            'emp_position,emp_reason,emp_start,employer,employer2,'
367            'firstname,history,hq_degree,hq_disc,hq_matric_no,hq_school,'
368            'hq_session,hq_type,jamb_score,jamb_subjects,lastname,lga,'
369            'locked,middlename,nationality,notice,nysc_lga,nysc_year,'
370            'password,phone,pp_school,presently_inst,reg_number,'
371            'result_uploaded,screening_date,screening_score,'
372            'screening_venue,sex,special_application,'
373            'state,student_id,suspended,container_code\r\n'
374            ',dp2011_654321,,654321,CERT1,CERT1,CERT1,1981-02-04#,'
375            'Anna M. Tester,anna@sample.com,,,,,,,,,,,Anna,'
376            '[u\'2012-10-28 21:27:52 WAT - Application initialized by system\']'
377            ',,,,,,,,,Tester,,0,M.,NG,"Some notice\nin lines.",,,'
378            'any password,+234-123-12345#,,,123456,,'
379            '"Saturday, 16th June 2012 2:00:00 PM",98,Exam Room,f,,initialized,,'
380            '0,dp2011\r\n')
381        # We can import the same file if we ignore some columns.
382        # Since the applicants_catalog hasn't been notified, the same
383        # record with same reg_number can be imported twice.
384        processor = NigeriaApplicantProcessor()
385        result = processor.doImport(
386            self.outfile,
387            ['aggreagate','ignore_applicant_id','application_date',
388            'ignore_application_number','course1','course2',
389            'course_admitted','date_of_birth','ignore3','email','emp2_end',
390            'emp2_position','emp2_reason','emp2_start','emp_end','emp_position',
391            'emp_reason','emp_start','employer','employer2','firstname','ignore4',
392            'hq_degree','hq_disc','hq_matric_no','hq_school','hq_session','hq_type',
393            'jamb_score','jamb_subjects','lastname','lga','locked','middlename',
394            'nationality','notice','nysc_lga',
395            'nysc_year','password','phone','pp_school','presently_inst',
396            'reg_number','result_uploaded',
397            'screening_date','screening_score','screening_venue','sex',
398            'special_application',
399            'state','student_id','suspended','container_code'],
400            mode='create')
401        num_succ, num_fail, finished_path, failed_path = result
402        #content = open(failed_path).read()
403        self.assertEqual(num_succ,1)
404        self.assertEqual(num_fail,0)
405        # Now we ignore also the container_code and import the same file
406        # in update mode which means that INigeriaApplicantUpdateByRegNo
407        # is used for field conversion. applicant_id must be ignored
408        # too since the previous import has notified the applicants_catalog
409        # so that the portal 'knows' that reg_number is in use.
410        processor = NigeriaApplicantProcessor()
411        result = processor.doImport(
412            self.outfile,
413            ['aggregate','ignore_applicant_id','application_date',
414            'ignore_application_number','course1','course2',
415            'course_admitted','date_of_birth','ignore3','email','emp2_end',
416            'emp2_position','emp2_reason','emp2_start','emp_end','emp_position',
417            'emp_reason','emp_start','employer','employer2','firstname','ignore4',
418            'hq_degree','hq_disc','hq_matric_no','hq_school','hq_session','hq_type',
419            'jamb_score','jamb_subjects','lastname','lga','locked','middlename',
420            'nationality','notice','nysc_lga',
421            'nysc_year','password','phone','pp_school','presently_inst',
422            'reg_number','result_uploaded','screening_date','screening_score',
423            'screening_venue','sex','special_application',
424            'state','student_id','suspended','ignore_container_code'],
425            mode='update')
426        num_succ, num_fail, finished_path, failed_path = result
427        self.assertEqual(num_succ,1)
428        self.assertEqual(num_fail,0)
429        return
Note: See TracBrowser for help on using the repository browser.