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

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

Much more logic for bed allocation, bed release.

Implement student relocation.

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