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

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

Add tests for student accommodation booking.

  • Property svn:keywords set to Id
File size: 48.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 7017 2011-11-07 09:42:01Z 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 two beds
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        bed = Bed()
175        bed.bed_id = u'hall-1_A_101_B'
176        bed.bed_number = 2
177        bed.owner = NOT_OCCUPIED
178        bed.bed_type = u'regular_female_fr'
179        self.app['hostels'][hostel.hostel_id].addBed(bed)
180
181        # Set study course attributes of test student
182        self.student['studycourse'].certificate = self.certificate
183        self.student['studycourse'].current_session = 2004
184        self.student['studycourse'].entry_session = 2004
185        self.student['studycourse'].current_verdict = 'A'
186        self.student['studycourse'].current_level = 100
187
188        # Put the prepopulated site into test ZODB and prepare test
189        # browser
190        self.browser = Browser()
191        self.browser.handleErrors = False
192
193    def tearDown(self):
194        super(StudentsFullSetup, self).tearDown()
195        clearSite()
196        shutil.rmtree(self.dc_root)
197
198
199
200class StudentsContainerUITests(StudentsFullSetup):
201    # Tests for StudentsContainer class views and pages
202
203    layer = FunctionalLayer
204
205    def test_anonymous_access(self):
206        # Anonymous users can't access students containers
207        self.assertRaises(
208            Unauthorized, self.browser.open, self.container_path)
209        self.assertRaises(
210            Unauthorized, self.browser.open, self.manage_container_path)
211        return
212
213    def test_manage_access(self):
214        # Managers can access the view page of students
215        # containers and can perform actions
216        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
217        self.browser.open(self.container_path)
218        self.assertEqual(self.browser.headers['Status'], '200 Ok')
219        self.assertEqual(self.browser.url, self.container_path)
220        self.browser.getLink("Manage student section").click()
221        self.assertEqual(self.browser.headers['Status'], '200 Ok')
222        self.assertEqual(self.browser.url, self.manage_container_path)
223        return
224
225    def test_add_search_delete_students(self):
226        # Managers can add search and remove students
227        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
228        self.browser.open(self.manage_container_path)
229        self.browser.getLink("Add student").click()
230        self.assertEqual(self.browser.headers['Status'], '200 Ok')
231        self.assertEqual(self.browser.url, self.add_student_path)
232        self.browser.getControl(name="form.fullname").value = 'Bob Tester'
233        self.browser.getControl("Create student record").click()
234        self.assertTrue('Student record created' in self.browser.contents)
235
236        # Registration and matric numbers must be unique
237        self.browser.getLink("Manage").click()
238        self.browser.getControl(name="form.reg_number").value = '123'
239        self.browser.getControl("Save").click()
240        self.assertMatches('...Registration number exists...',
241                           self.browser.contents)
242        self.browser.getControl(name="form.reg_number").value = '789'
243        self.browser.getControl(name="form.matric_number").value = '234'
244        self.browser.getControl("Save").click()
245        self.assertMatches('...Matriculation number exists...',
246                           self.browser.contents)
247
248        self.browser.open(self.container_path)
249        self.browser.getControl("Search").click()
250        self.assertTrue('Empty search string' in self.browser.contents)
251        self.browser.getControl(name="searchtype").value = ['student_id']
252        self.browser.getControl(name="searchterm").value = self.student_id
253        self.browser.getControl("Search").click()
254        self.assertTrue('Anna Tester' in self.browser.contents)
255
256        self.browser.open(self.manage_container_path)
257        self.browser.getControl("Search").click()
258        self.assertTrue('Empty search string' in self.browser.contents)
259        self.browser.getControl(name="searchtype").value = ['fullname']
260        self.browser.getControl(name="searchterm").value = 'Anna Tester'
261        self.browser.getControl("Search").click()
262        self.assertTrue('Anna Tester' in self.browser.contents)
263        # The old searchterm will be used again
264        self.browser.getControl("Search").click()
265        self.assertTrue('Anna Tester' in self.browser.contents)
266
267        ctrl = self.browser.getControl(name='entries')
268        ctrl.getControl(value=self.student_id).selected = True
269        self.browser.getControl("Remove selected", index=0).click()
270        self.assertTrue('Successfully removed' in self.browser.contents)
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
276        self.browser.open(self.container_path)
277        self.browser.getControl(name="searchtype").value = ['student_id']
278        self.browser.getControl(name="searchterm").value = self.student_id
279        self.browser.getControl("Search").click()
280        self.assertTrue('No student found' in self.browser.contents)
281        return
282
283class StudentUITests(StudentsFullSetup):
284    # Tests for Student class views and pages
285
286    layer = FunctionalLayer
287
288    def test_manage_access(self):
289        # Managers can access the pages of students
290        # and can perform actions
291        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
292
293        self.browser.open(self.student_path)
294        self.assertEqual(self.browser.headers['Status'], '200 Ok')
295        self.assertEqual(self.browser.url, self.student_path)
296        self.browser.getLink("Manage").click()
297        self.assertEqual(self.browser.headers['Status'], '200 Ok')
298        self.assertEqual(self.browser.url, self.manage_student_path)
299        # Managers can edit base data and fire transitions
300        self.browser.getControl(name="transition").value = ['admit']
301        self.browser.getControl(name="form.fullname").value = 'John Tester'
302        self.browser.getControl(name="form.reg_number").value = '345'
303        self.browser.getControl(name="password").value = 'secret'
304        self.browser.getControl(name="control_password").value = 'secret'
305        self.browser.getControl("Save").click()
306        self.assertMatches('...Form has been saved...',
307                           self.browser.contents)
308        self.browser.open(self.student_path)
309        self.browser.getLink("Clearance Data").click()
310        self.assertEqual(self.browser.headers['Status'], '200 Ok')
311        self.assertEqual(self.browser.url, self.clearance_student_path)
312        self.browser.getLink("Manage").click()
313        self.assertEqual(self.browser.headers['Status'], '200 Ok')
314        self.assertEqual(self.browser.url, self.edit_clearance_student_path)
315        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
316        self.browser.getControl("Save").click()
317        self.assertMatches('...Form has been saved...',
318                           self.browser.contents)
319
320        self.browser.open(self.student_path)
321        self.browser.getLink("Personal Data").click()
322        self.assertEqual(self.browser.headers['Status'], '200 Ok')
323        self.assertEqual(self.browser.url, self.personal_student_path)
324        self.browser.getLink("Manage").click()
325        self.assertEqual(self.browser.headers['Status'], '200 Ok')
326        self.assertEqual(self.browser.url, self.edit_personal_student_path)
327        self.browser.getControl("Save").click()
328        self.assertMatches('...Form has been saved...',
329                           self.browser.contents)
330
331        # Managers can browse all subobjects
332        self.browser.open(self.student_path)
333        self.browser.getLink("Payments").click()
334        self.assertEqual(self.browser.headers['Status'], '200 Ok')
335        self.assertEqual(self.browser.url, self.payments_student_path)
336        self.browser.open(self.student_path)
337        self.browser.getLink("Accommodation").click()
338        self.assertEqual(self.browser.headers['Status'], '200 Ok')
339        self.assertEqual(self.browser.url, self.acco_student_path)
340        self.browser.open(self.student_path)
341        self.browser.getLink("History").click()
342        self.assertEqual(self.browser.headers['Status'], '200 Ok')
343        self.assertEqual(self.browser.url, self.history_student_path)
344        self.assertMatches('...Student admitted by zope.mgr...',
345                           self.browser.contents)
346        return
347
348    def test_manage_course_lists(self):
349        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
350        self.browser.open(self.student_path)
351        self.browser.getLink("Study Course").click()
352        self.assertEqual(self.browser.headers['Status'], '200 Ok')
353        self.assertEqual(self.browser.url, self.studycourse_student_path)
354        self.browser.getLink("Manage").click()
355        self.assertTrue('Manage study course' in self.browser.contents)
356        # Before we can select a level, the certificate must be selected and saved
357        self.browser.getControl(name="form.certificate").value = ['CERT1']
358        self.browser.getControl(name="form.current_session").value = ['2004']
359        self.browser.getControl(name="form.current_verdict").value = ['A']
360        self.browser.getControl("Save").click()
361        # Now we can save also the current level which depends on start and end
362        # level of the certificate
363        self.browser.getControl(name="form.current_level").value = ['100']
364        self.browser.getControl("Save").click()
365        # Managers can add and remove any study level (course list)
366        self.browser.getControl(name="addlevel").value = ['100']
367        self.browser.getControl("Add study level").click()
368        self.assertMatches('...<span>100</span>...', self.browser.contents)
369        self.browser.getControl("Add study level").click()
370        self.assertMatches('...This level exists...', self.browser.contents)
371        self.browser.getControl("Remove selected").click()
372        self.assertMatches('...No study level selected...', self.browser.contents)
373        self.browser.getControl(name="val_id").value = ['100']
374        self.browser.getControl("Remove selected").click()
375        self.assertMatches('...Successfully removed...', self.browser.contents)
376        # Add level again
377        self.browser.getControl(name="addlevel").value = ['100']
378        self.browser.getControl("Add study level").click()
379        self.browser.getControl(name="addlevel").value = ['100']
380
381        # Managers can view and manage course lists
382        self.browser.getLink("100").click()
383        self.assertMatches('...: Study Level 100 (Year 1)...', self.browser.contents)
384        self.browser.getLink("Manage").click()
385        self.browser.getControl(name="form.level_session").value = ['2002']
386        self.browser.getControl("Save").click()
387        self.browser.getControl("Remove selected").click()
388        self.assertMatches('...No ticket selected...', self.browser.contents)
389        ctrl = self.browser.getControl(name='val_id')
390        ctrl.getControl(value='COURSE1').selected = True
391        self.browser.getControl("Remove selected", index=0).click()
392        self.assertTrue('Successfully removed' in self.browser.contents)
393        self.browser.getControl("Add course ticket").click()
394        self.browser.getControl(name="form.course").value = ['COURSE1']
395        self.browser.getControl("Add course ticket").click()
396        self.assertTrue('Successfully added' in self.browser.contents)
397        self.browser.getControl("Add course ticket").click()
398        self.browser.getControl(name="form.course").value = ['COURSE1']
399        self.browser.getControl("Add course ticket").click()
400        self.assertTrue('The ticket exists' in self.browser.contents)
401        self.browser.getControl("Cancel").click()
402        self.browser.getLink("COURSE1").click()
403        self.browser.getLink("Manage").click()
404        self.browser.getControl(name="form.score").value = '10'
405        self.browser.getControl("Save").click()
406        self.assertTrue('Form has been saved' in self.browser.contents)
407        return
408
409    def test_manage_workflow(self):
410        # Managers can pass through the whole workflow
411        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
412        student = self.app['students'][self.student_id]
413        self.browser.open(self.manage_student_path)
414        self.assertTrue(student.clearance_locked)
415        self.browser.getControl(name="transition").value = ['admit']
416        self.browser.getControl("Save").click()
417        self.assertTrue(student.clearance_locked)
418        self.browser.getControl(name="transition").value = ['start_clearance']
419        self.browser.getControl("Save").click()
420        self.assertFalse(student.clearance_locked)
421        self.browser.getControl(name="transition").value = ['request_clearance']
422        self.browser.getControl("Save").click()
423        self.assertTrue(student.clearance_locked)
424        self.browser.getControl(name="transition").value = ['clear']
425        self.browser.getControl("Save").click()
426        self.browser.getControl(name="transition").value = ['pay_first_school_fee']
427        self.browser.getControl("Save").click()
428        self.browser.getControl(name="transition").value = ['reset6']
429        self.browser.getControl("Save").click()
430        # In state returning the pay_school_fee transition triggers some
431        # changes of attributes
432        self.browser.getControl(name="transition").value = ['pay_school_fee']
433        self.browser.getControl("Save").click()
434        self.assertEqual(student['studycourse'].current_session, 2005) # +1
435        self.assertEqual(student['studycourse'].current_level, 200) # +100
436        self.assertEqual(student['studycourse'].current_verdict, '0') # 0 = not set
437        self.assertEqual(student['studycourse'].previous_verdict, 'A')
438        self.browser.getControl(name="transition").value = ['register_courses']
439        self.browser.getControl("Save").click()
440        self.browser.getControl(name="transition").value = ['validate_courses']
441        self.browser.getControl("Save").click()
442        self.browser.getControl(name="transition").value = ['return']
443        self.browser.getControl("Save").click()
444        return
445
446    def test_manage_import(self):
447        # Managers can import student data files
448        datacenter_path = 'http://localhost/app/datacenter'
449        # Prepare a csv file for students
450        open('students.csv', 'wb').write(
451"""firstname,lastname,fullname,reg_number,date_of_birth,matric_number
452Aaren,Pieri,Aaren Pieri,1,1990-01-02,100000
453Claus,Finau,Claus Finau,2,1990-01-03,100001
454Brit,Berson,Brit Berson,3,1990-01-04,100001
455""")
456        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
457        self.browser.open(datacenter_path)
458        self.browser.getLink('Upload CSV file').click()
459        filecontents = cStringIO.StringIO(open('students.csv', 'rb').read())
460        filewidget = self.browser.getControl(name='uploadfile:file')
461        filewidget.add_file(filecontents, 'text/plain', 'students.csv')
462        self.browser.getControl(name='SUBMIT').click()
463        self.browser.getLink('Batch processing').click()
464        button = lookup_submit_value(
465            'select', 'students_zope.mgr.csv', self.browser)
466        button.click()
467        importerselect = self.browser.getControl(name='importer')
468        modeselect = self.browser.getControl(name='mode')
469        importerselect.getControl('Student Importer').selected = True
470        modeselect.getControl(value='create').selected = True
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        self.assertTrue('Batch processing finished' in self.browser.contents)
477        open('studycourses.csv', 'wb').write(
478"""reg_number,matric_number,certificate,current_session,current_level
4791,,CERT1,2008,100
480,100001,CERT1,2008,100
481,100002,CERT1,2008,100
482""")
483        self.browser.open(datacenter_path)
484        self.browser.getLink('Upload CSV file').click()
485        filecontents = cStringIO.StringIO(open('studycourses.csv', 'rb').read())
486        filewidget = self.browser.getControl(name='uploadfile:file')
487        filewidget.add_file(filecontents, 'text/plain', 'studycourses.csv')
488        self.browser.getControl(name='SUBMIT').click()
489        self.browser.getLink('Batch processing').click()
490        button = lookup_submit_value(
491            'select', 'studycourses_zope.mgr.csv', self.browser)
492        button.click()
493        importerselect = self.browser.getControl(name='importer')
494        modeselect = self.browser.getControl(name='mode')
495        importerselect.getControl(
496            'StudentStudyCourse Importer (update only)').selected = True
497        modeselect.getControl(value='create').selected = True
498        self.browser.getControl('Proceed to step 3...').click()
499        self.assertTrue('Update mode only' in self.browser.contents)
500        self.browser.getControl('Proceed to step 3...').click()
501        self.assertTrue('Header fields OK' in self.browser.contents)
502        self.browser.getControl('Perform import...').click()
503        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
504        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
505        return
506
507    def test_student_change_password(self):
508        # Students can change the password
509        self.browser.open(self.login_path)
510        self.browser.getControl(name="form.login").value = self.student_id
511        self.browser.getControl(name="form.password").value = 'spwd'
512        self.browser.getControl("Login").click()
513        self.assertEqual(self.browser.url, self.student_path)
514        self.assertTrue('You logged in' in self.browser.contents)
515        # Change password
516        self.browser.getLink("Change password").click()
517        self.browser.getControl(name="form.password").value = 'new_password'
518        self.browser.getControl(
519            name="form.password_repeat").value = 'new_passssword'
520        self.browser.getControl("Save").click()
521        self.assertTrue('passwords do not match' in self.browser.contents)
522        self.browser.getControl(name="form.password").value = 'new_password'
523        self.browser.getControl(
524            name="form.password_repeat").value = 'new_password'
525        self.browser.getControl("Save").click()
526        self.assertTrue('Form has been saved' in self.browser.contents)
527        # We are still logged in. Changing the password hasn't thrown us out.
528        self.browser.getLink("My Data").click()
529        self.assertEqual(self.browser.url, self.student_path)
530        # We can logout
531        self.browser.getLink("Logout").click()
532        self.assertTrue('You have been logged out' in self.browser.contents)
533        self.assertEqual(self.browser.url, 'http://localhost/app')
534        # We can login again with the new password
535        self.browser.getLink("Login").click()
536        self.browser.open(self.login_path)
537        self.browser.getControl(name="form.login").value = self.student_id
538        self.browser.getControl(name="form.password").value = 'new_password'
539        self.browser.getControl("Login").click()
540        self.assertEqual(self.browser.url, self.student_path)
541        self.assertTrue('You logged in' in self.browser.contents)
542        return
543
544    def test_setpassword(self):
545        # Set password for first-time access
546        student = Student()
547        student.reg_number = u'123456'
548        student.fullname = u'Klaus Tester'
549        self.app['students'].addStudent(student)
550        setpassword_path = 'http://localhost/app/setpassword'
551        student_path = 'http://localhost/app/students/%s' % student.student_id
552        self.browser.open(setpassword_path)
553        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
554        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
555        self.browser.getControl(name="reg_number").value = '223456'
556        self.browser.getControl("Show").click()
557        self.assertMatches('...No student found...',
558                           self.browser.contents)
559        self.browser.getControl(name="reg_number").value = '123456'
560        self.browser.getControl(name="ac_number").value = '999999'
561        self.browser.getControl("Show").click()
562        self.assertMatches('...Access code is invalid...',
563                           self.browser.contents)
564        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
565        self.browser.getControl("Show").click()
566        self.assertMatches('...Password has been set. Your Student Id is...',
567                           self.browser.contents)
568        self.browser.getControl("Show").click()
569        self.assertMatches(
570            '...Password has already been set. Your Student Id is...',
571            self.browser.contents)
572        existing_pwdpin = self.pwdpins[1]
573        parts = existing_pwdpin.split('-')[1:]
574        existing_pwdseries, existing_pwdnumber = parts
575        self.browser.getControl(name="ac_series").value = existing_pwdseries
576        self.browser.getControl(name="ac_number").value = existing_pwdnumber
577        self.browser.getControl(name="reg_number").value = '123456'
578        self.browser.getControl("Show").click()
579        self.assertMatches(
580            '...You are using the wrong Access Code...',
581            self.browser.contents)
582        # The student can login with the new credentials
583        self.browser.open(self.login_path)
584        self.browser.getControl(name="form.login").value = student.student_id
585        self.browser.getControl(
586            name="form.password").value = self.existing_pwdnumber
587        self.browser.getControl("Login").click()
588        self.assertEqual(self.browser.url, student_path)
589        self.assertTrue('You logged in' in self.browser.contents)
590        return
591
592    def test_student_access(self):
593        # Students can access their own objects
594        # and can perform actions
595        IWorkflowInfo(self.student).fireTransition('admit')
596        self.browser.open(self.login_path)
597        self.browser.getControl(name="form.login").value = self.student_id
598        self.browser.getControl(name="form.password").value = 'spwd'
599        self.browser.getControl("Login").click()
600        # Student can view the clearance data
601        self.browser.getLink("Clearance Data").click()
602        # Student can't open clearance edit form before starting clearance
603        self.browser.open(self.student_path + '/cedit')
604        self.assertMatches('...The requested form is locked...',
605                           self.browser.contents)
606        self.browser.getLink("Clearance Data").click()
607        self.browser.getLink("Start clearance").click()
608        self.browser.getControl(name="ac_series").value = '3'
609        self.browser.getControl(name="ac_number").value = '4444444'
610        self.browser.getControl("Start clearance now").click()
611        self.assertMatches('...Activation code is invalid...',
612                           self.browser.contents)
613        self.browser.getControl(name="ac_series").value = self.existing_clrseries
614        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
615        # Owner is Hans Wurst, AC can't be invalidated
616        self.browser.getControl("Start clearance now").click()
617        self.assertMatches('...You are not the owner of this access code...',
618                           self.browser.contents)
619        # Set the correct owner
620        self.existing_clrac.owner = self.student_id
621        self.browser.getControl("Start clearance now").click()
622        self.assertMatches('...Clearance process has been started...',
623                           self.browser.contents)
624        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
625        self.browser.getControl("Save", index=0).click()
626        # Student can view the clearance data
627        self.browser.getLink("Clearance Data").click()
628        # and go back to the edit form
629        self.browser.getLink("Edit").click()
630        self.browser.getControl("Save and request clearance").click()
631        self.browser.getControl(name="ac_series").value = self.existing_clrseries
632        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
633        self.browser.getControl("Request clearance now").click()
634        self.assertMatches('...Clearance has been requested...',
635                           self.browser.contents)
636        # Student can't reopen clearance form after requesting clearance
637        self.browser.open(self.student_path + '/cedit')
638        self.assertMatches('...The requested form is locked...',
639                           self.browser.contents)
640        # Student can't add study level if not in state 'school fee paid'
641        self.browser.open(self.student_path + '/studycourse/add')
642        self.assertMatches('...The requested form is locked...',
643                           self.browser.contents)
644        # ... and must be transferred first
645        IWorkflowInfo(self.student).fireTransition('clear')
646        IWorkflowInfo(self.student).fireTransition('pay_first_school_fee')
647        # Now students can add the current study level
648        self.browser.getLink("Study Course").click()
649        self.browser.getLink("Add course list").click()
650        self.assertMatches('...Add current level 100 (Year 1)...',
651                           self.browser.contents)
652        self.browser.getControl("Create course list now").click()
653        self.browser.getLink("100").click()
654        self.browser.getLink("Add and remove courses").click()
655        self.browser.getControl("Add course ticket").click()
656        self.browser.getControl(name="form.course").value = ['COURSE1']
657        self.browser.getControl("Add course ticket").click()
658        self.assertMatches('...The ticket exists...',
659                           self.browser.contents)
660        self.student['studycourse'].current_level = 200
661        self.browser.getLink("Study Course").click()
662        self.browser.getLink("Add course list").click()
663        self.assertMatches('...Add current level 200 (Year 2)...',
664                           self.browser.contents)
665        self.browser.getControl("Create course list now").click()
666        self.browser.getLink("200").click()
667        self.browser.getLink("Add and remove courses").click()
668        self.browser.getControl("Add course ticket").click()
669        self.browser.getControl(name="form.course").value = ['COURSE1']
670        self.browser.getControl("Add course ticket").click()
671        self.assertMatches('...Successfully added COURSE1...',
672                           self.browser.contents)
673        self.browser.getControl("Remove selected", index=0).click()
674        self.assertTrue('No ticket selected' in self.browser.contents)
675        ctrl = self.browser.getControl(name='val_id')
676        ctrl.getControl(value='COURSE1').selected = True
677        self.browser.getControl("Remove selected", index=0).click()
678        self.assertTrue('Successfully removed' in self.browser.contents)
679        self.browser.getControl("Register course list").click()
680        self.assertTrue('Course list has been registered' in self.browser.contents)
681        self.assertEqual(self.student.state, 'courses registered')
682        return
683
684    def test_manage_payments(self):
685        # Managers can add online school fee payment tickets
686        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
687        self.browser.open(self.payments_student_path)
688        self.browser.getControl("Add online payment ticket").click()
689        self.browser.getControl(name="form.p_category").value = ['schoolfee']
690        self.browser.getControl("Create ticket").click()
691        self.assertMatches('...ticket created...',
692                           self.browser.contents)
693        ctrl = self.browser.getControl(name='val_id')
694        value = ctrl.options[0]
695        self.browser.getLink(value).click()
696        self.assertMatches('...Amount Authorized...',
697                           self.browser.contents)
698
699        # Managers can open the callback view which simulates a valid callback
700        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
701        self.browser.open(self.browser.url + '/callback')
702        self.assertMatches('...Valid callback received...',
703                          self.browser.contents)
704
705        # Managers can remove online school fee payment tickets
706        self.browser.open(self.payments_student_path)
707        self.browser.getControl("Remove selected").click()
708        self.assertMatches('...No payment selected...', self.browser.contents)
709        ctrl = self.browser.getControl(name='val_id')
710        value = ctrl.options[0]
711        ctrl.getControl(value=value).selected = True
712        self.browser.getControl("Remove selected", index=0).click()
713        self.assertTrue('Successfully removed' in self.browser.contents)
714
715        # Managers can add online clearance payment tickets
716        self.browser.open(self.payments_student_path + '/addop')
717        self.browser.getControl(name="form.p_category").value = ['clearance']
718        self.browser.getControl("Create ticket").click()
719        self.assertMatches('...ticket created...',
720                           self.browser.contents)
721
722        # Managers can open the callback view which simulates a valid callback
723        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
724        ctrl = self.browser.getControl(name='val_id')
725        value = ctrl.options[0]
726        self.browser.getLink(value).click()
727        self.browser.open(self.browser.url + '/callback')
728        self.assertMatches('...Valid callback received...',
729                          self.browser.contents)
730        expected = '''...
731        <td>
732          Paid
733        </td>...'''
734        self.assertMatches(expected,self.browser.contents)
735        # The new CLR-0 pin has been created
736        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
737        pin = self.app['accesscodes']['CLR-0'].keys()[0]
738        ac = self.app['accesscodes']['CLR-0'][pin]
739        ac.owner = self.student_id
740        # The new CLR-0 pin can be used for starting clearance
741        IWorkflowInfo(self.student).fireTransition('admit')
742        self.browser.open(self.student_path + '/start_clearance')
743        parts = pin.split('-')[1:]
744        clrseries, clrnumber = parts
745        self.browser.getControl(name="ac_series").value = clrseries
746        self.browser.getControl(name="ac_number").value = clrnumber
747        self.browser.getControl("Start clearance now").click()
748        self.assertMatches('...Clearance process has been started...',
749                           self.browser.contents)
750        return
751
752    def test_student_payments(self):
753        # Login
754        self.browser.open(self.login_path)
755        self.browser.getControl(name="form.login").value = self.student_id
756        self.browser.getControl(name="form.password").value = 'spwd'
757        self.browser.getControl("Login").click()
758
759        # Students can add online clearance payment tickets
760        self.browser.open(self.payments_student_path + '/addop')
761        self.browser.getControl(name="form.p_category").value = ['clearance']
762        self.browser.getControl("Create ticket").click()
763        self.assertMatches('...ticket created...',
764                           self.browser.contents)
765
766        # Students can open the callback view which simulates a valid callback
767        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
768        ctrl = self.browser.getControl(name='val_id')
769        value = ctrl.options[0]
770        self.browser.getLink(value).click()
771        self.browser.open(self.browser.url + '/callback')
772        self.assertMatches('...Valid callback received...',
773                          self.browser.contents)
774        expected = '''...
775        <td>
776          Paid
777        </td>...'''
778        self.assertMatches(expected,self.browser.contents)
779        # The new CLR-0 pin has been created
780        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
781        pin = self.app['accesscodes']['CLR-0'].keys()[0]
782        ac = self.app['accesscodes']['CLR-0'][pin]
783        ac.owner = self.student_id
784        # The new CLR-0 pin can be used for starting clearance
785        IWorkflowInfo(self.student).fireTransition('admit')
786        self.browser.open(self.student_path + '/start_clearance')
787        parts = pin.split('-')[1:]
788        clrseries, clrnumber = parts
789        self.browser.getControl(name="ac_series").value = clrseries
790        self.browser.getControl(name="ac_number").value = clrnumber
791        self.browser.getControl("Start clearance now").click()
792        self.assertMatches('...Clearance process has been started...',
793                           self.browser.contents)
794
795        # Students can add online school fee payment tickets
796        self.browser.open(self.payments_student_path)
797        self.browser.getControl("Add online payment ticket").click()
798        self.browser.getControl(name="form.p_category").value = ['schoolfee']
799        self.browser.getControl("Create ticket").click()
800        self.assertMatches('...ticket created...',
801                           self.browser.contents)
802        ctrl = self.browser.getControl(name='val_id')
803        value = ctrl.options[0]
804        self.browser.getLink(value).click()
805        self.assertMatches('...Amount Authorized...',
806                           self.browser.contents)
807
808        # Students can open the callback view which simulates a valid callback
809        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
810        self.browser.open(self.browser.url + '/callback')
811        self.assertMatches('...Valid callback received...',
812                          self.browser.contents)
813
814        # Students can remove only online payment tickets which have
815        # not received a valid callback
816        self.browser.open(self.payments_student_path)
817        self.assertRaises(
818            LookupError, self.browser.getControl, name='val_id')
819        self.browser.open(self.payments_student_path + '/addop')
820        self.browser.getControl(name="form.p_category").value = ['gown']
821        self.browser.getControl("Create ticket").click()
822        self.browser.open(self.payments_student_path)
823        ctrl = self.browser.getControl(name='val_id')
824        value = ctrl.options[0]
825        ctrl.getControl(value=value).selected = True
826        self.browser.getControl("Remove selected", index=0).click()
827        self.assertTrue('Successfully removed' in self.browser.contents)
828
829        # The new SFE-0 pin can be used for starting course registration
830        IWorkflowInfo(self.student).fireTransition('request_clearance')
831        IWorkflowInfo(self.student).fireTransition('clear')
832        self.browser.open(self.studycourse_student_path)
833        self.browser.getLink('Start course registration').click()
834        pin = self.app['accesscodes']['SFE-0'].keys()[0]
835        parts = pin.split('-')[1:]
836        sfeseries, sfenumber = parts
837        self.browser.getControl(name="ac_series").value = sfeseries
838        self.browser.getControl(name="ac_number").value = sfenumber
839        self.browser.getControl("Start course registration now").click()
840        self.assertMatches('...Course registration has been started...',
841                           self.browser.contents)
842        self.assertTrue(self.student.state == 'school fee paid')
843        return
844
845    def test_manage_accommodation(self):
846        # Managers can add online booking fee payment tickets and open the
847        # callback view (see test_manage_payments)
848        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
849        self.browser.open(self.payments_student_path)
850        self.browser.getControl("Add online payment ticket").click()
851        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
852        self.browser.getControl("Create ticket").click()
853        ctrl = self.browser.getControl(name='val_id')
854        value = ctrl.options[0]
855        self.browser.getLink(value).click()
856        self.browser.open(self.browser.url + '/callback')
857        # The new HOS-0 pin has been created
858        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
859        pin = self.app['accesscodes']['HOS-0'].keys()[0]
860        ac = self.app['accesscodes']['HOS-0'][pin]
861        ac.owner = self.student_id
862        parts = pin.split('-')[1:]
863        sfeseries, sfenumber = parts
864        # Managers can use HOS code and book a bed space with it
865        self.browser.open(self.acco_student_path)
866        self.browser.getLink("Book accommodation").click()
867        self.assertMatches('...You are in the wrong...',
868                           self.browser.contents)
869        IWorkflowInfo(self.student).fireTransition('admit')
870        self.browser.getLink("Book accommodation").click()
871        self.assertMatches('...Activation Code:...',
872                           self.browser.contents)
873        self.browser.getControl(name="ac_series").value = sfeseries
874        self.browser.getControl(name="ac_number").value = sfenumber
875        self.browser.getControl("Create bed ticket").click()
876        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
877                           self.browser.contents)
878        # Bed has been allocated
879        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
880        self.assertTrue(bed.owner == self.student_id)
881        # BedTicketAddPage is now blocked
882        self.browser.getLink("Book accommodation").click()
883        self.assertMatches('...You already booked a bed space...',
884            self.browser.contents)
885        # The bed ticket displays the data correctly
886        self.browser.open(self.acco_student_path + '/2004')
887        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
888                           self.browser.contents)
889        self.assertMatches('...2004/2005...', self.browser.contents)
890        self.assertMatches('...regular_male_fr...', self.browser.contents)
891        self.assertMatches('...%s...' % pin, self.browser.contents)
892        # Managers can relocate students
893        self.browser.getLink("Relocate student").click()
894        self.assertMatches(
895            "...Bed category hasn't changed...", self.browser.contents)
896        self.student.sex = u'f'
897        self.browser.getLink("Relocate student").click()
898        self.assertMatches(
899            "...Hall 1, Block A, Room 101, Bed B...", self.browser.contents)
900        bed1 = self.app['hostels']['hall-1']['hall-1_A_101_A']
901        self.assertTrue(bed1.owner == NOT_OCCUPIED)
902        bed2 = self.app['hostels']['hall-1']['hall-1_A_101_B']
903        self.assertTrue(bed2.owner == self.student_id)
904        # Managers can delete bed tickets
905        self.browser.open(self.acco_student_path)
906        ctrl = self.browser.getControl(name='val_id')
907        value = ctrl.options[0]
908        ctrl.getControl(value=value).selected = True
909        self.browser.getControl("Remove selected", index=0).click()
910        self.assertMatches('...Successfully removed...', self.browser.contents)
911        # The bed has been released properly by the event handler
912        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
913        self.assertTrue(bed.owner == NOT_OCCUPIED)
914        return
915
916    def test_student_accommodation(self):
917        # Login
918        self.browser.open(self.login_path)
919        self.browser.getControl(name="form.login").value = self.student_id
920        self.browser.getControl(name="form.password").value = 'spwd'
921        self.browser.getControl("Login").click()
922
923        # Students can add online booking fee payment tickets and open the
924        # callback view (see test_manage_payments)
925        self.browser.getLink("Payments").click()
926        self.browser.getControl("Add online payment ticket").click()
927        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
928        self.browser.getControl("Create ticket").click()
929        ctrl = self.browser.getControl(name='val_id')
930        value = ctrl.options[0]
931        self.browser.getLink(value).click()
932        self.browser.open(self.browser.url + '/callback')
933        # The new HOS-0 pin has been created
934        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
935        pin = self.app['accesscodes']['HOS-0'].keys()[0]
936        ac = self.app['accesscodes']['HOS-0'][pin]
937        ac.owner = self.student_id
938        parts = pin.split('-')[1:]
939        sfeseries, sfenumber = parts
940        # Students can use HOS code and book a bed space with it
941        self.browser.open(self.acco_student_path)
942        self.browser.getLink("Book accommodation").click()
943        self.assertMatches('...You are in the wrong...',
944                           self.browser.contents)
945        IWorkflowInfo(self.student).fireTransition('admit')
946        self.browser.getLink("Book accommodation").click()
947        self.assertMatches('...Activation Code:...',
948                           self.browser.contents)
949        self.browser.getControl(name="ac_series").value = sfeseries
950        self.browser.getControl(name="ac_number").value = sfenumber
951        self.browser.getControl("Create bed ticket").click()
952        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
953                           self.browser.contents)
954        # Bed has been allocated
955        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
956        self.assertTrue(bed.owner == self.student_id)
957        # BedTicketAddPage is now blocked
958        self.browser.getLink("Book accommodation").click()
959        self.assertMatches('...You already booked a bed space...',
960            self.browser.contents)
961        # The bed ticket displays the data correctly
962        self.browser.open(self.acco_student_path + '/2004')
963        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
964                           self.browser.contents)
965        self.assertMatches('...2004/2005...', self.browser.contents)
966        self.assertMatches('...regular_male_fr...', self.browser.contents)
967        self.assertMatches('...%s...' % pin, self.browser.contents)
968        # Students can't relocate themselves
969        self.assertFalse('Relocate' in self.browser.contents)
970        relocate_path = self.acco_student_path + '/2004/relocate'
971        self.assertRaises(
972            Unauthorized, self.browser.open, relocate_path)
973        # Students can't the Remove button and check boxes
974        self.browser.open(self.acco_student_path)
975        self.assertFalse('Remove' in self.browser.contents)
976        self.assertFalse('val_id' in self.browser.contents)
977        return
Note: See TracBrowser for help on using the repository browser.