source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/students/tests/test_browser.py @ 12417

Last change on this file since 12417 was 12417, checked in by Henrik Bettermann, 10 years ago

Add test which shows that ResultEntry? fields are always modified when saving a form. The problem has not yet been solved.

  • Property svn:keywords set to Id
File size: 16.3 KB
Line 
1## $Id: test_browser.py 12417 2015-01-08 07:59:46Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import os
19import shutil
20import tempfile
21from datetime import datetime, timedelta
22from StringIO import StringIO
23from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
24from zope.component.hooks import setSite, clearSite
25from zope.component import getUtility, createObject
26from zope.interface import verify
27from waeup.kofa.app import University
28from waeup.kofa.students.tests.test_browser import (
29    StudentsFullSetup, SAMPLE_IMAGE)
30from waeup.kofa.testing import FunctionalTestCase
31from waeup.kofa.interfaces import (
32    IExtFileStore, IFileStoreNameChooser)
33from waeup.kofa.schoolgrades import ResultEntry
34from waeup.kofa.students.batching import StudentProcessor
35from waeup.kofa.students.interfaces import IStudentsUtils
36from kofacustom.nigeria.students.batching import NigeriaStudentProcessor
37from kofacustom.nigeria.testing import FunctionalLayer
38from kofacustom.nigeria.utils.utils import NigeriaKofaUtils
39from kofacustom.nigeria.students.interfaces import (
40    INigeriaStudentStudyCourse, INigeriaStudent,
41    INigeriaStudentStudyLevel, INigeriaCourseTicket)
42
43
44STUDENT_SAMPLE_DATA = open(
45    os.path.join(os.path.dirname(__file__), 'sample_student_data.csv'),
46    'rb').read()
47
48STUDENT_HEADER_FIELDS = STUDENT_SAMPLE_DATA.split(
49    '\n')[0].split(',')
50
51class StudentProcessorTest(FunctionalTestCase):
52    """Perform some batching tests.
53    """
54
55    layer = FunctionalLayer
56
57    def setUp(self):
58        super(StudentProcessorTest, self).setUp()
59        # Setup a sample site for each test
60        app = University()
61        self.dc_root = tempfile.mkdtemp()
62        app['datacenter'].setStoragePath(self.dc_root)
63
64        # Prepopulate the ZODB...
65        self.getRootFolder()['app'] = app
66        # we add the site immediately after creation to the
67        # ZODB. Catalogs and other local utilities are not setup
68        # before that step.
69        self.app = self.getRootFolder()['app']
70        # Set site here. Some of the following setup code might need
71        # to access grok.getSite() and should get our new app then
72        setSite(app)
73
74        self.processor_base = StudentProcessor()
75        self.processor = NigeriaStudentProcessor()
76        self.workdir = tempfile.mkdtemp()
77        self.csv_file = os.path.join(self.workdir, 'sample_student_data.csv')
78        open(self.csv_file, 'wb').write(STUDENT_SAMPLE_DATA)
79
80    def tearDown(self):
81        super(StudentProcessorTest, self).tearDown()
82        shutil.rmtree(self.workdir)
83        shutil.rmtree(self.dc_root)
84        clearSite()
85        return
86
87    def test_import(self):
88        # We have an empty column 'date_of_birth' in  the import file.
89        # The original processor will fail because 'date_of_birth' is required
90        # in the base package.
91        num, num_warns, fin_file, fail_file = self.processor_base.doImport(
92            self.csv_file, STUDENT_HEADER_FIELDS)
93        self.assertEqual(num_warns,3)
94        assert len(self.app['students'].keys()) == 0
95        # The customized processor does not complain since 'date_of_birth' is
96        # not required in the custom package.
97        num, num_warns, fin_file, fail_file = self.processor.doImport(
98            self.csv_file, STUDENT_HEADER_FIELDS)
99        #print open(fail_file).read()
100        self.assertEqual(num_warns,0)
101        assert len(self.app['students'].keys()) == 3
102        # Also fst_sit_results have been properly imported (tested only here!)
103        self.assertEqual(
104            self.app['students']['K1000000'].fst_sit_results[0].__dict__,
105            {'grade': 'A1', 'subject': 'visual_art'})
106        self.assertEqual(
107            self.app['students']['K1000000'].fst_sit_results[1].__dict__,
108            {'grade': 'C6', 'subject': 'applied_electricity'})
109        shutil.rmtree(os.path.dirname(fin_file))
110
111
112class StudentUITests(StudentsFullSetup):
113    """Tests for customized student class views and pages
114    """
115
116    layer = FunctionalLayer
117
118    def setUp(self):
119        super(StudentUITests, self).setUp()
120
121    def test_classes(self):
122        # Let's see if objects created in the customized
123        # portal really implement the customized interfaces
124        verify.verifyObject(INigeriaStudent, self.student)
125        verify.verifyObject(
126            INigeriaStudentStudyCourse, self.student['studycourse'])
127        studylevel = createObject(u'waeup.StudentStudyLevel')
128        verify.verifyObject(INigeriaStudentStudyLevel, studylevel)
129        ticket = createObject(u'waeup.CourseTicket')
130        verify.verifyObject(INigeriaCourseTicket, ticket)
131        IWorkflowState(self.student).setState('returning')
132        # Let's see if next_session_allowed works as expected
133        # A, ug_ft, 100
134        self.assertTrue(self.student['studycourse'].next_session_allowed)
135        # Zero, ug_ft, 100
136        self.student['studycourse'].current_verdict = '0' # Zero!
137        self.assertTrue(self.student['studycourse'].next_session_allowed)
138        # Zero, ug_ft, 200
139        self.student['studycourse'].current_level = 200
140        self.assertFalse(self.student['studycourse'].next_session_allowed)
141        # Zero, de_ft, 200
142        self.student['studycourse'].certificate.study_mode = 'de_ft'
143        self.assertTrue(self.student['studycourse'].next_session_allowed)
144        # Zero, ph_ft, 300
145        self.student['studycourse'].certificate.study_mode = 'ph_ft'
146        self.student['studycourse'].current_level = 300
147        self.assertTrue(self.student['studycourse'].next_session_allowed)
148        # Zero, ph_ft, 400
149        self.student['studycourse'].current_level = 400
150        self.assertFalse(self.student['studycourse'].next_session_allowed)
151
152        # Now we convert the certificate into a postgraduate certificate
153        IWorkflowState(self.student).setState('school fee paid')
154        self.certificate.study_mode = 'pg_ft'
155        # ... and voila next session registration is allowed
156        self.assertTrue(self.student['studycourse'].next_session_allowed)
157
158    def test_manage_access(self):
159        self.student.nationality = u'DE'
160        # Managers can access the pages of students
161        # and can perform actions
162        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
163        # The student created in the base package is an ug student
164        self.browser.open(self.student_path)
165        self.browser.getLink("Clearance Data").click()
166        self.assertEqual(self.browser.headers['Status'], '200 Ok')
167        self.assertEqual(self.browser.url, self.clearance_path)
168        self.browser.getLink("Manage").click()
169        self.assertEqual(self.browser.headers['Status'], '200 Ok')
170        self.assertEqual(self.browser.url, self.manage_clearance_path)
171        self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
172        self.browser.getControl("Save").click()
173        self.assertMatches('...Form has been saved...',
174                           self.browser.contents)
175        self.assertMatches('...First Sitting Record...',
176                           self.browser.contents)
177        # Managers can open clearance slip of ug students
178        self.browser.open(self.student_path + '/clearance_slip.pdf')
179        self.assertEqual(self.browser.headers['Status'], '200 Ok')
180        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
181        # There is no pg field in the clearance form
182        self.assertFalse('Second Higher Education Record'
183            in self.browser.contents)
184        # Now we change the study mode ...
185        self.certificate.study_mode = 'pg_ft'
186        self.browser.open(self.clearance_path)
187        # ... and additional pg clearance fields appear
188        self.assertMatches('...Second Higher Education Record...',
189                           self.browser.contents)
190        # But also fields from the ug form are displayed
191        self.assertMatches('...First Sitting Record...',
192                           self.browser.contents)
193        # Managers can open clearance slip of pg students
194        self.browser.open(self.student_path + '/clearance_slip.pdf')
195        self.assertEqual(self.browser.headers['Status'], '200 Ok')
196        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
197        # Managers can edit personal data. No fields are required.
198        self.browser.open(self.manage_personal_path)
199        self.browser.getControl("Save").click()
200        self.assertMatches('...Form has been saved...',
201                           self.browser.contents)
202
203    def test_logging(self):
204        self.student.nationality = u'DE'
205        valid_subj = NigeriaKofaUtils().EXAM_SUBJECTS_DICT.keys()[0]
206        valid_grade = NigeriaKofaUtils().EXAM_GRADES[0][0]
207        result_entry = ResultEntry(valid_subj, valid_grade)
208        self.student.fst_sit_results = [result_entry,]
209        # Managers can access the pages of students
210        # and can perform actions
211        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
212        # The student created in the base package is an ug student
213        self.browser.open(self.student_path)
214        self.browser.getLink("Clearance Data").click()
215        self.browser.getLink("Manage").click()
216        self.browser.getControl("Save").click()
217        logfile = os.path.join(
218            self.app['datacenter'].storage, 'logs', 'students.log')
219        logcontent = open(logfile).read()
220        self.assertFalse('saved: fst_sit_results' in logcontent)
221
222    def test_student_access(self):
223        # Students can edit clearance data
224        IWorkflowState(self.student).setState('cleared')
225        self.browser.open(self.login_path)
226        self.browser.getControl(name="form.login").value = self.student_id
227        self.browser.getControl(name="form.password").value = 'spwd'
228        self.browser.getControl("Login").click()
229        # Even in state admitted students can't change the portait if
230        # application slip exists.
231        IWorkflowState(self.student).setState('admitted')
232        self.browser.open(self.student_path)
233        self.assertTrue('Change portrait' in self.browser.contents)
234        file_store = getUtility(IExtFileStore)
235        applicant_slip = 'My application slip'
236        file_id = IFileStoreNameChooser(self.student).chooseName(
237            attr="application_slip.pdf")
238        file_store.createFile(file_id, StringIO(applicant_slip))
239        self.browser.open(self.student_path)
240        self.assertFalse('Change portrait' in self.browser.contents)
241        self.browser.open(self.student_path + '/change_portrait')
242        self.assertTrue('The requested form is locked' in self.browser.contents)
243
244        # Student can view and edit clearance data if clearance has started ...
245        IWorkflowInfo(self.student).fireTransition('start_clearance')
246        self.student.officer_comment = u'Fill properly'
247        self.browser.getLink("Clearance Data").click()
248        self.assertTrue("Officer's Comment" in self.browser.contents)
249        # Students can't edit officer's comment
250        self.browser.getLink("Edit").click()
251        self.assertFalse("Officer's Comment" in self.browser.contents)
252        self.assertTrue('Save' in self.browser.contents)
253        # ... and request clearance if nationality field has been filled.
254        self.browser.getControl("Save and request clearance").click()
255        self.assertMatches('...Required input is missing...',
256                           self.browser.contents)
257        self.student.nationality = u'DE'
258        self.browser.open(self.edit_clearance_path)
259        self.browser.getControl("Save and request clearance").click()
260        self.assertMatches('...Clearance has been requested...',
261                           self.browser.contents)
262
263        # Students can edit personal data. Some fields are required.
264        self.browser.open(self.personal_path)
265        self.assertTrue('Updated' in self.browser.contents)
266        self.browser.getLink("Edit").click()
267        self.assertEqual(self.browser.headers['Status'], '200 Ok')
268        self.assertEqual(self.browser.url, self.edit_personal_path)
269        self.browser.getControl("Save").click()
270        self.assertMatches('...Required input is missing...',
271                           self.browser.contents)
272        self.browser.getControl(name="form.perm_address").value = 'My address!'
273        self.browser.getControl("Save").click()
274        self.assertMatches('...Required input is missing...',
275                           self.browser.contents)
276        # Ok, let's give up and fill the rest.
277        self.browser.getControl(name="form.next_kin_name").value = 'My Mutti'
278        self.browser.getControl(name="form.next_kin_relation").value = 'mother'
279        self.browser.getControl(name="form.next_kin_address").value = 'sweet home'
280        self.browser.getControl(name="form.next_kin_phone.country").value = ['+234']
281        self.browser.getControl(name="form.next_kin_phone.ext").value = '45678'
282        self.browser.getControl("Save").click()
283        self.assertMatches('...Form has been saved...',
284                           self.browser.contents)
285
286    def test_manage_upload_file(self):
287        # Managers can upload a file via the StudentClearanceManageFormPage
288        # The image is stored even if form has errors
289        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
290        self.browser.open(self.manage_clearance_path)
291        # Managers can add and delete a file
292        self.browser.open(self.manage_clearance_path)
293        image = open(SAMPLE_IMAGE, 'rb')
294        ctrl = self.browser.getControl(name='birthcertificateupload')
295        file_ctrl = ctrl.mech_control
296        file_ctrl.add_file(image, filename='my_acceptance_letter.jpg')
297        self.browser.getControl(
298            name='upload_acceptanceletterupload').click()
299        # Uups, we used the wrong 'Browse' field
300        self.assertFalse(
301            '<a target="image" href="acc_let">'
302            in self.browser.contents)
303        ctrl = self.browser.getControl(name='acceptanceletterupload')
304        file_ctrl = ctrl.mech_control
305        image.seek(0)
306        file_ctrl.add_file(image, filename='my_acceptance_letter.jpg')
307        self.browser.getControl(
308            name='upload_acceptanceletterupload').click()
309        self.assertTrue(
310            'http://localhost/app/students/K1000000/acc_let'
311            in self.browser.contents)
312        self.browser.getControl(
313            name='delete_acceptanceletterupload').click()
314        self.assertTrue(
315            'acc_let deleted'
316            in self.browser.contents)
317
318    def test_student_expired_personal_data(self):
319        # Login
320        IWorkflowState(self.student).setState('school fee paid')
321        delta = timedelta(days=180)
322        self.student.personal_updated = datetime.utcnow() - delta
323        self.browser.open(self.login_path)
324        self.browser.getControl(name="form.login").value = self.student_id
325        self.browser.getControl(name="form.password").value = 'spwd'
326        self.browser.getControl("Login").click()
327        self.assertEqual(self.browser.url, self.student_path)
328        self.assertTrue(
329            'You logged in' in self.browser.contents)
330        # Students don't see personal_updated field in edit form
331        self.browser.open(self.edit_personal_path)
332        self.assertFalse('Updated' in self.browser.contents)
333        self.browser.open(self.personal_path)
334        self.assertTrue('Updated' in self.browser.contents)
335        self.browser.getLink("Logout").click()
336        delta = timedelta(days=181)
337        self.student.personal_updated = datetime.utcnow() - delta
338        self.browser.open(self.login_path)
339        self.browser.getControl(name="form.login").value = self.student_id
340        self.browser.getControl(name="form.password").value = 'spwd'
341        self.browser.getControl("Login").click()
342        self.assertEqual(self.browser.url, self.edit_personal_path)
343        self.assertTrue(
344            'Your personal data record is outdated.' in self.browser.contents)
Note: See TracBrowser for help on using the repository browser.