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

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

Add missing handler.

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