source: main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py @ 6942

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

Reorganize test_manage_payments and add more tests for payments made by students.

  • Property svn:keywords set to Id
File size: 40.2 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: test_browser.py 6942 2011-10-25 09:44:52Z henrik $
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 student-related UI components.
24"""
25import shutil
26import tempfile
27import cStringIO
28from datetime import datetime
29from zope.component import createObject
30from zope.component.hooks import setSite, clearSite
31from zope.security.interfaces import Unauthorized
32from zope.testbrowser.testing import Browser
33from hurry.workflow.interfaces import IWorkflowInfo
34from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
35from waeup.sirp.app import University
36from waeup.sirp.configuration import SessionConfiguration
37from waeup.sirp.students.student import Student
38from waeup.sirp.university.faculty import Faculty
39from waeup.sirp.university.department import Department
40from waeup.sirp.interfaces import IUserAccount
41
42PH_LEN = 2059  # Length of placeholder file
43
44def lookup_submit_value(name, value, browser):
45    """Find a button with a certain value."""
46    for num in range(0, 100):
47        try:
48            button = browser.getControl(name=name, index=num)
49            if button.value.endswith(value):
50                return button
51        except IndexError:
52            break
53    return None
54
55class StudentsFullSetup(FunctionalTestCase):
56    # A test case that only contains a setup and teardown
57    #
58    # Complete setup for students 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(StudentsFullSetup, 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        # Add student with subobjects
85        student = Student()
86        student.fullname = u'Anna Tester'
87        student.reg_number = u'123'
88        student.matric_number = u'234'
89        self.app['students'].addStudent(student)
90        self.student_id = student.student_id
91        self.student = self.app['students'][self.student_id]
92
93        # Set password
94        IUserAccount(
95            self.app['students'][self.student_id]).setPassword('spwd')
96
97        self.login_path = 'http://localhost/app/login'
98        self.container_path = 'http://localhost/app/students'
99        self.manage_container_path = self.container_path + '/@@manage'
100        self.add_student_path = self.container_path + '/addstudent'
101        self.student_path = self.container_path + '/' + self.student_id
102        self.manage_student_path = self.student_path + '/edit_base'
103        self.clearance_student_path = self.student_path + '/view_clearance'
104        self.personal_student_path = self.student_path + '/view_personal'
105        self.edit_clearance_student_path = self.student_path + '/edit_clearance'
106        self.edit_personal_student_path = self.student_path + '/edit_personal'
107
108        self.studycourse_student_path = self.student_path + '/studycourse'
109        self.payments_student_path = self.student_path + '/payments'
110        self.accommodation_student_path = self.student_path + '/accommodation'
111        self.history_student_path = self.student_path + '/history'
112
113        # Create 5 access codes with prefix'PWD'
114        pin_container = self.app['accesscodes']
115        pin_container.createBatch(
116            datetime.now(), 'some_userid', 'PWD', 9.99, 5)
117        pins = pin_container['PWD-1'].values()
118        self.pwdpins = [x.representation for x in pins]
119        self.existing_pwdpin = self.pwdpins[0]
120        parts = self.existing_pwdpin.split('-')[1:]
121        self.existing_pwdseries, self.existing_pwdnumber = parts
122        # Create 5 access codes with prefix 'CLR'
123        pin_container.createBatch(
124            datetime.now(), 'some_userid', 'CLR', 9.99, 5)
125        pins = pin_container['CLR-1'].values()
126        pins[0].owner = u'Hans Wurst'
127        self.existing_clrac = pins[0]
128        self.existing_clrpin = pins[0].representation
129        parts = self.existing_clrpin.split('-')[1:]
130        self.existing_clrseries, self.existing_clrnumber = parts
131
132        # Populate university
133        self.certificate = createObject('waeup.Certificate')
134        self.certificate.code = u'CERT1'
135        self.certificate.application_category = 'basic'
136        self.certificate.study_mode = 'ug_ft'
137        self.certificate.start_level = 100
138        self.certificate.end_level = 500
139        self.app['faculties']['fac1'] = Faculty()
140        self.app['faculties']['fac1']['dep1'] = Department()
141        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
142            self.certificate)
143        self.course = createObject('waeup.Course')
144        self.course.code = 'COURSE1'
145        self.course.semester = 1
146        self.course.credits = 10
147        self.course.passmark = 40
148        self.app['faculties']['fac1']['dep1'].courses.addCourse(
149            self.course)
150        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
151            self.course, level=100)
152
153        # Set study course attributes of test student
154        self.student['studycourse'].certificate = self.certificate
155        self.student['studycourse'].current_session = 2004
156        self.student['studycourse'].current_verdict = 'A'
157        self.student['studycourse'].current_level = 100
158
159        # Put the prepopulated site into test ZODB and prepare test
160        # browser
161        self.browser = Browser()
162        self.browser.handleErrors = False
163
164    def tearDown(self):
165        super(StudentsFullSetup, self).tearDown()
166        clearSite()
167        shutil.rmtree(self.dc_root)
168
169
170
171class StudentsContainerUITests(StudentsFullSetup):
172    # Tests for StudentsContainer class views and pages
173
174    layer = FunctionalLayer
175
176    def test_anonymous_access(self):
177        # Anonymous users can't access students containers
178        self.assertRaises(
179            Unauthorized, self.browser.open, self.container_path)
180        self.assertRaises(
181            Unauthorized, self.browser.open, self.manage_container_path)
182        return
183
184    def test_manage_access(self):
185        # Managers can access the view page of students
186        # containers and can perform actions
187        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
188        self.browser.open(self.container_path)
189        self.assertEqual(self.browser.headers['Status'], '200 Ok')
190        self.assertEqual(self.browser.url, self.container_path)
191        self.browser.getLink("Manage student section").click()
192        self.assertEqual(self.browser.headers['Status'], '200 Ok')
193        self.assertEqual(self.browser.url, self.manage_container_path)
194        return
195
196    def test_add_search_delete_students(self):
197        # Managers can add search and remove students
198        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
199        self.browser.open(self.manage_container_path)
200        self.browser.getLink("Add student").click()
201        self.assertEqual(self.browser.headers['Status'], '200 Ok')
202        self.assertEqual(self.browser.url, self.add_student_path)
203        self.browser.getControl(name="form.fullname").value = 'Bob Tester'
204        self.browser.getControl("Create student record").click()
205        self.assertTrue('Student record created' in self.browser.contents)
206
207        # Registration and matric numbers must be unique
208        self.browser.getLink("Manage").click()
209        self.browser.getControl(name="form.reg_number").value = '123'
210        self.browser.getControl("Save").click()
211        self.assertMatches('...Registration number exists...',
212                           self.browser.contents)
213        self.browser.getControl(name="form.reg_number").value = '789'
214        self.browser.getControl(name="form.matric_number").value = '234'
215        self.browser.getControl("Save").click()
216        self.assertMatches('...Matriculation number exists...',
217                           self.browser.contents)
218
219        self.browser.open(self.container_path)
220        self.browser.getControl("Search").click()
221        self.assertTrue('Empty search string' in self.browser.contents)
222        self.browser.getControl(name="searchtype").value = ['student_id']
223        self.browser.getControl(name="searchterm").value = self.student_id
224        self.browser.getControl("Search").click()
225        self.assertTrue('Anna Tester' in self.browser.contents)
226
227        self.browser.open(self.manage_container_path)
228        self.browser.getControl("Search").click()
229        self.assertTrue('Empty search string' in self.browser.contents)
230        self.browser.getControl(name="searchtype").value = ['fullname']
231        self.browser.getControl(name="searchterm").value = 'Anna Tester'
232        self.browser.getControl("Search").click()
233        self.assertTrue('Anna Tester' in self.browser.contents)
234        # The old searchterm will be used again
235        self.browser.getControl("Search").click()
236        self.assertTrue('Anna Tester' in self.browser.contents)
237
238        ctrl = self.browser.getControl(name='entries')
239        ctrl.getControl(value=self.student_id).selected = True
240        self.browser.getControl("Remove selected", index=0).click()
241        self.assertTrue('Successfully removed' in self.browser.contents)
242        self.browser.getControl(name="searchtype").value = ['student_id']
243        self.browser.getControl(name="searchterm").value = self.student_id
244        self.browser.getControl("Search").click()
245        self.assertTrue('No student found' in self.browser.contents)
246
247        self.browser.open(self.container_path)
248        self.browser.getControl(name="searchtype").value = ['student_id']
249        self.browser.getControl(name="searchterm").value = self.student_id
250        self.browser.getControl("Search").click()
251        self.assertTrue('No student found' in self.browser.contents)
252        return
253
254class StudentUITests(StudentsFullSetup):
255    # Tests for Student class views and pages
256
257    layer = FunctionalLayer
258
259    def test_manage_access(self):
260        # Managers can access the pages of students
261        # and can perform actions
262        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
263
264        self.browser.open(self.student_path)
265        self.assertEqual(self.browser.headers['Status'], '200 Ok')
266        self.assertEqual(self.browser.url, self.student_path)
267        self.browser.getLink("Manage").click()
268        self.assertEqual(self.browser.headers['Status'], '200 Ok')
269        self.assertEqual(self.browser.url, self.manage_student_path)
270        # Managers can edit base data and fire transitions
271        self.browser.getControl(name="transition").value = ['admit']
272        self.browser.getControl(name="form.fullname").value = 'John Tester'
273        self.browser.getControl(name="form.reg_number").value = '345'
274        self.browser.getControl(name="password").value = 'secret'
275        self.browser.getControl(name="control_password").value = 'secret'
276        self.browser.getControl("Save").click()
277        self.assertMatches('...Form has been saved...',
278                           self.browser.contents)
279        self.browser.open(self.student_path)
280        self.browser.getLink("Clearance Data").click()
281        self.assertEqual(self.browser.headers['Status'], '200 Ok')
282        self.assertEqual(self.browser.url, self.clearance_student_path)
283        self.browser.getLink("Manage").click()
284        self.assertEqual(self.browser.headers['Status'], '200 Ok')
285        self.assertEqual(self.browser.url, self.edit_clearance_student_path)
286        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
287        self.browser.getControl("Save").click()
288        self.assertMatches('...Form has been saved...',
289                           self.browser.contents)
290
291        self.browser.open(self.student_path)
292        self.browser.getLink("Personal Data").click()
293        self.assertEqual(self.browser.headers['Status'], '200 Ok')
294        self.assertEqual(self.browser.url, self.personal_student_path)
295        self.browser.getLink("Manage").click()
296        self.assertEqual(self.browser.headers['Status'], '200 Ok')
297        self.assertEqual(self.browser.url, self.edit_personal_student_path)
298        self.browser.getControl("Save").click()
299        self.assertMatches('...Form has been saved...',
300                           self.browser.contents)
301
302        # Managers can browse all subobjects
303        self.browser.open(self.student_path)
304        self.browser.getLink("Payments").click()
305        self.assertEqual(self.browser.headers['Status'], '200 Ok')
306        self.assertEqual(self.browser.url, self.payments_student_path)
307        self.browser.open(self.student_path)
308        self.browser.getLink("Accommodation").click()
309        self.assertEqual(self.browser.headers['Status'], '200 Ok')
310        self.assertEqual(self.browser.url, self.accommodation_student_path)
311        self.browser.open(self.student_path)
312        self.browser.getLink("History").click()
313        self.assertEqual(self.browser.headers['Status'], '200 Ok')
314        self.assertEqual(self.browser.url, self.history_student_path)
315        self.assertMatches('...Student admitted by zope.mgr...',
316                           self.browser.contents)
317        return
318
319    def test_manage_course_lists(self):
320        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
321        self.browser.open(self.student_path)
322        self.browser.getLink("Study Course").click()
323        self.assertEqual(self.browser.headers['Status'], '200 Ok')
324        self.assertEqual(self.browser.url, self.studycourse_student_path)
325        self.browser.getLink("Manage").click()
326        self.assertTrue('Manage study course' in self.browser.contents)
327        # Before we can select a level, the certificate must be selected and saved
328        self.browser.getControl(name="form.certificate").value = ['CERT1']
329        self.browser.getControl(name="form.current_session").value = ['2004']
330        self.browser.getControl(name="form.current_verdict").value = ['A']
331        self.browser.getControl("Save").click()
332        # Now we can save also the current level which depends on start and end
333        # level of the certificate
334        self.browser.getControl(name="form.current_level").value = ['100']
335        self.browser.getControl("Save").click()
336        # Managers can add and remove any study level (course list)
337        self.browser.getControl(name="addlevel").value = ['100']
338        self.browser.getControl("Add study level").click()
339        self.assertMatches('...<span>100</span>...', self.browser.contents)
340        self.browser.getControl("Add study level").click()
341        self.assertMatches('...This level exists...', self.browser.contents)
342        self.browser.getControl("Remove selected").click()
343        self.assertMatches('...No study level selected...', self.browser.contents)
344        self.browser.getControl(name="val_id").value = ['100']
345        self.browser.getControl("Remove selected").click()
346        self.assertMatches('...Successfully removed...', self.browser.contents)
347        # Add level again
348        self.browser.getControl(name="addlevel").value = ['100']
349        self.browser.getControl("Add study level").click()
350        self.browser.getControl(name="addlevel").value = ['100']
351
352        # Managers can view and manage course lists
353        self.browser.getLink("100").click()
354        self.assertMatches('...: Study Level 100 (Year 1)...', self.browser.contents)
355        self.browser.getLink("Manage").click()
356        self.browser.getControl(name="form.level_session").value = ['2002']
357        self.browser.getControl("Save").click()
358        self.browser.getControl("Remove selected").click()
359        self.assertMatches('...No ticket selected...', self.browser.contents)
360        ctrl = self.browser.getControl(name='val_id')
361        ctrl.getControl(value='COURSE1').selected = True
362        self.browser.getControl("Remove selected", index=0).click()
363        self.assertTrue('Successfully removed' in self.browser.contents)
364        self.browser.getControl("Add course ticket").click()
365        self.browser.getControl(name="form.course").value = ['COURSE1']
366        self.browser.getControl("Add course ticket").click()
367        self.assertTrue('Successfully added' in self.browser.contents)
368        self.browser.getControl("Add course ticket").click()
369        self.browser.getControl(name="form.course").value = ['COURSE1']
370        self.browser.getControl("Add course ticket").click()
371        self.assertTrue('The ticket exists' in self.browser.contents)
372        self.browser.getControl("Cancel").click()
373        self.browser.getLink("COURSE1").click()
374        self.browser.getLink("Manage").click()
375        self.browser.getControl(name="form.score").value = '10'
376        self.browser.getControl("Save").click()
377        self.assertTrue('Form has been saved' in self.browser.contents)
378        return
379
380    def test_manage_workflow(self):
381        # Managers can pass through the whole workflow
382        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
383        student = self.app['students'][self.student_id]
384        self.browser.open(self.manage_student_path)
385        self.assertTrue(student.clearance_locked)
386        self.browser.getControl(name="transition").value = ['admit']
387        self.browser.getControl("Save").click()
388        self.assertTrue(student.clearance_locked)
389        self.browser.getControl(name="transition").value = ['start_clearance']
390        self.browser.getControl("Save").click()
391        self.assertFalse(student.clearance_locked)
392        self.browser.getControl(name="transition").value = ['request_clearance']
393        self.browser.getControl("Save").click()
394        self.assertTrue(student.clearance_locked)
395        self.browser.getControl(name="transition").value = ['clear']
396        self.browser.getControl("Save").click()
397        self.browser.getControl(name="transition").value = ['pay_first_school_fee']
398        self.browser.getControl("Save").click()
399        self.browser.getControl(name="transition").value = ['reset6']
400        self.browser.getControl("Save").click()
401        # In state returning the pay_school_fee transition triggers some
402        # changes of attributes
403        self.browser.getControl(name="transition").value = ['pay_school_fee']
404        self.browser.getControl("Save").click()
405        self.assertEqual(student['studycourse'].current_session, 2005) # +1
406        self.assertEqual(student['studycourse'].current_level, 200) # +100
407        self.assertEqual(student['studycourse'].current_verdict, '0') # 0 = not set
408        self.assertEqual(student['studycourse'].previous_verdict, 'A')
409        self.browser.getControl(name="transition").value = ['register_courses']
410        self.browser.getControl("Save").click()
411        self.browser.getControl(name="transition").value = ['validate_courses']
412        self.browser.getControl("Save").click()
413        self.browser.getControl(name="transition").value = ['return']
414        self.browser.getControl("Save").click()
415        return
416
417    def test_manage_import(self):
418        # Managers can import student data files
419        datacenter_path = 'http://localhost/app/datacenter'
420        # Prepare a csv file for students
421        open('students.csv', 'wb').write(
422"""firstname,lastname,fullname,reg_number,date_of_birth,matric_number
423Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000
424Claus,Finau,Claus Finau,2,1990-01-03,100001
425Brit,Berson,Brit Berson,3,1990-01-04,100001
426""")
427        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
428        self.browser.open(datacenter_path)
429        self.browser.getLink('Upload CSV file').click()
430        filecontents = cStringIO.StringIO(open('students.csv', 'rb').read())
431        filewidget = self.browser.getControl(name='uploadfile:file')
432        filewidget.add_file(filecontents, 'text/plain', 'students.csv')
433        self.browser.getControl(name='SUBMIT').click()
434        self.browser.getLink('Batch processing').click()
435        button = lookup_submit_value(
436            'select', 'students_zope.mgr.csv', self.browser)
437        button.click()
438        importerselect = self.browser.getControl(name='importer')
439        modeselect = self.browser.getControl(name='mode')
440        importerselect.getControl('Student Importer').selected = True
441        modeselect.getControl(value='create').selected = True
442        self.browser.getControl('Proceed to step 3...').click()
443        self.assertTrue('Header fields OK' in self.browser.contents)
444        self.browser.getControl('Perform import...').click()
445        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
446        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
447        self.assertTrue('Batch processing finished' in self.browser.contents)
448        open('studycourses.csv', 'wb').write(
449"""reg_number,matric_number,certificate,current_session,current_level
4501,,CERT1,2008,100
451,100001,CERT1,2008,100
452,100002,CERT1,2008,100
453""")
454        self.browser.open(datacenter_path)
455        self.browser.getLink('Upload CSV file').click()
456        filecontents = cStringIO.StringIO(open('studycourses.csv', 'rb').read())
457        filewidget = self.browser.getControl(name='uploadfile:file')
458        filewidget.add_file(filecontents, 'text/plain', 'studycourses.csv')
459        self.browser.getControl(name='SUBMIT').click()
460        self.browser.getLink('Batch processing').click()
461        button = lookup_submit_value(
462            'select', 'studycourses_zope.mgr.csv', self.browser)
463        button.click()
464        importerselect = self.browser.getControl(name='importer')
465        modeselect = self.browser.getControl(name='mode')
466        importerselect.getControl(
467            'StudentStudyCourse Importer (update only)').selected = True
468        modeselect.getControl(value='create').selected = True
469        self.browser.getControl('Proceed to step 3...').click()
470        self.assertTrue('Update mode only' in self.browser.contents)
471        self.browser.getControl('Proceed to step 3...').click()
472        self.assertTrue('Header fields OK' in self.browser.contents)
473        self.browser.getControl('Perform import...').click()
474        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
475        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
476
477    def test_student_change_password(self):
478        # Students can change the password
479        self.browser.open(self.login_path)
480        self.browser.getControl(name="form.login").value = self.student_id
481        self.browser.getControl(name="form.password").value = 'spwd'
482        self.browser.getControl("Login").click()
483        self.assertEqual(self.browser.url, self.student_path)
484        self.assertTrue('You logged in' in self.browser.contents)
485        # Change password
486        self.browser.getLink("Change password").click()
487        self.browser.getControl(name="form.password").value = 'new_password'
488        self.browser.getControl(
489            name="form.password_repeat").value = 'new_passssword'
490        self.browser.getControl("Save").click()
491        self.assertTrue('passwords do not match' in self.browser.contents)
492        self.browser.getControl(name="form.password").value = 'new_password'
493        self.browser.getControl(
494            name="form.password_repeat").value = 'new_password'
495        self.browser.getControl("Save").click()
496        self.assertTrue('Form has been saved' in self.browser.contents)
497        # We are still logged in. Changing the password hasn't thrown us out.
498        self.browser.getLink("My Data").click()
499        self.assertEqual(self.browser.url, self.student_path)
500        # We can logout
501        self.browser.getLink("Logout").click()
502        self.assertTrue('You have been logged out' in self.browser.contents)
503        self.assertEqual(self.browser.url, 'http://localhost/app')
504        # We can login again with the new password
505        self.browser.getLink("Login").click()
506        self.browser.open(self.login_path)
507        self.browser.getControl(name="form.login").value = self.student_id
508        self.browser.getControl(name="form.password").value = 'new_password'
509        self.browser.getControl("Login").click()
510        self.assertEqual(self.browser.url, self.student_path)
511        self.assertTrue('You logged in' in self.browser.contents)
512        return
513
514    def test_setpassword(self):
515        # Set password for first-time access
516        student = Student()
517        student.reg_number = u'123456'
518        student.fullname = u'Klaus Tester'
519        self.app['students'].addStudent(student)
520        setpassword_path = 'http://localhost/app/setpassword'
521        student_path = 'http://localhost/app/students/%s' % student.student_id
522        self.browser.open(setpassword_path)
523        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
524        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
525        self.browser.getControl(name="reg_number").value = '223456'
526        self.browser.getControl("Show").click()
527        self.assertMatches('...No student found...',
528                           self.browser.contents)
529        self.browser.getControl(name="reg_number").value = '123456'
530        self.browser.getControl(name="ac_number").value = '999999'
531        self.browser.getControl("Show").click()
532        self.assertMatches('...Access code is invalid...',
533                           self.browser.contents)
534        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
535        self.browser.getControl("Show").click()
536        self.assertMatches('...Password has been set. Your Student Id is...',
537                           self.browser.contents)
538        self.browser.getControl("Show").click()
539        self.assertMatches(
540            '...Password has already been set. Your Student Id is...',
541            self.browser.contents)
542        existing_pwdpin = self.pwdpins[1]
543        parts = existing_pwdpin.split('-')[1:]
544        existing_pwdseries, existing_pwdnumber = parts
545        self.browser.getControl(name="ac_series").value = existing_pwdseries
546        self.browser.getControl(name="ac_number").value = existing_pwdnumber
547        self.browser.getControl(name="reg_number").value = '123456'
548        self.browser.getControl("Show").click()
549        self.assertMatches(
550            '...You are using the wrong Access Code...',
551            self.browser.contents)
552        # The student can login with the new credentials
553        self.browser.open(self.login_path)
554        self.browser.getControl(name="form.login").value = student.student_id
555        self.browser.getControl(
556            name="form.password").value = self.existing_pwdnumber
557        self.browser.getControl("Login").click()
558        self.assertEqual(self.browser.url, student_path)
559        self.assertTrue('You logged in' in self.browser.contents)
560        return
561
562    def test_student_access(self):
563        # Students can access their own objects
564        # and can perform actions
565        IWorkflowInfo(self.student).fireTransition('admit')
566        self.browser.open(self.login_path)
567        self.browser.getControl(name="form.login").value = self.student_id
568        self.browser.getControl(name="form.password").value = 'spwd'
569        self.browser.getControl("Login").click()
570        # Student can view the clearance data
571        self.browser.getLink("Clearance Data").click()
572        # Student can't open clearance edit form before starting clearance
573        self.browser.open(self.student_path + '/cedit')
574        self.assertMatches('...The requested form is locked...',
575                           self.browser.contents)
576        self.browser.getLink("Clearance Data").click()
577        self.browser.getLink("Start clearance").click()
578        self.browser.getControl(name="ac_series").value = '3'
579        self.browser.getControl(name="ac_number").value = '4444444'
580        self.browser.getControl("Start clearance now").click()
581        self.assertMatches('...Activation code is invalid...',
582                           self.browser.contents)
583        self.browser.getControl(name="ac_series").value = self.existing_clrseries
584        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
585        # Owner is Hans Wurst, AC can't be invalidated
586        self.browser.getControl("Start clearance now").click()
587        self.assertMatches('...You are not the owner of this access code...',
588                           self.browser.contents)
589        # Set the correct owner
590        self.existing_clrac.owner = self.student_id
591        self.browser.getControl("Start clearance now").click()
592        self.assertMatches('...Clearance process has been started...',
593                           self.browser.contents)
594        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
595        self.browser.getControl("Save", index=0).click()
596        # Student can view the clearance data
597        self.browser.getLink("Clearance Data").click()
598        # and go back to the edit form
599        self.browser.getLink("Edit").click()
600        self.browser.getControl("Save and request clearance").click()
601        self.browser.getControl(name="ac_series").value = self.existing_clrseries
602        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
603        self.browser.getControl("Request clearance now").click()
604        self.assertMatches('...Clearance has been requested...',
605                           self.browser.contents)
606        # Student can't reopen clearance form after requesting clearance
607        self.browser.open(self.student_path + '/cedit')
608        self.assertMatches('...The requested form is locked...',
609                           self.browser.contents)
610        # Student can't add study level if not in state 'school fee paid'
611        self.browser.open(self.student_path + '/studycourse/add')
612        self.assertMatches('...The requested form is locked...',
613                           self.browser.contents)
614        # ... and must be transferred first
615        IWorkflowInfo(self.student).fireTransition('clear')
616        IWorkflowInfo(self.student).fireTransition('pay_first_school_fee')
617        # Now students can add the current study level
618        self.browser.getLink("Study Course").click()
619        self.browser.getLink("Add course list").click()
620        self.assertMatches('...Add current level 100 (Year 1)...',
621                           self.browser.contents)
622        self.browser.getControl("Create course list now").click()
623        self.browser.getLink("100").click()
624        self.browser.getLink("Add and remove courses").click()
625        self.browser.getControl("Add course ticket").click()
626        self.browser.getControl(name="form.course").value = ['COURSE1']
627        self.browser.getControl("Add course ticket").click()
628        self.assertMatches('...The ticket exists...',
629                           self.browser.contents)
630        self.student['studycourse'].current_level = 200
631        self.browser.getLink("Study Course").click()
632        self.browser.getLink("Add course list").click()
633        self.assertMatches('...Add current level 200 (Year 2)...',
634                           self.browser.contents)
635        self.browser.getControl("Create course list now").click()
636        self.browser.getLink("200").click()
637        self.browser.getLink("Add and remove courses").click()
638        self.browser.getControl("Add course ticket").click()
639        self.browser.getControl(name="form.course").value = ['COURSE1']
640        self.browser.getControl("Add course ticket").click()
641        self.assertMatches('...Successfully added COURSE1...',
642                           self.browser.contents)
643        self.browser.getControl("Remove selected", index=0).click()
644        self.assertTrue('No ticket selected' in self.browser.contents)
645        ctrl = self.browser.getControl(name='val_id')
646        ctrl.getControl(value='COURSE1').selected = True
647        self.browser.getControl("Remove selected", index=0).click()
648        self.assertTrue('Successfully removed' in self.browser.contents)
649        self.browser.getControl("Register course list").click()
650        self.assertTrue('Course list has been registered' in self.browser.contents)
651        self.assertEqual(self.student.state, 'courses registered')
652        return
653
654    def test_manage_payments(self):
655        # Set up SessionConfiguration object
656        configuration = SessionConfiguration()
657        configuration.academic_session = 2004
658        configuration.fee_1 = 20000
659        self.app['configuration'].addSessionConfiguration(configuration)
660
661        # Managers can add online school fee payment tickets
662        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
663        self.browser.open(self.payments_student_path)
664        self.browser.getControl("Add online payment ticket").click()
665        self.browser.getControl(name="form.p_category").value = ['schoolfee']
666        self.browser.getControl("Create ticket").click()
667        self.assertMatches('...ticket created...',
668                           self.browser.contents)
669        ctrl = self.browser.getControl(name='val_id')
670        value = ctrl.options[0]
671        self.browser.getLink(value).click()
672        self.assertMatches('...Amount Authorized...',
673                           self.browser.contents)
674
675        # Managers can open the callback view which simulates a valid callback
676        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
677        self.browser.open(self.browser.url + '/callback')
678        self.assertMatches('...Valid callback received...',
679                          self.browser.contents)
680
681        # Managers can remove online school fee payment tickets
682        self.browser.open(self.payments_student_path)
683        self.browser.getControl("Remove selected").click()
684        self.assertMatches('...No payment selected...', self.browser.contents)
685        ctrl = self.browser.getControl(name='val_id')
686        value = ctrl.options[0]
687        ctrl.getControl(value=value).selected = True
688        self.browser.getControl("Remove selected", index=0).click()
689        self.assertTrue('Successfully removed' in self.browser.contents)
690
691        # Managers can add online clearance payment tickets
692        self.browser.open(self.payments_student_path + '/addop')
693        self.browser.getControl(name="form.p_category").value = ['clearance']
694        self.browser.getControl("Create ticket").click()
695        self.assertMatches('...ticket created...',
696                           self.browser.contents)
697
698        # Managers can open the callback view which simulates a valid callback
699        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
700        ctrl = self.browser.getControl(name='val_id')
701        value = ctrl.options[0]
702        self.browser.getLink(value).click()
703        self.browser.open(self.browser.url + '/callback')
704        self.assertMatches('...Valid callback received...',
705                          self.browser.contents)
706        expected = '''...
707        <td>
708          Paid
709        </td>...'''
710        self.assertMatches(expected,self.browser.contents)
711        # The new CLR-0 pin has been created
712        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
713        pin = self.app['accesscodes']['CLR-0'].keys()[0]
714        ac = self.app['accesscodes']['CLR-0'][pin]
715        ac.owner = self.student_id
716        # The new CLR-0 pin can be used for starting clearance
717        IWorkflowInfo(self.student).fireTransition('admit')
718        self.browser.open(self.student_path + '/start_clearance')
719        parts = pin.split('-')[1:]
720        clrseries, clrnumber = parts
721        self.browser.getControl(name="ac_series").value = clrseries
722        self.browser.getControl(name="ac_number").value = clrnumber
723        self.browser.getControl("Start clearance now").click()
724        self.assertMatches('...Clearance process has been started...',
725                           self.browser.contents)
726
727
728
729    def test_student_payments(self):
730        # Set up SessionConfiguration object
731        configuration = SessionConfiguration()
732        configuration.academic_session = 2004
733        configuration.fee_1 = 20000
734        self.app['configuration'].addSessionConfiguration(configuration)
735        self.browser.open(self.login_path)
736        self.browser.getControl(name="form.login").value = self.student_id
737        self.browser.getControl(name="form.password").value = 'spwd'
738        self.browser.getControl("Login").click()
739
740        # Students can add online clearance payment tickets
741        self.browser.open(self.payments_student_path + '/addop')
742        self.browser.getControl(name="form.p_category").value = ['clearance']
743        self.browser.getControl("Create ticket").click()
744        self.assertMatches('...ticket created...',
745                           self.browser.contents)
746
747        # Students can open the callback view which simulates a valid callback
748        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
749        ctrl = self.browser.getControl(name='val_id')
750        value = ctrl.options[0]
751        self.browser.getLink(value).click()
752        self.browser.open(self.browser.url + '/callback')
753        self.assertMatches('...Valid callback received...',
754                          self.browser.contents)
755        expected = '''...
756        <td>
757          Paid
758        </td>...'''
759        self.assertMatches(expected,self.browser.contents)
760        # The new CLR-0 pin has been created
761        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
762        pin = self.app['accesscodes']['CLR-0'].keys()[0]
763        ac = self.app['accesscodes']['CLR-0'][pin]
764        ac.owner = self.student_id
765        # The new CLR-0 pin can be used for starting clearance
766        IWorkflowInfo(self.student).fireTransition('admit')
767        self.browser.open(self.student_path + '/start_clearance')
768        parts = pin.split('-')[1:]
769        clrseries, clrnumber = parts
770        self.browser.getControl(name="ac_series").value = clrseries
771        self.browser.getControl(name="ac_number").value = clrnumber
772        self.browser.getControl("Start clearance now").click()
773        self.assertMatches('...Clearance process has been started...',
774                           self.browser.contents)
775
776        # Students can add online school fee payment tickets
777        self.browser.open(self.payments_student_path)
778        self.browser.getControl("Add online payment ticket").click()
779        self.browser.getControl(name="form.p_category").value = ['schoolfee']
780        self.browser.getControl("Create ticket").click()
781        self.assertMatches('...ticket created...',
782                           self.browser.contents)
783        ctrl = self.browser.getControl(name='val_id')
784        value = ctrl.options[0]
785        self.browser.getLink(value).click()
786        self.assertMatches('...Amount Authorized...',
787                           self.browser.contents)
788
789        # Students can open the callback view which simulates a valid callback
790        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
791        self.browser.open(self.browser.url + '/callback')
792        self.assertMatches('...Valid callback received...',
793                          self.browser.contents)
794
795        # Students can remove only online payment tickets which have
796        # not received a valid callback
797        self.browser.open(self.payments_student_path)
798        self.assertRaises(
799            LookupError, self.browser.getControl, name='val_id')
800        self.browser.open(self.payments_student_path + '/addop')
801        self.browser.getControl(name="form.p_category").value = ['gown']
802        self.browser.getControl("Create ticket").click()
803        self.browser.open(self.payments_student_path)
804        ctrl = self.browser.getControl(name='val_id')
805        value = ctrl.options[0]
806        ctrl.getControl(value=value).selected = True
807        self.browser.getControl("Remove selected", index=0).click()
808        self.assertTrue('Successfully removed' in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.