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

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

Filter actions if students are using the AccommodationManageFormPage?.

I first tried to use two different pages, one for officers and one for students, and use different targets in breadcrumbs. But this was much more complicated.

  • Property svn:keywords set to Id
File size: 44.8 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 7009 2011-11-06 17:24:21Z 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        return
500
501    def test_student_change_password(self):
502        # Students can change the password
503        self.browser.open(self.login_path)
504        self.browser.getControl(name="form.login").value = self.student_id
505        self.browser.getControl(name="form.password").value = 'spwd'
506        self.browser.getControl("Login").click()
507        self.assertEqual(self.browser.url, self.student_path)
508        self.assertTrue('You logged in' in self.browser.contents)
509        # Change password
510        self.browser.getLink("Change password").click()
511        self.browser.getControl(name="form.password").value = 'new_password'
512        self.browser.getControl(
513            name="form.password_repeat").value = 'new_passssword'
514        self.browser.getControl("Save").click()
515        self.assertTrue('passwords do not match' in self.browser.contents)
516        self.browser.getControl(name="form.password").value = 'new_password'
517        self.browser.getControl(
518            name="form.password_repeat").value = 'new_password'
519        self.browser.getControl("Save").click()
520        self.assertTrue('Form has been saved' in self.browser.contents)
521        # We are still logged in. Changing the password hasn't thrown us out.
522        self.browser.getLink("My Data").click()
523        self.assertEqual(self.browser.url, self.student_path)
524        # We can logout
525        self.browser.getLink("Logout").click()
526        self.assertTrue('You have been logged out' in self.browser.contents)
527        self.assertEqual(self.browser.url, 'http://localhost/app')
528        # We can login again with the new password
529        self.browser.getLink("Login").click()
530        self.browser.open(self.login_path)
531        self.browser.getControl(name="form.login").value = self.student_id
532        self.browser.getControl(name="form.password").value = 'new_password'
533        self.browser.getControl("Login").click()
534        self.assertEqual(self.browser.url, self.student_path)
535        self.assertTrue('You logged in' in self.browser.contents)
536        return
537
538    def test_setpassword(self):
539        # Set password for first-time access
540        student = Student()
541        student.reg_number = u'123456'
542        student.fullname = u'Klaus Tester'
543        self.app['students'].addStudent(student)
544        setpassword_path = 'http://localhost/app/setpassword'
545        student_path = 'http://localhost/app/students/%s' % student.student_id
546        self.browser.open(setpassword_path)
547        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
548        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
549        self.browser.getControl(name="reg_number").value = '223456'
550        self.browser.getControl("Show").click()
551        self.assertMatches('...No student found...',
552                           self.browser.contents)
553        self.browser.getControl(name="reg_number").value = '123456'
554        self.browser.getControl(name="ac_number").value = '999999'
555        self.browser.getControl("Show").click()
556        self.assertMatches('...Access code is invalid...',
557                           self.browser.contents)
558        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
559        self.browser.getControl("Show").click()
560        self.assertMatches('...Password has been set. Your Student Id is...',
561                           self.browser.contents)
562        self.browser.getControl("Show").click()
563        self.assertMatches(
564            '...Password has already been set. Your Student Id is...',
565            self.browser.contents)
566        existing_pwdpin = self.pwdpins[1]
567        parts = existing_pwdpin.split('-')[1:]
568        existing_pwdseries, existing_pwdnumber = parts
569        self.browser.getControl(name="ac_series").value = existing_pwdseries
570        self.browser.getControl(name="ac_number").value = existing_pwdnumber
571        self.browser.getControl(name="reg_number").value = '123456'
572        self.browser.getControl("Show").click()
573        self.assertMatches(
574            '...You are using the wrong Access Code...',
575            self.browser.contents)
576        # The student can login with the new credentials
577        self.browser.open(self.login_path)
578        self.browser.getControl(name="form.login").value = student.student_id
579        self.browser.getControl(
580            name="form.password").value = self.existing_pwdnumber
581        self.browser.getControl("Login").click()
582        self.assertEqual(self.browser.url, student_path)
583        self.assertTrue('You logged in' in self.browser.contents)
584        return
585
586    def test_student_access(self):
587        # Students can access their own objects
588        # and can perform actions
589        IWorkflowInfo(self.student).fireTransition('admit')
590        self.browser.open(self.login_path)
591        self.browser.getControl(name="form.login").value = self.student_id
592        self.browser.getControl(name="form.password").value = 'spwd'
593        self.browser.getControl("Login").click()
594        # Student can view the clearance data
595        self.browser.getLink("Clearance Data").click()
596        # Student can't open clearance edit form before starting clearance
597        self.browser.open(self.student_path + '/cedit')
598        self.assertMatches('...The requested form is locked...',
599                           self.browser.contents)
600        self.browser.getLink("Clearance Data").click()
601        self.browser.getLink("Start clearance").click()
602        self.browser.getControl(name="ac_series").value = '3'
603        self.browser.getControl(name="ac_number").value = '4444444'
604        self.browser.getControl("Start clearance now").click()
605        self.assertMatches('...Activation code is invalid...',
606                           self.browser.contents)
607        self.browser.getControl(name="ac_series").value = self.existing_clrseries
608        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
609        # Owner is Hans Wurst, AC can't be invalidated
610        self.browser.getControl("Start clearance now").click()
611        self.assertMatches('...You are not the owner of this access code...',
612                           self.browser.contents)
613        # Set the correct owner
614        self.existing_clrac.owner = self.student_id
615        self.browser.getControl("Start clearance now").click()
616        self.assertMatches('...Clearance process has been started...',
617                           self.browser.contents)
618        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
619        self.browser.getControl("Save", index=0).click()
620        # Student can view the clearance data
621        self.browser.getLink("Clearance Data").click()
622        # and go back to the edit form
623        self.browser.getLink("Edit").click()
624        self.browser.getControl("Save and request clearance").click()
625        self.browser.getControl(name="ac_series").value = self.existing_clrseries
626        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
627        self.browser.getControl("Request clearance now").click()
628        self.assertMatches('...Clearance has been requested...',
629                           self.browser.contents)
630        # Student can't reopen clearance form after requesting clearance
631        self.browser.open(self.student_path + '/cedit')
632        self.assertMatches('...The requested form is locked...',
633                           self.browser.contents)
634        # Student can't add study level if not in state 'school fee paid'
635        self.browser.open(self.student_path + '/studycourse/add')
636        self.assertMatches('...The requested form is locked...',
637                           self.browser.contents)
638        # ... and must be transferred first
639        IWorkflowInfo(self.student).fireTransition('clear')
640        IWorkflowInfo(self.student).fireTransition('pay_first_school_fee')
641        # Now students can add the current study level
642        self.browser.getLink("Study Course").click()
643        self.browser.getLink("Add course list").click()
644        self.assertMatches('...Add current level 100 (Year 1)...',
645                           self.browser.contents)
646        self.browser.getControl("Create course list now").click()
647        self.browser.getLink("100").click()
648        self.browser.getLink("Add and remove courses").click()
649        self.browser.getControl("Add course ticket").click()
650        self.browser.getControl(name="form.course").value = ['COURSE1']
651        self.browser.getControl("Add course ticket").click()
652        self.assertMatches('...The ticket exists...',
653                           self.browser.contents)
654        self.student['studycourse'].current_level = 200
655        self.browser.getLink("Study Course").click()
656        self.browser.getLink("Add course list").click()
657        self.assertMatches('...Add current level 200 (Year 2)...',
658                           self.browser.contents)
659        self.browser.getControl("Create course list now").click()
660        self.browser.getLink("200").click()
661        self.browser.getLink("Add and remove courses").click()
662        self.browser.getControl("Add course ticket").click()
663        self.browser.getControl(name="form.course").value = ['COURSE1']
664        self.browser.getControl("Add course ticket").click()
665        self.assertMatches('...Successfully added COURSE1...',
666                           self.browser.contents)
667        self.browser.getControl("Remove selected", index=0).click()
668        self.assertTrue('No ticket selected' in self.browser.contents)
669        ctrl = self.browser.getControl(name='val_id')
670        ctrl.getControl(value='COURSE1').selected = True
671        self.browser.getControl("Remove selected", index=0).click()
672        self.assertTrue('Successfully removed' in self.browser.contents)
673        self.browser.getControl("Register course list").click()
674        self.assertTrue('Course list has been registered' in self.browser.contents)
675        self.assertEqual(self.student.state, 'courses registered')
676        return
677
678    def test_manage_payments(self):
679        # Managers can add online school fee payment tickets
680        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
681        self.browser.open(self.payments_student_path)
682        self.browser.getControl("Add online payment ticket").click()
683        self.browser.getControl(name="form.p_category").value = ['schoolfee']
684        self.browser.getControl("Create ticket").click()
685        self.assertMatches('...ticket created...',
686                           self.browser.contents)
687        ctrl = self.browser.getControl(name='val_id')
688        value = ctrl.options[0]
689        self.browser.getLink(value).click()
690        self.assertMatches('...Amount Authorized...',
691                           self.browser.contents)
692
693        # Managers can open the callback view which simulates a valid callback
694        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
695        self.browser.open(self.browser.url + '/callback')
696        self.assertMatches('...Valid callback received...',
697                          self.browser.contents)
698
699        # Managers can remove online school fee payment tickets
700        self.browser.open(self.payments_student_path)
701        self.browser.getControl("Remove selected").click()
702        self.assertMatches('...No payment selected...', self.browser.contents)
703        ctrl = self.browser.getControl(name='val_id')
704        value = ctrl.options[0]
705        ctrl.getControl(value=value).selected = True
706        self.browser.getControl("Remove selected", index=0).click()
707        self.assertTrue('Successfully removed' in self.browser.contents)
708
709        # Managers can add online clearance payment tickets
710        self.browser.open(self.payments_student_path + '/addop')
711        self.browser.getControl(name="form.p_category").value = ['clearance']
712        self.browser.getControl("Create ticket").click()
713        self.assertMatches('...ticket created...',
714                           self.browser.contents)
715
716        # Managers can open the callback view which simulates a valid callback
717        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
718        ctrl = self.browser.getControl(name='val_id')
719        value = ctrl.options[0]
720        self.browser.getLink(value).click()
721        self.browser.open(self.browser.url + '/callback')
722        self.assertMatches('...Valid callback received...',
723                          self.browser.contents)
724        expected = '''...
725        <td>
726          Paid
727        </td>...'''
728        self.assertMatches(expected,self.browser.contents)
729        # The new CLR-0 pin has been created
730        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
731        pin = self.app['accesscodes']['CLR-0'].keys()[0]
732        ac = self.app['accesscodes']['CLR-0'][pin]
733        ac.owner = self.student_id
734        # The new CLR-0 pin can be used for starting clearance
735        IWorkflowInfo(self.student).fireTransition('admit')
736        self.browser.open(self.student_path + '/start_clearance')
737        parts = pin.split('-')[1:]
738        clrseries, clrnumber = parts
739        self.browser.getControl(name="ac_series").value = clrseries
740        self.browser.getControl(name="ac_number").value = clrnumber
741        self.browser.getControl("Start clearance now").click()
742        self.assertMatches('...Clearance process has been started...',
743                           self.browser.contents)
744        return
745
746    def test_student_payments(self):
747        # Set up SessionConfiguration object
748        self.browser.open(self.login_path)
749        self.browser.getControl(name="form.login").value = self.student_id
750        self.browser.getControl(name="form.password").value = 'spwd'
751        self.browser.getControl("Login").click()
752
753        # Students can add online clearance payment tickets
754        self.browser.open(self.payments_student_path + '/addop')
755        self.browser.getControl(name="form.p_category").value = ['clearance']
756        self.browser.getControl("Create ticket").click()
757        self.assertMatches('...ticket created...',
758                           self.browser.contents)
759
760        # Students can open the callback view which simulates a valid callback
761        self.assertEqual(len(self.app['accesscodes']['CLR-0']),0)
762        ctrl = self.browser.getControl(name='val_id')
763        value = ctrl.options[0]
764        self.browser.getLink(value).click()
765        self.browser.open(self.browser.url + '/callback')
766        self.assertMatches('...Valid callback received...',
767                          self.browser.contents)
768        expected = '''...
769        <td>
770          Paid
771        </td>...'''
772        self.assertMatches(expected,self.browser.contents)
773        # The new CLR-0 pin has been created
774        self.assertEqual(len(self.app['accesscodes']['CLR-0']),1)
775        pin = self.app['accesscodes']['CLR-0'].keys()[0]
776        ac = self.app['accesscodes']['CLR-0'][pin]
777        ac.owner = self.student_id
778        # The new CLR-0 pin can be used for starting clearance
779        IWorkflowInfo(self.student).fireTransition('admit')
780        self.browser.open(self.student_path + '/start_clearance')
781        parts = pin.split('-')[1:]
782        clrseries, clrnumber = parts
783        self.browser.getControl(name="ac_series").value = clrseries
784        self.browser.getControl(name="ac_number").value = clrnumber
785        self.browser.getControl("Start clearance now").click()
786        self.assertMatches('...Clearance process has been started...',
787                           self.browser.contents)
788
789        # Students can add online school fee payment tickets
790        self.browser.open(self.payments_student_path)
791        self.browser.getControl("Add online payment ticket").click()
792        self.browser.getControl(name="form.p_category").value = ['schoolfee']
793        self.browser.getControl("Create ticket").click()
794        self.assertMatches('...ticket created...',
795                           self.browser.contents)
796        ctrl = self.browser.getControl(name='val_id')
797        value = ctrl.options[0]
798        self.browser.getLink(value).click()
799        self.assertMatches('...Amount Authorized...',
800                           self.browser.contents)
801
802        # Students can open the callback view which simulates a valid callback
803        self.assertEqual(len(self.app['accesscodes']['SFE-0']),0)
804        self.browser.open(self.browser.url + '/callback')
805        self.assertMatches('...Valid callback received...',
806                          self.browser.contents)
807
808        # Students can remove only online payment tickets which have
809        # not received a valid callback
810        self.browser.open(self.payments_student_path)
811        self.assertRaises(
812            LookupError, self.browser.getControl, name='val_id')
813        self.browser.open(self.payments_student_path + '/addop')
814        self.browser.getControl(name="form.p_category").value = ['gown']
815        self.browser.getControl("Create ticket").click()
816        self.browser.open(self.payments_student_path)
817        ctrl = self.browser.getControl(name='val_id')
818        value = ctrl.options[0]
819        ctrl.getControl(value=value).selected = True
820        self.browser.getControl("Remove selected", index=0).click()
821        self.assertTrue('Successfully removed' in self.browser.contents)
822
823        # The new SFE-0 pin can be used for starting course registration
824        IWorkflowInfo(self.student).fireTransition('request_clearance')
825        IWorkflowInfo(self.student).fireTransition('clear')
826        self.browser.open(self.studycourse_student_path)
827        self.browser.getLink('Start course registration').click()
828        pin = self.app['accesscodes']['SFE-0'].keys()[0]
829        parts = pin.split('-')[1:]
830        sfeseries, sfenumber = parts
831        self.browser.getControl(name="ac_series").value = sfeseries
832        self.browser.getControl(name="ac_number").value = sfenumber
833        self.browser.getControl("Start course registration now").click()
834        self.assertMatches('...Course registration has been started...',
835                           self.browser.contents)
836        self.assertTrue(self.student.state,'school fee paid')
837        return
838
839    def test_manage_accommodation(self):
840        # Managers can add online booking fee payment tickets and open the
841        # callback view (see test_manage_payments)
842        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
843        self.browser.open(self.payments_student_path)
844        self.browser.getControl("Add online payment ticket").click()
845        self.browser.getControl(name="form.p_category").value = ['bed_allocation']
846        self.browser.getControl("Create ticket").click()
847        ctrl = self.browser.getControl(name='val_id')
848        value = ctrl.options[0]
849        self.browser.getLink(value).click()
850        self.browser.open(self.browser.url + '/callback')
851        # The new HOS-0 pin has been created
852        self.assertEqual(len(self.app['accesscodes']['HOS-0']),1)
853        pin = self.app['accesscodes']['HOS-0'].keys()[0]
854        ac = self.app['accesscodes']['HOS-0'][pin]
855        ac.owner = self.student_id
856        parts = pin.split('-')[1:]
857        sfeseries, sfenumber = parts
858        # Managers can use HOS code and book a bed space with it
859        self.browser.open(self.acco_student_path)
860        self.browser.getControl("Book accommodation").click()
861        self.assertMatches('...Wrong state...',
862                           self.browser.contents)
863        IWorkflowInfo(self.student).fireTransition('admit')
864        self.browser.getControl("Book accommodation").click()
865        self.assertMatches('...Activation Code:...',
866                           self.browser.contents)
867        self.browser.getControl(name="ac_series").value = sfeseries
868        self.browser.getControl(name="ac_number").value = sfenumber
869        self.browser.getControl("Create bed ticket").click()
870        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
871                           self.browser.contents)
872        # Bed has been allocated
873        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
874        self.assertTrue(bed.owner,self.student_id)
875        # BedTicketAddPage is now blocked
876        self.browser.getControl("Book accommodation").click()
877        self.assertMatches('...Ticket for 2004 already created...',
878            self.browser.contents)
879        # The bed ticket displays the data correctly
880        self.browser.open(self.acco_student_path + '/2004')
881        self.assertMatches('...Hall 1, Block A, Room 101, Bed A...',
882                           self.browser.contents)
883        self.assertMatches('...2004/2005...', self.browser.contents)
884        self.assertMatches('...regular_male_fr...', self.browser.contents)
885        self.assertMatches('...%s...' % pin, self.browser.contents)
886        # Managers cab delete bed tickets
887        self.browser.open(self.acco_student_path)
888        ctrl = self.browser.getControl(name='val_id')
889        value = ctrl.options[0]
890        ctrl.getControl(value=value).selected = True
891        self.browser.getControl("Remove selected", index=0).click()
892        self.assertMatches('...Successfully removed...', self.browser.contents)
893        # The bed has been released properly by the event handler
894        bed = self.app['hostels']['hall-1']['hall-1_A_101_A']
895        self.assertTrue(bed.owner == NOT_OCCUPIED)
896        return
897
898    def test_student_accommodation(self):
899        return
Note: See TracBrowser for help on using the repository browser.