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

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

Add register course list action.

  • Property svn:keywords set to Id
File size: 27.4 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 6810 2011-09-21 13:19:22Z 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
27from datetime import datetime
28from zope.component import createObject
29from zope.component.hooks import setSite, clearSite
30from zope.security.interfaces import Unauthorized
31from zope.testbrowser.testing import Browser
32from hurry.workflow.interfaces import IWorkflowInfo
33from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
34from waeup.sirp.app import University
35from waeup.sirp.students.student import Student
36from waeup.sirp.university.faculty import Faculty
37from waeup.sirp.university.department import Department
38from waeup.sirp.interfaces import IUserAccount
39
40PH_LEN = 2059  # Length of placeholder file
41
42class StudentsFullSetup(FunctionalTestCase):
43    # A test case that only contains a setup and teardown
44    #
45    # Complete setup for students handlings is rather complex and
46    # requires lots of things created before we can start. This is a
47    # setup that does all this, creates a university, creates PINs,
48    # etc.  so that we do not have to bother with that in different
49    # test cases.
50
51    layer = FunctionalLayer
52
53    def setUp(self):
54        super(StudentsFullSetup, self).setUp()
55
56        # Setup a sample site for each test
57        app = University()
58        self.dc_root = tempfile.mkdtemp()
59        app['datacenter'].setStoragePath(self.dc_root)
60
61        # Prepopulate the ZODB...
62        self.getRootFolder()['app'] = app
63        # we add the site immediately after creation to the
64        # ZODB. Catalogs and other local utilities are not setup
65        # before that step.
66        self.app = self.getRootFolder()['app']
67        # Set site here. Some of the following setup code might need
68        # to access grok.getSite() and should get our new app then
69        setSite(app)
70
71        # Add student with subobjects (done by addStudent)
72        student = Student()
73        student.name = u'Anna Tester'
74        student.reg_number = u'123'
75        student.matric_number = u'234'
76        self.test_student_id = self.app['students'].addStudent(student)
77        self.student = self.app['students'][self.test_student_id]
78
79        # Set password
80        IUserAccount(
81            self.app['students'][self.test_student_id]).setPassword('spwd')
82
83        self.login_path = 'http://localhost/app/login'
84        self.container_path = 'http://localhost/app/students'
85        self.manage_container_path = self.container_path + '/@@manage'
86        self.add_student_path = self.container_path + '/addstudent'
87        self.student_path = self.container_path + '/' + self.test_student_id
88        self.manage_student_path = self.student_path + '/edit_base'
89        self.clearance_student_path = self.student_path + '/view_clearance'
90        self.personal_student_path = self.student_path + '/view_personal'
91        self.edit_clearance_student_path = self.student_path + '/edit_clearance'
92        self.edit_personal_student_path = self.student_path + '/edit_personal'
93
94        self.studycourse_student_path = self.student_path + '/studycourse'
95        self.payments_student_path = self.student_path + '/payments'
96        self.accommodation_student_path = self.student_path + '/accommodation'
97        self.history_student_path = self.student_path + '/history'
98
99        # Create 5 access codes with prefix'PWD'
100        pin_container = self.app['accesscodes']
101        pin_container.createBatch(
102            datetime.now(), 'some_userid', 'PWD', 9.99, 5)
103        pins = pin_container[pin_container.keys()[0]].values()
104        self.pwdpins = [x.representation for x in pins]
105        self.existing_pwdpin = self.pwdpins[0]
106        parts = self.existing_pwdpin.split('-')[1:]
107        self.existing_pwdseries, self.existing_pwdnumber = parts
108        # Create 5 access codes with prefix 'CLR'
109        pin_container.createBatch(
110            datetime.now(), 'some_userid', 'CLR', 9.99, 5)
111        pins = pin_container[pin_container.keys()[0]].values()
112        self.clrpins = [x.representation for x in pins]
113        self.existing_clrpin = self.clrpins[0]
114        self.existing_clrpin
115        parts = self.existing_clrpin.split('-')[1:]
116        self.existing_clrseries, self.existing_clrnumber = parts
117
118        # Populate university
119        self.certificate = createObject('waeup.Certificate')
120        self.certificate.code = 'CERT1'
121        self.certificate.application_category = 'basic'
122        self.certificate.start_level = 100
123        self.certificate.end_level = 500
124        self.app['faculties']['fac1'] = Faculty()
125        self.app['faculties']['fac1']['dep1'] = Department()
126        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
127            self.certificate)
128        self.course = createObject('waeup.Course')
129        self.course.code = 'COURSE1'
130        self.course.semester = 1
131        self.course.credits = 10
132        self.course.passmark = 40
133        self.app['faculties']['fac1']['dep1'].courses.addCourse(
134            self.course)
135        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
136            self.course, level=100)
137
138        # Set study course attributes of test student
139        self.student['studycourse'].certificate = self.certificate
140        self.student['studycourse'].current_session = 2004
141        self.student['studycourse'].current_verdict = 'A'
142        self.student['studycourse'].current_level = 100
143
144        # Put the prepopulated site into test ZODB and prepare test
145        # browser
146        self.browser = Browser()
147        self.browser.handleErrors = False
148
149    def tearDown(self):
150        super(StudentsFullSetup, self).tearDown()
151        clearSite()
152        shutil.rmtree(self.dc_root)
153
154
155
156class StudentsContainerUITests(StudentsFullSetup):
157    # Tests for StudentsContainer class views and pages
158
159    layer = FunctionalLayer
160
161    def test_anonymous_access(self):
162        # Anonymous users can't access students containers
163        self.assertRaises(
164            Unauthorized, self.browser.open, self.container_path)
165        self.assertRaises(
166            Unauthorized, self.browser.open, self.manage_container_path)
167        return
168
169    def test_manage_access(self):
170        # Managers can access the view page of students
171        # containers and can perform actions
172        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
173        self.browser.open(self.container_path)
174        self.assertEqual(self.browser.headers['Status'], '200 Ok')
175        self.assertEqual(self.browser.url, self.container_path)
176        self.browser.getLink("Manage student section").click()
177        self.assertEqual(self.browser.headers['Status'], '200 Ok')
178        self.assertEqual(self.browser.url, self.manage_container_path)
179        return
180
181    def test_add_search_delete_students(self):
182        # Managers can add search and remove students
183        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
184        self.browser.open(self.manage_container_path)
185        self.browser.getLink("Add student").click()
186        self.assertEqual(self.browser.headers['Status'], '200 Ok')
187        self.assertEqual(self.browser.url, self.add_student_path)
188        self.browser.getControl(name="form.name").value = 'Bob Tester'
189        self.browser.getControl("Create student record").click()
190        self.assertTrue('Student record created' in self.browser.contents)
191
192        # Registration and matric numbers must be unique
193        self.browser.getLink("Manage").click()
194        self.browser.getControl(name="form.reg_number").value = '123'
195        self.browser.getControl("Save").click()
196        self.assertMatches('...Registration number exists...',
197                           self.browser.contents)
198        self.browser.getControl(name="form.reg_number").value = '789'
199        self.browser.getControl(name="form.matric_number").value = '234'
200        self.browser.getControl("Save").click()
201        self.assertMatches('...Matriculation number exists...',
202                           self.browser.contents)
203
204        self.browser.open(self.container_path)
205        self.browser.getControl("Search").click()
206        self.assertTrue('Empty search string' in self.browser.contents)
207        self.browser.getControl(name="searchtype").value = ['student_id']
208        self.browser.getControl(name="searchterm").value = self.test_student_id
209        self.browser.getControl("Search").click()
210        self.assertTrue('Anna Tester' in self.browser.contents)
211
212        self.browser.open(self.manage_container_path)
213        self.browser.getControl("Search").click()
214        self.assertTrue('Empty search string' in self.browser.contents)
215        self.browser.getControl(name="searchtype").value = ['name']
216        self.browser.getControl(name="searchterm").value = 'Anna Tester'
217        self.browser.getControl("Search").click()
218        self.assertTrue('Anna Tester' in self.browser.contents)
219        # The old searchterm will be used again
220        self.browser.getControl("Search").click()
221        self.assertTrue('Anna Tester' in self.browser.contents)
222
223        ctrl = self.browser.getControl(name='entries')
224        ctrl.getControl(value=self.test_student_id).selected = True
225        self.browser.getControl("Remove selected", index=0).click()
226        self.assertTrue('Successfully removed' in self.browser.contents)
227        self.browser.getControl(name="searchtype").value = ['student_id']
228        self.browser.getControl(name="searchterm").value = self.test_student_id
229        self.browser.getControl("Search").click()
230        self.assertTrue('No student found' in self.browser.contents)
231
232        self.browser.open(self.container_path)
233        self.browser.getControl(name="searchtype").value = ['student_id']
234        self.browser.getControl(name="searchterm").value = self.test_student_id
235        self.browser.getControl("Search").click()
236        self.assertTrue('No student found' in self.browser.contents)
237        return
238
239class StudentUITests(StudentsFullSetup):
240    # Tests for Student class views and pages
241
242    layer = FunctionalLayer
243
244    def test_manage_access(self):
245        # Managers can access the pages of students
246        # and can perform actions
247        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
248
249        self.browser.open(self.student_path)
250        self.assertEqual(self.browser.headers['Status'], '200 Ok')
251        self.assertEqual(self.browser.url, self.student_path)
252        self.browser.getLink("Manage").click()
253        self.assertEqual(self.browser.headers['Status'], '200 Ok')
254        self.assertEqual(self.browser.url, self.manage_student_path)
255        # Managers can edit base data and fire transitions
256        self.browser.getControl(name="transition").value = ['admit']
257        self.browser.getControl(name="form.name").value = 'John Tester'
258        self.browser.getControl(name="form.reg_number").value = '345'
259        self.browser.getControl(name="password").value = 'secret'
260        self.browser.getControl(name="control_password").value = 'secret'
261        self.browser.getControl("Save").click()
262        self.assertMatches('...Form has been saved...',
263                           self.browser.contents)
264        self.browser.open(self.student_path)
265        self.browser.getLink("Clearance Data").click()
266        self.assertEqual(self.browser.headers['Status'], '200 Ok')
267        self.assertEqual(self.browser.url, self.clearance_student_path)
268        self.browser.getLink("Manage").click()
269        self.assertEqual(self.browser.headers['Status'], '200 Ok')
270        self.assertEqual(self.browser.url, self.edit_clearance_student_path)
271        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
272        self.browser.getControl("Save").click()
273        self.assertMatches('...Form has been saved...',
274                           self.browser.contents)
275
276        self.browser.open(self.student_path)
277        self.browser.getLink("Personal Data").click()
278        self.assertEqual(self.browser.headers['Status'], '200 Ok')
279        self.assertEqual(self.browser.url, self.personal_student_path)
280        self.browser.getLink("Manage").click()
281        self.assertEqual(self.browser.headers['Status'], '200 Ok')
282        self.assertEqual(self.browser.url, self.edit_personal_student_path)
283        self.browser.getControl("Save").click()
284        self.assertMatches('...Form has been saved...',
285                           self.browser.contents)
286
287        # Managers can browse all subobjects
288        self.browser.open(self.student_path)
289        self.browser.getLink("Payments").click()
290        self.assertEqual(self.browser.headers['Status'], '200 Ok')
291        self.assertEqual(self.browser.url, self.payments_student_path)
292        self.browser.open(self.student_path)
293        self.browser.getLink("Accommodation").click()
294        self.assertEqual(self.browser.headers['Status'], '200 Ok')
295        self.assertEqual(self.browser.url, self.accommodation_student_path)
296        self.browser.open(self.student_path)
297        self.browser.getLink("History").click()
298        self.assertEqual(self.browser.headers['Status'], '200 Ok')
299        self.assertEqual(self.browser.url, self.history_student_path)
300        self.assertMatches('...Student admitted by zope.mgr...',
301                           self.browser.contents)
302        return
303
304    def test_manage_course_lists(self):
305        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
306        self.browser.open(self.student_path)
307        self.browser.getLink("Study Course").click()
308        self.assertEqual(self.browser.headers['Status'], '200 Ok')
309        self.assertEqual(self.browser.url, self.studycourse_student_path)
310        self.browser.getLink("Manage").click()
311        self.assertTrue('Manage study course' in self.browser.contents)
312        # Before we can select a level, the certificate must be selected and saved
313        self.browser.getControl(name="form.certificate").value = ['CERT1']
314        self.browser.getControl(name="form.current_session").value = ['2004']
315        self.browser.getControl(name="form.current_verdict").value = ['A']
316        self.browser.getControl("Save").click()
317        # Now we can save also the current level which depends on start and end
318        # level of the certificate
319        self.browser.getControl(name="form.current_level").value = ['100']
320        self.browser.getControl("Save").click()
321        # Managers can add and remove any study level (course list)
322        self.browser.getControl(name="addlevel").value = ['100']
323        self.browser.getControl("Add study level").click()
324        self.assertMatches('...<span>100</span>...', self.browser.contents)
325        self.browser.getControl(name="val_id").value = ['100']
326        self.browser.getControl("Remove selected").click()
327        self.assertMatches('...Successfully removed...', self.browser.contents)
328        # Add again level again
329        self.browser.getControl(name="addlevel").value = ['100']
330        self.browser.getControl("Add study level").click()
331
332        # Managers can view and manage course lists
333        self.browser.getLink("100").click()
334        self.assertMatches('...: Study Level 100 (Year 1)...', self.browser.contents)
335        self.browser.getLink("Manage").click()
336        self.browser.getControl(name="form.level_session").value = ['2002']
337        self.browser.getControl("Save").click()
338        ctrl = self.browser.getControl(name='val_id')
339        ctrl.getControl(value='COURSE1').selected = True
340        self.browser.getControl("Remove selected", index=0).click()
341        self.assertTrue('Successfully removed' in self.browser.contents)
342        self.browser.getControl("Add course ticket").click()
343        self.browser.getControl(name="form.course").value = ['COURSE1']
344        self.browser.getControl("Add course ticket").click()
345        self.assertTrue('Successfully added' in self.browser.contents)
346        self.browser.getLink("COURSE1").click()
347        self.browser.getLink("Manage").click()
348        self.browser.getControl(name="form.score").value = '10'
349        self.browser.getControl("Save").click()
350        self.assertTrue('Form has been saved' in self.browser.contents)
351        return
352
353    def test_manage_workflow(self):
354        # Managers can pass through the whole workflow
355        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
356        student = self.app['students'][self.test_student_id]
357        self.browser.open(self.manage_student_path)
358        self.assertTrue(student.clearance_locked)
359        self.browser.getControl(name="transition").value = ['admit']
360        self.browser.getControl("Save").click()
361        self.assertTrue(student.clearance_locked)
362        self.browser.getControl(name="transition").value = ['start_clearance']
363        self.browser.getControl("Save").click()
364        self.assertFalse(student.clearance_locked)
365        self.browser.getControl(name="transition").value = ['request_clearance']
366        self.browser.getControl("Save").click()
367        self.assertTrue(student.clearance_locked)
368        self.browser.getControl(name="transition").value = ['clear']
369        self.browser.getControl("Save").click()
370        self.browser.getControl(name="transition").value = ['pay_first_school_fee']
371        self.browser.getControl("Save").click()
372        self.browser.getControl(name="transition").value = ['reset6']
373        self.browser.getControl("Save").click()
374        # In state returning the pay_school_fee transition triggers some
375        # changes of attributes
376        self.browser.getControl(name="transition").value = ['pay_school_fee']
377        self.browser.getControl("Save").click()
378        self.assertEqual(student['studycourse'].current_session, 2005) # +1
379        self.assertEqual(student['studycourse'].current_level, 200) # +100
380        self.assertEqual(student['studycourse'].current_verdict, '0') # 0 = not set
381        self.assertEqual(student['studycourse'].previous_verdict, 'A')
382        self.browser.getControl(name="transition").value = ['register_courses']
383        self.browser.getControl("Save").click()
384        self.browser.getControl(name="transition").value = ['validate_courses']
385        self.browser.getControl("Save").click()
386        self.browser.getControl(name="transition").value = ['return']
387        self.browser.getControl("Save").click()
388        return
389
390    def test_student_change_password(self):
391        # Students can change the password
392        self.browser.open(self.login_path)
393        self.browser.getControl(name="form.login").value = self.test_student_id
394        self.browser.getControl(name="form.password").value = 'spwd'
395        self.browser.getControl("Login").click()
396        self.assertEqual(self.browser.url, self.student_path)
397        self.assertTrue('You logged in' in self.browser.contents)
398        # Change password
399        self.browser.getLink("Change password").click()
400        self.browser.getControl(name="form.password").value = 'new_password'
401        self.browser.getControl(
402            name="form.password_repeat").value = 'new_passssword'
403        self.browser.getControl("Save").click()
404        self.assertTrue('passwords do not match' in self.browser.contents)
405        self.browser.getControl(name="form.password").value = 'new_password'
406        self.browser.getControl(
407            name="form.password_repeat").value = 'new_password'
408        self.browser.getControl("Save").click()
409        self.assertTrue('Form has been saved' in self.browser.contents)
410        # We are still logged in. Changing the password hasn't thrown us out.
411        self.browser.getLink("My Data").click()
412        self.assertEqual(self.browser.url, self.student_path)
413        # We can logout
414        self.browser.getLink("Logout").click()
415        self.assertTrue('You have been logged out' in self.browser.contents)
416        self.assertEqual(self.browser.url, 'http://localhost/app')
417        # We can login again with the new password
418        self.browser.getLink("Login").click()
419        self.browser.open(self.login_path)
420        self.browser.getControl(name="form.login").value = self.test_student_id
421        self.browser.getControl(name="form.password").value = 'new_password'
422        self.browser.getControl("Login").click()
423        self.assertEqual(self.browser.url, self.student_path)
424        self.assertTrue('You logged in' in self.browser.contents)
425        return
426
427    def test_setpassword(self):
428        # Set password for first-time access
429        student = Student()
430        student.reg_number = u'123456'
431        student.name = u'Klaus Tester'
432        test_student_id = self.app['students'].addStudent(student)
433        setpassword_path = 'http://localhost/app/setpassword'
434        student_path = 'http://localhost/app/students/%s' % test_student_id
435        self.browser.open(setpassword_path)
436        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
437        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
438        self.browser.getControl(name="reg_number").value = '223456'
439        self.browser.getControl("Show").click()
440        self.assertMatches('...No student found...',
441                           self.browser.contents)
442        self.browser.getControl(name="reg_number").value = '123456'
443        self.browser.getControl(name="ac_number").value = '999999'
444        self.browser.getControl("Show").click()
445        self.assertMatches('...Access code is invalid...',
446                           self.browser.contents)
447        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
448        self.browser.getControl("Show").click()
449        self.assertMatches('...Password has been set. Your Student Id is...',
450                           self.browser.contents)
451        self.browser.getControl("Show").click()
452        self.assertMatches(
453            '...Password has already been set. Your Student Id is...',
454            self.browser.contents)
455        existing_pwdpin = self.pwdpins[1]
456        parts = existing_pwdpin.split('-')[1:]
457        existing_pwdseries, existing_pwdnumber = parts
458        self.browser.getControl(name="ac_series").value = existing_pwdseries
459        self.browser.getControl(name="ac_number").value = existing_pwdnumber
460        self.browser.getControl(name="reg_number").value = '123456'
461        self.browser.getControl("Show").click()
462        self.assertMatches(
463            '...You are using the wrong Access Code...',
464            self.browser.contents)
465        # The student can login with the new credentials
466        self.browser.open(self.login_path)
467        self.browser.getControl(name="form.login").value = test_student_id
468        self.browser.getControl(
469            name="form.password").value = self.existing_pwdnumber
470        self.browser.getControl("Login").click()
471        self.assertEqual(self.browser.url, student_path)
472        self.assertTrue('You logged in' in self.browser.contents)
473        return
474
475    def test_student_access(self):
476        # Students can access their own objects
477        # and can perform actions
478        student = self.app['students'][self.test_student_id]
479        IWorkflowInfo(student).fireTransition('admit')
480        self.browser.open(self.login_path)
481        self.browser.getControl(name="form.login").value = self.test_student_id
482        self.browser.getControl(name="form.password").value = 'spwd'
483        self.browser.getControl("Login").click()
484        # Student can view the clearance data
485        self.browser.getLink("Clearance Data").click()
486        # Student can't open clearance edit form before starting clearance
487        self.browser.open(self.student_path + '/cedit')
488        self.assertMatches('...The requested form is locked...',
489                           self.browser.contents)
490        self.browser.getLink("Clearance Data").click()
491        self.browser.getLink("Start clearance").click()
492        self.browser.getControl(name="ac_series").value = self.existing_clrseries
493        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
494        self.browser.getControl("Start clearance now").click()
495        self.assertMatches('...Clearance process has been started...',
496                           self.browser.contents)
497        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
498        self.browser.getControl("Save", index=0).click()
499        # Student can view the clearance data
500        self.browser.getLink("Clearance Data").click()
501        # and go back to the edit form
502        self.browser.getLink("Edit").click()
503        self.browser.getControl("Save and request clearance").click()
504        self.browser.getControl(name="ac_series").value = self.existing_clrseries
505        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
506        self.browser.getControl("Request clearance now").click()
507        self.assertMatches('...Clearance has been requested...',
508                           self.browser.contents)
509        # Student can't reopen clearance form after requesting clearance
510        self.browser.open(self.student_path + '/cedit')
511        self.assertMatches('...The requested form is locked...',
512                           self.browser.contents)
513        IWorkflowInfo(student).fireTransition('clear')
514        IWorkflowInfo(student).fireTransition('pay_first_school_fee')
515        # Students can add the current study level
516        self.browser.getLink("Study Course").click()
517        self.browser.getLink("Add course list").click()
518        self.assertMatches('...Add current level 100 (Year 1)...',
519                           self.browser.contents)
520        self.browser.getControl("Create course list now").click()
521        self.browser.getLink("100").click()
522        self.browser.getLink("Add and remove courses").click()
523        self.browser.getControl("Add course ticket").click()
524        self.browser.getControl(name="form.course").value = ['COURSE1']
525        self.browser.getControl("Add course ticket").click()
526        self.assertMatches('...The ticket exists...',
527                           self.browser.contents)
528        self.student['studycourse'].current_level = 200
529        self.browser.getLink("Study Course").click()
530        self.browser.getLink("Add course list").click()
531        self.assertMatches('...Add current level 200 (Year 2)...',
532                           self.browser.contents)
533        self.browser.getControl("Create course list now").click()
534        self.browser.getLink("200").click()
535        self.browser.getLink("Add and remove courses").click()
536        self.browser.getControl("Add course ticket").click()
537        self.browser.getControl(name="form.course").value = ['COURSE1']
538        self.browser.getControl("Add course ticket").click()
539        self.assertMatches('...Successfully added COURSE1...',
540                           self.browser.contents)
541        ctrl = self.browser.getControl(name='val_id')
542        ctrl.getControl(value='COURSE1').selected = True
543        self.browser.getControl("Remove selected", index=0).click()
544        self.assertTrue('Successfully removed' in self.browser.contents)
545        self.browser.getControl("Register course list").click()
546        self.assertTrue('Course list has been registered' in self.browser.contents)
547        self.assertEqual(self.student.state, 'courses registered')
548        return
Note: See TracBrowser for help on using the repository browser.