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

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

Turn list of lists into single list with Uli's technique.

Do not log changes made by students. During clearance this would be too much.

  • Property svn:keywords set to Id
File size: 20.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 6771 2011-09-14 14:20:40Z 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        # Set password
78        IUserAccount(
79            self.app['students'][self.test_student_id]).setPassword('spwd')
80
81        self.login_path = 'http://localhost/app/login'
82        self.container_path = 'http://localhost/app/students'
83        self.manage_container_path = self.container_path + '/@@manage'
84        self.add_student_path = self.container_path + '/addstudent'
85        self.student_path = self.container_path + '/' + self.test_student_id
86        self.manage_student_path = self.student_path + '/edit_base'
87        self.clearance_student_path = self.student_path + '/view_clearance'
88        self.personal_student_path = self.student_path + '/view_personal'
89        self.edit_clearance_student_path = self.student_path + '/edit_clearance'
90        self.edit_personal_student_path = self.student_path + '/edit_personal'
91
92        self.studycourse_student_path = self.student_path + '/studycourse'
93        self.payments_student_path = self.student_path + '/payments'
94        self.accommodation_student_path = self.student_path + '/accommodation'
95        self.history_student_path = self.student_path + '/history'
96
97        # Create 5 access codes with prefix'PWD'
98        pin_container = self.app['accesscodes']
99        pin_container.createBatch(
100            datetime.now(), 'some_userid', 'PWD', 9.99, 5)
101        pins = pin_container[pin_container.keys()[0]].values()
102        self.pwdpins = [x.representation for x in pins]
103        self.existing_pwdpin = self.pwdpins[0]
104        parts = self.existing_pwdpin.split('-')[1:]
105        self.existing_pwdseries, self.existing_pwdnumber = parts
106        # Create 5 access codes with prefix 'CLR'
107        pin_container.createBatch(
108            datetime.now(), 'some_userid', 'CLR', 9.99, 5)
109        pins = pin_container[pin_container.keys()[0]].values()
110        self.clrpins = [x.representation for x in pins]
111        self.existing_clrpin = self.clrpins[0]
112        self.existing_clrpin
113        parts = self.existing_clrpin.split('-')[1:]
114        self.existing_clrseries, self.existing_clrnumber = parts
115
116        # Populate university
117        certificate = createObject('waeup.Certificate')
118        certificate.code = 'CERT1'
119        certificate.application_category = 'basic'
120        certificate.start_level = 100
121        certificate.end_level = 500
122        self.app['faculties']['fac1'] = Faculty()
123        self.app['faculties']['fac1']['dep1'] = Department()
124        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
125            certificate)
126
127        # Put the prepopulated site into test ZODB and prepare test
128        # browser
129        self.browser = Browser()
130        self.browser.handleErrors = False
131
132    def tearDown(self):
133        super(StudentsFullSetup, self).tearDown()
134        clearSite()
135        shutil.rmtree(self.dc_root)
136
137
138
139class StudentsContainerUITests(StudentsFullSetup):
140    # Tests for StudentsContainer class views and pages
141
142    layer = FunctionalLayer
143
144    def test_anonymous_access(self):
145        # Anonymous users can't access students containers
146        self.assertRaises(
147            Unauthorized, self.browser.open, self.container_path)
148        self.assertRaises(
149            Unauthorized, self.browser.open, self.manage_container_path)
150        return
151
152    def test_manage_access(self):
153        # Managers can access the view page of students
154        # containers and can perform actions
155        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
156        self.browser.open(self.container_path)
157        self.assertEqual(self.browser.headers['Status'], '200 Ok')
158        self.assertEqual(self.browser.url, self.container_path)
159        self.browser.getLink("Manage student section").click()
160        self.assertEqual(self.browser.headers['Status'], '200 Ok')
161        self.assertEqual(self.browser.url, self.manage_container_path)
162        return
163
164    def test_add_search_delete_students(self):
165        # Managers can add search and remove students
166        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
167        self.browser.open(self.manage_container_path)
168        self.browser.getLink("Add student").click()
169        self.assertEqual(self.browser.headers['Status'], '200 Ok')
170        self.assertEqual(self.browser.url, self.add_student_path)
171        self.browser.getControl(name="form.name").value = 'Bob Tester'
172        self.browser.getControl("Create student record").click()
173        self.assertTrue('Student record created' in self.browser.contents)
174
175        # Registration numbers must be unique
176        self.browser.getLink("Manage").click()
177        self.browser.getControl(name="form.reg_number").value = '123'
178        self.browser.getControl("Save").click()
179        self.assertMatches('...value already exists in catalog...',
180                           self.browser.contents)
181
182        self.browser.open(self.container_path)
183        self.browser.getControl("Search").click()
184        self.assertTrue('Empty search string' in self.browser.contents)
185        self.browser.getControl(name="searchtype").value = ['student_id']
186        self.browser.getControl(name="searchterm").value = self.test_student_id
187        self.browser.getControl("Search").click()
188        self.assertTrue('Anna Tester' in self.browser.contents)
189
190        self.browser.open(self.manage_container_path)
191        self.browser.getControl("Search").click()
192        self.assertTrue('Empty search string' in self.browser.contents)
193        self.browser.getControl(name="searchtype").value = ['name']
194        self.browser.getControl(name="searchterm").value = 'Anna Tester'
195        self.browser.getControl("Search").click()
196        self.assertTrue('Anna Tester' in self.browser.contents)
197        # The old searchterm will be used again
198        self.browser.getControl("Search").click()
199        self.assertTrue('Anna Tester' in self.browser.contents)
200
201        ctrl = self.browser.getControl(name='entries')
202        ctrl.getControl(value=self.test_student_id).selected = True
203        self.browser.getControl("Remove selected", index=0).click()
204        self.assertTrue('Successfully removed' in self.browser.contents)
205        self.browser.getControl(name="searchtype").value = ['student_id']
206        self.browser.getControl(name="searchterm").value = self.test_student_id
207        self.browser.getControl("Search").click()
208        self.assertTrue('No student found' in self.browser.contents)
209
210        self.browser.open(self.container_path)
211        self.browser.getControl(name="searchtype").value = ['student_id']
212        self.browser.getControl(name="searchterm").value = self.test_student_id
213        self.browser.getControl("Search").click()
214        self.assertTrue('No student found' in self.browser.contents)
215
216class StudentUITests(StudentsFullSetup):
217    # Tests for Student class views and pages
218
219    layer = FunctionalLayer
220
221    def test_manage_access(self):
222        # Managers can access the pages of students
223        # and can perform actions
224        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
225
226        self.browser.open(self.student_path)
227        self.assertEqual(self.browser.headers['Status'], '200 Ok')
228        self.assertEqual(self.browser.url, self.student_path)
229        self.browser.getLink("Manage").click()
230        self.assertEqual(self.browser.headers['Status'], '200 Ok')
231        self.assertEqual(self.browser.url, self.manage_student_path)
232        # Managers can edit base data and fire transitions
233        self.browser.getControl(name="transition").value = ['admit']
234        self.browser.getControl(name="form.name").value = 'John Tester'
235        self.browser.getControl(name="form.reg_number").value = '123'
236        self.browser.getControl(name="password").value = 'secret'
237        self.browser.getControl(name="control_password").value = 'secret'
238        self.browser.getControl("Save").click()
239        self.assertMatches('...Form has been saved...',
240                           self.browser.contents)
241        self.browser.open(self.student_path)
242        self.browser.getLink("Clearance Data").click()
243        self.assertEqual(self.browser.headers['Status'], '200 Ok')
244        self.assertEqual(self.browser.url, self.clearance_student_path)
245        self.browser.getLink("Manage").click()
246        self.assertEqual(self.browser.headers['Status'], '200 Ok')
247        self.assertEqual(self.browser.url, self.edit_clearance_student_path)
248        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
249        self.browser.getControl("Save").click()
250        self.assertMatches('...Form has been saved...',
251                           self.browser.contents)
252
253        self.browser.open(self.student_path)
254        self.browser.getLink("Personal Data").click()
255        self.assertEqual(self.browser.headers['Status'], '200 Ok')
256        self.assertEqual(self.browser.url, self.personal_student_path)
257        self.browser.getLink("Manage").click()
258        self.assertEqual(self.browser.headers['Status'], '200 Ok')
259        self.assertEqual(self.browser.url, self.edit_personal_student_path)
260        self.browser.getControl("Save").click()
261        self.assertMatches('...Form has been saved...',
262                           self.browser.contents)
263
264        self.browser.open(self.student_path)
265        self.browser.getLink("Study Course").click()
266        self.assertEqual(self.browser.headers['Status'], '200 Ok')
267        self.assertEqual(self.browser.url, self.studycourse_student_path)
268        self.browser.getLink("Manage").click()
269        self.assertTrue('Manage study course' in self.browser.contents)
270        # Before we can select a level, the certificate must be selected and saved
271        self.browser.getControl(name="form.certificate").value = ['CERT1']
272        self.browser.getControl(name="form.current_session").value = ['2004']
273        self.browser.getControl(name="form.current_verdict").value = ['A']
274        self.browser.getControl("Save").click()
275        # Now we can save also the current level which depends on start and end
276        # level of the certificate
277        self.browser.getControl(name="form.current_level").value = ['100']
278        self.browser.getControl("Save").click()
279
280        self.browser.open(self.student_path)
281        self.browser.getLink("Payments").click()
282        self.assertEqual(self.browser.headers['Status'], '200 Ok')
283        self.assertEqual(self.browser.url, self.payments_student_path)
284
285        self.browser.open(self.student_path)
286        self.browser.getLink("Accommodation").click()
287        self.assertEqual(self.browser.headers['Status'], '200 Ok')
288        self.assertEqual(self.browser.url, self.accommodation_student_path)
289
290        self.browser.open(self.student_path)
291        self.browser.getLink("History").click()
292        self.assertEqual(self.browser.headers['Status'], '200 Ok')
293        self.assertEqual(self.browser.url, self.history_student_path)
294        self.assertMatches('...Student admitted by zope.mgr...',
295                           self.browser.contents)
296
297        # Managers can pass through the whole workflow
298        student = self.app['students'][self.test_student_id]
299        self.browser.open(self.manage_student_path)
300        self.assertTrue(student.clearance_locked)
301        self.browser.getControl(name="transition").value = ['start_clearance']
302        self.browser.getControl("Save").click()
303        self.assertFalse(student.clearance_locked)
304        self.browser.getControl(name="transition").value = ['request_clearance']
305        self.browser.getControl("Save").click()
306        self.assertTrue(student.clearance_locked)
307        self.browser.getControl(name="transition").value = ['clear']
308        self.browser.getControl("Save").click()
309        self.browser.getControl(name="transition").value = ['pay_first_school_fee']
310        self.browser.getControl("Save").click()
311        self.browser.getControl(name="transition").value = ['reset6']
312        self.browser.getControl("Save").click()
313        # The pay_school_fee transition triggers some changes
314        self.browser.getControl(name="transition").value = ['pay_school_fee']
315        self.browser.getControl("Save").click()
316        self.assertEqual(student['studycourse'].current_session, 2005) # was 2004
317        self.assertEqual(student['studycourse'].current_level, 200) # was 100
318        self.assertEqual(student['studycourse'].current_verdict, '') # was 'A'
319        self.assertEqual(student['studycourse'].previous_verdict, 'A') # was empty
320        return
321
322    def test_student_change_password(self):
323        # Students can change the password
324        self.browser.open(self.login_path)
325        self.browser.getControl(name="form.login").value = self.test_student_id
326        self.browser.getControl(name="form.password").value = 'spwd'
327        self.browser.getControl("Login").click()
328        self.assertEqual(self.browser.url, self.student_path)
329        self.assertTrue('You logged in' in self.browser.contents)
330        # Change password
331        self.browser.getLink("Change password").click()
332        self.browser.getControl(name="form.password").value = 'new_password'
333        self.browser.getControl(
334            name="form.password_repeat").value = 'new_passssword'
335        self.browser.getControl("Save").click()
336        self.assertTrue('passwords do not match' in self.browser.contents)
337        self.browser.getControl(name="form.password").value = 'new_password'
338        self.browser.getControl(
339            name="form.password_repeat").value = 'new_password'
340        self.browser.getControl("Save").click()
341        self.assertTrue('Form has been saved' in self.browser.contents)
342        # We are still logged in. Changing the password hasn't thrown us out.
343        self.browser.getLink("My Data").click()
344        self.assertEqual(self.browser.url, self.student_path)
345        # We can logout
346        self.browser.getLink("Logout").click()
347        self.assertTrue('You have been logged out' in self.browser.contents)
348        self.assertEqual(self.browser.url, 'http://localhost/app')
349        # We can login again with the new password
350        self.browser.getLink("Login").click()
351        self.browser.open(self.login_path)
352        self.browser.getControl(name="form.login").value = self.test_student_id
353        self.browser.getControl(name="form.password").value = 'new_password'
354        self.browser.getControl("Login").click()
355        self.assertEqual(self.browser.url, self.student_path)
356        self.assertTrue('You logged in' in self.browser.contents)
357        return
358
359    def test_setpassword(self):
360        # Set password for first-time access
361        student = Student()
362        student.reg_number = u'123456'
363        student.name = u'Klaus Tester'
364        test_student_id = self.app['students'].addStudent(student)
365        setpassword_path = 'http://localhost/app/setpassword'
366        student_path = 'http://localhost/app/students/%s' % test_student_id
367        self.browser.open(setpassword_path)
368        self.browser.getControl(name="ac_series").value = self.existing_pwdseries
369        self.browser.getControl(name="ac_number").value = self.existing_pwdnumber
370        self.browser.getControl(name="reg_number").value = '123456'
371        self.browser.getControl("Show").click()
372        self.assertMatches('...Password has been set. Your Student Id is...',
373                           self.browser.contents)
374        # The student can login with the new credentials
375        self.browser.open(self.login_path)
376        self.browser.getControl(name="form.login").value = test_student_id
377        self.browser.getControl(
378            name="form.password").value = self.existing_pwdnumber
379        self.browser.getControl("Login").click()
380        self.assertEqual(self.browser.url, student_path)
381        self.assertTrue('You logged in' in self.browser.contents)
382        return
383
384    def test_student_access(self):
385        # Students can access their own objects
386        # and can perform actions
387        student = self.app['students'][self.test_student_id]
388        IWorkflowInfo(student).fireTransition('admit')
389        self.browser.open(self.login_path)
390        self.browser.getControl(name="form.login").value = self.test_student_id
391        self.browser.getControl(name="form.password").value = 'spwd'
392        self.browser.getControl("Login").click()
393        # Student can view the clearance data
394        self.browser.getLink("Clearance Data").click()
395        # Student can't open clearance edit form before starting clearance
396        self.browser.open(self.student_path + '/cedit')
397        self.assertMatches('...The requested form is locked...',
398                           self.browser.contents)
399        self.browser.getLink("Clearance Data").click()
400        self.browser.getLink("Start clearance").click()
401        self.browser.getControl(name="ac_series").value = self.existing_clrseries
402        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
403        self.browser.getControl("Start clearance now").click()
404        self.assertMatches('...Clearance process has been started...',
405                           self.browser.contents)
406        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
407        self.browser.getControl("Save", index=0).click()
408        # Student can view the clearance data
409        self.browser.getLink("Clearance Data").click()
410        # and go back to the edit form
411        self.browser.getLink("Edit").click()
412        self.browser.getControl("Save and request clearance").click()
413        self.browser.getControl(name="ac_series").value = self.existing_clrseries
414        self.browser.getControl(name="ac_number").value = self.existing_clrnumber
415        self.browser.getControl("Request clearance now").click()
416        self.assertMatches('...Clearance has been requested...',
417                           self.browser.contents)
418        # Student can't reopen clearance form after requesting clearance
419        self.browser.open(self.student_path + '/cedit')
420        self.assertMatches('...The requested form is locked...',
421                           self.browser.contents)
Note: See TracBrowser for help on using the repository browser.