source: main/kofacustom.nigeria/branches/0.1/src/kofacustom/nigeria/students/tests/test_browser.py @ 17356

Last change on this file since 17356 was 11054, checked in by Henrik Bettermann, 11 years ago

Test import of ResultEntryField? values.

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