source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_browser.py @ 12062

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

Add PDFDocumentSlipPage and related components.

  • Property svn:keywords set to Id
File size: 51.3 KB
Line 
1## $Id: test_browser.py 12062 2014-11-26 13:03:56Z henrik $
2##
3## Copyright (C) 2014 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##
18"""
19Test the customer-related UI components.
20"""
21import shutil
22import tempfile
23import pytz
24import base64
25from datetime import datetime, timedelta, date
26from StringIO import StringIO
27import os
28import grok
29from zc.async.testing import wait_for_result
30from zope.event import notify
31from zope.component import createObject, queryUtility, getUtility
32from zope.component.hooks import setSite, clearSite
33from zope.catalog.interfaces import ICatalog
34from zope.security.interfaces import Unauthorized
35from zope.securitypolicy.interfaces import IPrincipalRoleManager
36from zope.testbrowser.testing import Browser
37from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
38from waeup.ikoba.testing import FunctionalLayer, FunctionalTestCase
39from waeup.ikoba.app import Company
40from waeup.ikoba.customers.interfaces import ICustomersUtils
41from waeup.ikoba.customers.customer import Customer
42from waeup.ikoba.interfaces import IUserAccount, IJobManager, APPROVED
43from waeup.ikoba.authentication import LocalRoleSetEvent
44from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase
45from waeup.ikoba.documents.workflow import VERIFIED
46from waeup.ikoba.browser.tests.test_pdf import samples_dir
47
48PH_LEN = 15911  # Length of placeholder file
49
50SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
51SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
52SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf')
53
54def lookup_submit_value(name, value, browser):
55    """Find a button with a certain value."""
56    for num in range(0, 100):
57        try:
58            button = browser.getControl(name=name, index=num)
59            if button.value.endswith(value):
60                return button
61        except IndexError:
62            break
63    return None
64
65class CustomersFullSetup(FunctionalTestCase):
66    # A test case that only contains a setup and teardown
67    #
68    # Complete setup for customers handlings is rather complex and
69    # requires lots of things created before we can start. This is a
70    # setup that does all this, creates a university, creates PINs,
71    # etc.  so that we do not have to bother with that in different
72    # test cases.
73
74    layer = FunctionalLayer
75
76    def setUp(self):
77        super(CustomersFullSetup, self).setUp()
78
79        # Setup a sample site for each test
80        app = Company()
81        self.dc_root = tempfile.mkdtemp()
82        app['datacenter'].setStoragePath(self.dc_root)
83
84        # Prepopulate the ZODB...
85        self.getRootFolder()['app'] = app
86        # we add the site immediately after creation to the
87        # ZODB. Catalogs and other local utilities are not setup
88        # before that step.
89        self.app = self.getRootFolder()['app']
90        # Set site here. Some of the following setup code might need
91        # to access grok.getSite() and should get our new app then
92        setSite(app)
93
94        # Add customer with subobjects
95        customer = createObject('waeup.Customer')
96        customer.firstname = u'Anna'
97        customer.lastname = u'Tester'
98        customer.reg_number = u'123'
99        customer.sex = u'm'
100        customer.email = 'aa@aa.ng'
101        customer.phone = u'1234'
102        customer.date_of_birth = date(1981, 2, 4)
103        self.app['customers'].addCustomer(customer)
104        self.customer_id = customer.customer_id
105        self.customer = self.app['customers'][self.customer_id]
106        document = createObject('waeup.CustomerSampleDocument')
107        document.title = u'My first document'
108        self.customer['documents'].addDocument(document)
109
110        # Set password
111        IUserAccount(
112            self.app['customers'][self.customer_id]).setPassword('cpwd')
113
114        self.login_path = 'http://localhost/app/login'
115        self.container_path = 'http://localhost/app/customers'
116        self.manage_container_path = self.container_path + '/@@manage'
117        self.add_customer_path = self.container_path + '/addcustomer'
118        self.customer_path = self.container_path + '/' + self.customer_id
119        self.manage_customer_path = self.customer_path + '/manage_base'
120        self.trigtrans_path = self.customer_path + '/trigtrans'
121        self.history_path = self.customer_path + '/history'
122        self.documents_path = self.customer_path + '/documents'
123
124        self.app['configuration'].carry_over = True
125        configuration = createObject('waeup.SessionConfiguration')
126        self.app['configuration'].addSessionConfiguration(configuration)
127
128        # Update the catalog
129        notify(grok.ObjectModifiedEvent(self.customer))
130
131        # Put the prepopulated site into test ZODB and prepare test
132        # browser
133        self.browser = Browser()
134        self.browser.handleErrors = False
135
136    def tearDown(self):
137        super(CustomersFullSetup, self).tearDown()
138        clearSite()
139        shutil.rmtree(self.dc_root)
140
141
142
143class CustomersContainerUITests(CustomersFullSetup):
144    # Tests for CustomersContainer class views and pages
145
146    layer = FunctionalLayer
147
148    def test_anonymous_access(self):
149        # Anonymous users can't access customers containers
150        self.assertRaises(
151            Unauthorized, self.browser.open, self.container_path)
152        self.assertRaises(
153            Unauthorized, self.browser.open, self.manage_container_path)
154        return
155
156    def test_manage_access(self):
157        # Managers can access the view page of customers
158        # containers and can perform actions
159        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
160        self.browser.open(self.container_path)
161        self.assertEqual(self.browser.headers['Status'], '200 Ok')
162        self.assertEqual(self.browser.url, self.container_path)
163        self.browser.getLink("Manage customer section").click()
164        self.assertEqual(self.browser.headers['Status'], '200 Ok')
165        self.assertEqual(self.browser.url, self.manage_container_path)
166        return
167
168    def test_add_search_delete_customers(self):
169        # Managers can add search and remove customers
170        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
171        self.browser.open(self.manage_container_path)
172        self.browser.getLink("Add customer").click()
173        self.assertEqual(self.browser.headers['Status'], '200 Ok')
174        self.assertEqual(self.browser.url, self.add_customer_path)
175        self.browser.getControl(name="form.firstname").value = 'Bob'
176        self.browser.getControl(name="form.lastname").value = 'Tester'
177        self.browser.getControl(name="form.reg_number").value = '123'
178        self.browser.getControl("Create customer record").click()
179        self.assertTrue('Registration number exists already'
180            in self.browser.contents)
181        self.browser.getControl(name="form.reg_number").value = '1234'
182        self.browser.getControl("Create customer record").click()
183        self.assertTrue('Customer record created' in self.browser.contents)
184
185        # Registration must be unique
186        self.browser.getLink("Manage").click()
187        self.browser.getControl(name="form.reg_number").value = '123'
188        self.browser.getControl("Save").click()
189        self.assertMatches('...Registration number exists...',
190                           self.browser.contents)
191
192        # We can find a customer with a certain customer_id
193        self.browser.open(self.container_path)
194        self.browser.getControl("Find customer(s)").click()
195        self.assertTrue('Empty search string' in self.browser.contents)
196        self.browser.getControl(name="searchtype").value = ['customer_id']
197        self.browser.getControl(name="searchterm").value = self.customer_id
198        self.browser.getControl("Find customer(s)").click()
199        self.assertTrue('Anna Tester' in self.browser.contents)
200
201        # We can find a customer by searching for all kind of name parts
202        self.browser.open(self.manage_container_path)
203        self.browser.getControl("Find customer(s)").click()
204        self.assertTrue('Empty search string' in self.browser.contents)
205        self.browser.getControl(name="searchtype").value = ['fullname']
206        self.browser.getControl(name="searchterm").value = 'Anna Tester'
207        self.browser.getControl("Find customer(s)").click()
208        self.assertTrue('Anna Tester' in self.browser.contents)
209        self.browser.open(self.manage_container_path)
210        self.browser.getControl(name="searchtype").value = ['fullname']
211        self.browser.getControl(name="searchterm").value = 'Anna'
212        self.browser.getControl("Find customer(s)").click()
213        self.assertTrue('Anna Tester' in self.browser.contents)
214        self.browser.open(self.manage_container_path)
215        self.browser.getControl(name="searchtype").value = ['fullname']
216        self.browser.getControl(name="searchterm").value = 'Tester'
217        self.browser.getControl("Find customer(s)").click()
218        self.assertTrue('Anna Tester' in self.browser.contents)
219        self.browser.open(self.manage_container_path)
220        self.browser.getControl(name="searchtype").value = ['fullname']
221        self.browser.getControl(name="searchterm").value = 'An'
222        self.browser.getControl("Find customer(s)").click()
223        self.assertFalse('Anna Tester' in self.browser.contents)
224        self.browser.open(self.manage_container_path)
225        self.browser.getControl(name="searchtype").value = ['fullname']
226        self.browser.getControl(name="searchterm").value = 'An*'
227        self.browser.getControl("Find customer(s)").click()
228        self.assertTrue('Anna Tester' in self.browser.contents)
229        self.browser.open(self.manage_container_path)
230        self.browser.getControl(name="searchtype").value = ['fullname']
231        self.browser.getControl(name="searchterm").value = 'tester'
232        self.browser.getControl("Find customer(s)").click()
233        self.assertTrue('Anna Tester' in self.browser.contents)
234        self.browser.open(self.manage_container_path)
235        self.browser.getControl(name="searchtype").value = ['fullname']
236        self.browser.getControl(name="searchterm").value = 'Tester Ana'
237        self.browser.getControl("Find customer(s)").click()
238        self.assertFalse('Anna Tester' in self.browser.contents)
239        self.browser.open(self.manage_container_path)
240        self.browser.getControl(name="searchtype").value = ['fullname']
241        self.browser.getControl(name="searchterm").value = 'Tester Anna'
242        self.browser.getControl("Find customer(s)").click()
243        self.assertTrue('Anna Tester' in self.browser.contents)
244        # The old searchterm will be used again
245        self.browser.getControl("Find customer(s)").click()
246        self.assertTrue('Anna Tester' in self.browser.contents)
247
248        # We can find suspended customers
249        self.customer.suspended = True
250        notify(grok.ObjectModifiedEvent(self.customer))
251        self.browser.open(self.manage_container_path)
252        self.browser.getControl(name="searchtype").value = ['suspended']
253        self.browser.getControl("Find customer(s)").click()
254        self.assertTrue('Anna Tester' in self.browser.contents)
255
256        # Removed customers won't be found
257        ctrl = self.browser.getControl(name='entries')
258        ctrl.getControl(value=self.customer_id).selected = True
259        self.browser.getControl("Remove selected", index=0).click()
260        self.assertTrue('Successfully removed' in self.browser.contents)
261        self.browser.getControl(name="searchtype").value = ['customer_id']
262        self.browser.getControl(name="searchterm").value = self.customer_id
263        self.browser.getControl("Find customer(s)").click()
264        self.assertTrue('No customer found' in self.browser.contents)
265        return
266
267class OfficerUITests(CustomersFullSetup):
268    # Tests for Customer class views and pages
269
270    def test_basic_auth(self):
271        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
272        self.browser.open('http://localhost/app')
273        self.browser.getLink("Logout").click()
274        self.assertTrue('You have been logged out' in self.browser.contents)
275        # But we are still logged in since we've used basic authentication here.
276        # Wikipedia says: Existing browsers retain authentication information
277        # until the tab or browser is closed or the user clears the history.
278        # HTTP does not provide a method for a server to direct clients to
279        # discard these cached credentials. This means that there is no
280        # effective way for a server to "log out" the user without closing
281        # the browser. This is a significant defect that requires browser
282        # manufacturers to support a "logout" user interface element ...
283        self.assertTrue('Manager' in self.browser.contents)
284
285    def test_basic_auth_base64(self):
286        auth_token = base64.b64encode('mgr:mgrpw')
287        self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
288        self.browser.open(self.manage_container_path)
289        self.assertEqual(self.browser.headers['Status'], '200 Ok')
290
291    def test_manage_access(self):
292        # Managers can access the pages of customers
293        # and can perform actions
294        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
295        self.browser.open(self.customer_path)
296        self.assertEqual(self.browser.headers['Status'], '200 Ok')
297        self.assertEqual(self.browser.url, self.customer_path)
298        self.browser.getLink("Transition").click()
299        self.assertEqual(self.browser.headers['Status'], '200 Ok')
300        # Managers can trigger transitions
301        self.browser.getControl(name="transition").value = ['start']
302        self.browser.getControl("Save").click()
303        # Managers can edit base
304        self.browser.open(self.customer_path)
305        self.browser.getLink("Manage").click()
306        self.assertEqual(self.browser.url, self.manage_customer_path)
307        self.assertEqual(self.browser.headers['Status'], '200 Ok')
308        self.browser.getControl(name="form.firstname").value = 'John'
309        self.browser.getControl(name="form.lastname").value = 'Tester'
310        self.browser.getControl(name="form.reg_number").value = '345'
311        self.browser.getControl(name="password").value = 'secret'
312        self.browser.getControl(name="control_password").value = 'secret'
313        self.browser.getControl("Save").click()
314        self.assertMatches('...Form has been saved...',
315                           self.browser.contents)
316
317    def test_manage_contact_customer(self):
318        # Managers can contact customer
319        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
320        self.customer.email = None
321        self.browser.open(self.customer_path)
322        self.browser.getLink("Send email").click()
323        self.browser.getControl(name="form.subject").value = 'Important subject'
324        self.browser.getControl(name="form.body").value = 'Hello!'
325        self.browser.getControl("Send message now").click()
326        self.assertTrue('An smtp server error occurred' in self.browser.contents)
327        self.customer.email = 'xx@yy.zz'
328        self.browser.getControl("Send message now").click()
329        self.assertTrue('Your message has been sent' in self.browser.contents)
330        return
331
332    def test_manage_upload_passport(self):
333        # Managers can upload a file via the CustomerBaseManageFormPage
334        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
335        self.browser.open(self.manage_customer_path)
336        image = open(SAMPLE_IMAGE_BMP, 'rb')
337        ctrl = self.browser.getControl(name='passportmanageupload')
338        file_ctrl = ctrl.mech_control
339        file_ctrl.add_file(image, filename='my_photo.bmp')
340        self.browser.getControl(
341            name='upload_passportmanageupload').click()
342        self.assertTrue('jpg file extension expected'
343            in self.browser.contents)
344        ctrl = self.browser.getControl(name='passportmanageupload')
345        file_ctrl = ctrl.mech_control
346        image = open(SAMPLE_IMAGE, 'rb')
347        file_ctrl.add_file(image, filename='my_photo.jpg')
348        self.browser.getControl(
349            name='upload_passportmanageupload').click()
350        self.assertTrue(
351            'src="http://localhost/app/customers/K1000000/passport.jpg"'
352            in self.browser.contents)
353        # We remove the passport file again
354        self.browser.open(self.manage_customer_path)
355        self.browser.getControl('Delete').click()
356        self.assertTrue('passport.jpg deleted' in self.browser.contents)
357
358
359    def test_manage_workflow(self):
360        # Managers can pass through the whole workflow
361        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
362        customer = self.app['customers'][self.customer_id]
363        self.browser.open(self.trigtrans_path)
364        self.browser.getControl(name="transition").value = ['start']
365        self.browser.getControl("Save").click()
366        self.browser.getControl(name="transition").value = ['request']
367        self.browser.getControl("Save").click()
368        self.browser.getControl(name="transition").value = ['reject']
369        self.browser.getControl("Save").click()
370        self.browser.getControl(name="transition").value = ['request']
371        self.browser.getControl("Save").click()
372        self.browser.getControl(name="transition").value = ['approve']
373        self.browser.getControl("Save").click()
374        self.browser.getControl(name="transition").value = ['reset1']
375        self.browser.getControl("Save").click()
376        return
377
378    def test_manage_import(self):
379        # Managers can import customer data files
380        datacenter_path = 'http://localhost/app/datacenter'
381        # Prepare a csv file for customers
382        open('customers.csv', 'wb').write(
383"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
384Aaren,Pieri,1,1990-01-02,aa@aa.ng,1234,m,mypwd1
385Claus,Finau,2,1990-01-03,aa@aa.ng,1234,m,mypwd1
386Brit,Berson,2,1990-01-04,aa@aa.ng,1234,m,mypwd1
387""")
388        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
389        self.browser.open(datacenter_path)
390        self.browser.getLink('Upload data').click()
391        filecontents = StringIO(open('customers.csv', 'rb').read())
392        filewidget = self.browser.getControl(name='uploadfile:file')
393        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
394        self.browser.getControl(name='SUBMIT').click()
395        self.browser.getLink('Process data').click()
396        button = lookup_submit_value(
397            'select', 'customers_zope.mgr.csv', self.browser)
398        button.click()
399        importerselect = self.browser.getControl(name='importer')
400        modeselect = self.browser.getControl(name='mode')
401        importerselect.getControl('Customer Processor').selected = True
402        modeselect.getControl(value='create').selected = True
403        self.browser.getControl('Proceed to step 3').click()
404        self.assertTrue('Header fields OK' in self.browser.contents)
405        self.browser.getControl('Perform import').click()
406        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
407        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
408        self.assertTrue('Batch processing finished' in self.browser.contents)
409
410        # The customers are properly indexed and we can
411        # thus find a customer in  the department
412        self.browser.open(self.manage_container_path)
413        # We can search for a new customer by name ...
414        self.browser.getControl(name="searchtype").value = ['fullname']
415        self.browser.getControl(name="searchterm").value = 'Claus'
416        self.browser.getControl("Find customer(s)").click()
417        self.assertTrue('Claus Finau' in self.browser.contents)
418        # ... and check if the imported password has been properly set
419        ctrl = self.browser.getControl(name='entries')
420        value = ctrl.options[0]
421        claus = self.app['customers'][value]
422        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
423        return
424
425    def test_activate_deactivate_buttons(self):
426        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
427        self.browser.open(self.customer_path)
428        self.browser.getLink("Deactivate").click()
429        self.assertTrue(
430            'Customer account has been deactivated.' in self.browser.contents)
431        self.assertTrue(
432            'Base Data (account deactivated)' in self.browser.contents)
433        self.assertTrue(self.customer.suspended)
434        self.browser.getLink("Activate").click()
435        self.assertTrue(
436            'Customer account has been activated.' in self.browser.contents)
437        self.assertFalse(
438            'Base Data (account deactivated)' in self.browser.contents)
439        self.assertFalse(self.customer.suspended)
440        # History messages have been added ...
441        self.browser.getLink("History").click()
442        self.assertTrue(
443            'Customer account deactivated by Manager<br />' in self.browser.contents)
444        self.assertTrue(
445            'Customer account activated by Manager<br />' in self.browser.contents)
446        # ... and actions have been logged.
447        logfile = os.path.join(
448            self.app['datacenter'].storage, 'logs', 'customers.log')
449        logcontent = open(logfile).read()
450        self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - '
451                        'K1000000 - account deactivated' in logcontent)
452        self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - '
453                        'K1000000 - account activated' in logcontent)
454
455
456    def test_login_as_customer(self):
457        # CustomerImpersonators can login as customer
458        # Create clearance officer
459        self.app['users'].addUser('mrofficer', 'mrofficersecret')
460        self.app['users']['mrofficer'].email = 'mrofficer@foo.ng'
461        self.app['users']['mrofficer'].title = 'Harry Actor'
462        prmglobal = IPrincipalRoleManager(self.app)
463        prmglobal.assignRoleToPrincipal('waeup.CustomerImpersonator', 'mrofficer')
464        prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer')
465        # Login as customer impersonator
466        self.browser.open(self.login_path)
467        self.browser.getControl(name="form.login").value = 'mrofficer'
468        self.browser.getControl(name="form.password").value = 'mrofficersecret'
469        self.browser.getControl("Login").click()
470        self.assertMatches('...You logged in...', self.browser.contents)
471        self.browser.open(self.customer_path)
472        self.browser.getLink("Login as").click()
473        self.browser.getControl("Set password now").click()
474        temp_password = self.browser.getControl(name='form.password').value
475        self.browser.getControl("Login now").click()
476        self.assertMatches(
477            '...You successfully logged in as...', self.browser.contents)
478        # We are logged in as customer and can see the 'My Data' tab
479        self.assertMatches(
480            '...<a href="#" class="dropdown-toggle" data-toggle="dropdown">...',
481            self.browser.contents)
482        self.assertMatches(
483            '...My Data...',
484            self.browser.contents)
485        self.browser.getLink("Logout").click()
486        # The customer can't login with the original password ...
487        self.browser.open(self.login_path)
488        self.browser.getControl(name="form.login").value = self.customer_id
489        self.browser.getControl(name="form.password").value = 'cpwd'
490        self.browser.getControl("Login").click()
491        self.assertMatches(
492            '...Your account has been temporarily deactivated...',
493            self.browser.contents)
494        # ... but with the temporary password
495        self.browser.open(self.login_path)
496        self.browser.getControl(name="form.login").value = self.customer_id
497        self.browser.getControl(name="form.password").value = temp_password
498        self.browser.getControl("Login").click()
499        self.assertMatches('...You logged in...', self.browser.contents)
500        # Creation of temp_password is properly logged
501        logfile = os.path.join(
502            self.app['datacenter'].storage, 'logs', 'customers.log')
503        logcontent = open(logfile).read()
504        self.assertTrue(
505            'mrofficer - customers.browser.LoginAsCustomerStep1 - K1000000 - '
506            'temp_password generated: %s' % temp_password in logcontent)
507
508
509class CustomerUITests(CustomersFullSetup):
510    # Tests for Customer class views and pages
511
512    def test_customer_change_password(self):
513        # Customers can change the password
514        self.customer.personal_updated = datetime.utcnow()
515        self.browser.open(self.login_path)
516        self.browser.getControl(name="form.login").value = self.customer_id
517        self.browser.getControl(name="form.password").value = 'cpwd'
518        self.browser.getControl("Login").click()
519        self.assertEqual(self.browser.url, self.customer_path)
520        self.assertTrue('You logged in' in self.browser.contents)
521        # Change password
522        self.browser.getLink("Change password").click()
523        self.browser.getControl(name="change_password").value = 'pw'
524        self.browser.getControl(
525            name="change_password_repeat").value = 'pw'
526        self.browser.getControl("Save").click()
527        self.assertTrue('Password must have at least' in self.browser.contents)
528        self.browser.getControl(name="change_password").value = 'new_password'
529        self.browser.getControl(
530            name="change_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="change_password").value = 'new_password'
534        self.browser.getControl(
535            name="change_password_repeat").value = 'new_password'
536        self.browser.getControl("Save").click()
537        self.assertTrue('Password changed' in self.browser.contents)
538        # We are still logged in. Changing the password hasn't thrown us out.
539        self.browser.getLink("Base Data").click()
540        self.assertEqual(self.browser.url, self.customer_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/index')
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.customer_id
549        self.browser.getControl(name="form.password").value = 'new_password'
550        self.browser.getControl("Login").click()
551        self.assertEqual(self.browser.url, self.customer_path)
552        self.assertTrue('You logged in' in self.browser.contents)
553        return
554
555    def test_customer_upload_passport(self):
556        # Customer cant login if their password is not set
557        IWorkflowInfo(self.customer).fireTransition('start')
558        self.browser.open(self.login_path)
559        self.browser.getControl(name="form.login").value = self.customer_id
560        self.browser.getControl(name="form.password").value = 'cpwd'
561        self.browser.getControl("Login").click()
562        self.assertMatches(
563            '...You logged in...', self.browser.contents)
564        # Admitted customer can upload a passport picture
565        self.browser.getLink("Change portrait").click()
566        ctrl = self.browser.getControl(name='passporteditupload')
567        file_obj = open(SAMPLE_IMAGE, 'rb')
568        file_ctrl = ctrl.mech_control
569        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
570        self.browser.getControl(
571            name='upload_passporteditupload').click()
572        self.assertTrue(
573            'src="http://localhost/app/customers/K1000000/passport.jpg"'
574            in self.browser.contents)
575
576    def test_customer_baseedit(self):
577        # Customers can change the password
578        self.customer.personal_updated = datetime.utcnow()
579        self.browser.open(self.login_path)
580        self.browser.getControl(name="form.login").value = self.customer_id
581        self.browser.getControl(name="form.password").value = 'cpwd'
582        self.browser.getControl("Login").click()
583        self.assertEqual(self.browser.url, self.customer_path)
584        self.assertTrue('You logged in' in self.browser.contents)
585        self.browser.getLink("Edit").click()
586        self.browser.getControl(name="form.email").value = 'new_email@aa.ng'
587        self.browser.getControl("Save").click()
588        self.assertMatches('...Form has been saved...',
589                           self.browser.contents)
590        # Customer can view history
591        self.browser.getLink("History").click()
592        self.assertMatches('...Customer record created by system...',
593            self.browser.contents)
594
595    def test_customer_login(self):
596        # Customer cant login if their password is not set
597        self.customer.password = None
598        self.browser.open(self.login_path)
599        self.browser.getControl(name="form.login").value = self.customer_id
600        self.browser.getControl(name="form.password").value = 'cpwd'
601        self.browser.getControl("Login").click()
602        self.assertTrue(
603            'You entered invalid credentials.' in self.browser.contents)
604        # We set the password again
605        IUserAccount(
606            self.app['customers'][self.customer_id]).setPassword('cpwd')
607        # Customers can't login if their account is suspended/deactivated
608        self.customer.suspended = True
609        self.browser.open(self.login_path)
610        self.browser.getControl(name="form.login").value = self.customer_id
611        self.browser.getControl(name="form.password").value = 'cpwd'
612        self.browser.getControl("Login").click()
613        self.assertMatches(
614            '...<div class="alert alert-warning">'
615            'Your account has been deactivated.</div>...', self.browser.contents)
616        # If suspended_comment is set this message will be flashed instead
617        self.customer.suspended_comment = u'Aetsch baetsch!'
618        self.browser.getControl(name="form.login").value = self.customer_id
619        self.browser.getControl(name="form.password").value = 'cpwd'
620        self.browser.getControl("Login").click()
621        self.assertMatches(
622            '...<div class="alert alert-warning">Aetsch baetsch!</div>...',
623            self.browser.contents)
624        self.customer.suspended = False
625        # Customers can't login if a temporary password has been set and
626        # is not expired
627        self.app['customers'][self.customer_id].setTempPassword(
628            'anybody', 'temp_cpwd')
629        self.browser.open(self.login_path)
630        self.browser.getControl(name="form.login").value = self.customer_id
631        self.browser.getControl(name="form.password").value = 'cpwd'
632        self.browser.getControl("Login").click()
633        self.assertMatches(
634            '...Your account has been temporarily deactivated...',
635            self.browser.contents)
636        # The customer can login with the temporary password
637        self.browser.open(self.login_path)
638        self.browser.getControl(name="form.login").value = self.customer_id
639        self.browser.getControl(name="form.password").value = 'temp_cpwd'
640        self.browser.getControl("Login").click()
641        self.assertMatches(
642            '...You logged in...', self.browser.contents)
643        # Customer can view the base data
644        self.browser.open(self.customer_path)
645        self.assertEqual(self.browser.headers['Status'], '200 Ok')
646        self.assertEqual(self.browser.url, self.customer_path)
647        # When the password expires ...
648        delta = timedelta(minutes=11)
649        self.app['customers'][self.customer_id].temp_password[
650            'timestamp'] = datetime.utcnow() - delta
651        self.app['customers'][self.customer_id]._p_changed = True
652        # ... the customer will be automatically logged out
653        self.assertRaises(
654            Unauthorized, self.browser.open, self.customer_path)
655        # Then the customer can login with the original password
656        self.browser.open(self.login_path)
657        self.browser.getControl(name="form.login").value = self.customer_id
658        self.browser.getControl(name="form.password").value = 'cpwd'
659        self.browser.getControl("Login").click()
660        self.assertMatches(
661            '...You logged in...', self.browser.contents)
662
663    def test_change_password_request(self):
664        self.browser.open('http://localhost/app/changepw')
665        self.browser.getControl(name="form.identifier").value = '123'
666        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
667        self.browser.getControl("Send login credentials").click()
668        self.assertTrue('An email with' in self.browser.contents)
669
670class CustomerRegistrationTests(CustomersFullSetup):
671    # Tests for customer registration
672
673    layer = FunctionalLayer
674
675    def test_request_pw(self):
676        # Customer with wrong number can't be found.
677        self.browser.open('http://localhost/app/requestpw')
678        self.browser.getControl(name="form.firstname").value = 'Anna'
679        self.browser.getControl(name="form.number").value = 'anynumber'
680        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
681        self.browser.getControl("Send login credentials").click()
682        self.assertTrue('No customer record found.'
683            in self.browser.contents)
684        # Anonymous is not informed that firstname verification failed.
685        # It seems that the record doesn't exist.
686        self.browser.open('http://localhost/app/requestpw')
687        self.browser.getControl(name="form.firstname").value = 'Johnny'
688        self.browser.getControl(name="form.number").value = '123'
689        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
690        self.browser.getControl("Send login credentials").click()
691        self.assertTrue('No customer record found.'
692            in self.browser.contents)
693        # Even with the correct firstname we can't register if a
694        # password has been set and used.
695        self.browser.getControl(name="form.firstname").value = 'Anna'
696        self.browser.getControl(name="form.number").value = '123'
697        self.browser.getControl("Send login credentials").click()
698        self.assertTrue('Your password has already been set and used.'
699            in self.browser.contents)
700        self.browser.open('http://localhost/app/requestpw')
701        self.app['customers'][self.customer_id].password = None
702        # The firstname field, used for verification, is not case-sensitive.
703        self.browser.getControl(name="form.firstname").value = 'aNNa'
704        self.browser.getControl(name="form.number").value = '123'
705        self.browser.getControl(name="form.email").value = 'new@yy.zz'
706        self.browser.getControl("Send login credentials").click()
707        # Yeah, we succeded ...
708        self.assertTrue('Your request was successful.'
709            in self.browser.contents)
710        # ... and  customer can be found in the catalog via the email address
711        cat = queryUtility(ICatalog, name='customers_catalog')
712        results = list(
713            cat.searchResults(
714            email=('new@yy.zz', 'new@yy.zz')))
715        self.assertEqual(self.customer,results[0])
716        logfile = os.path.join(
717            self.app['datacenter'].storage, 'logs', 'main.log')
718        logcontent = open(logfile).read()
719        self.assertTrue('zope.anybody - customers.browser.CustomerRequestPasswordPage - '
720                        '123 (K1000000) - new@yy.zz' in logcontent)
721        return
722
723    def test_create_account(self):
724        # Customer with wrong number can't be found.
725        self.browser.open('http://localhost/app/createaccount')
726        self.browser.getControl(name="form.firstname").value = 'Ruben'
727        self.browser.getControl(name="form.lastname").value = 'Gonzales'
728        self.browser.getControl(name="form.email").value = 'newcustomer@xx.zz'
729        self.browser.getControl("Send login credentials").click()
730        self.assertTrue('Your request was successful.'
731            in self.browser.contents)
732        # ... and  customer can be found in the catalog via the email address
733        cat = queryUtility(ICatalog, name='customers_catalog')
734        results = list(
735            cat.searchResults(
736            email=('newcustomer@xx.zz', 'newcustomer@xx.zz')))
737        self.assertEqual(self.app['customers']['K1000001'], results[0])
738        self.assertEqual(self.app['customers']['K1000001'].firstname, 'Ruben')
739        self.assertEqual(self.app['customers']['K1000001'].lastname, 'Gonzales')
740        logfile = os.path.join(
741            self.app['datacenter'].storage, 'logs', 'main.log')
742        logcontent = open(logfile).read()
743        self.assertTrue('zope.anybody - customers.browser.CustomerCreateAccountPage - '
744                        'K1000001 - newcustomer@xx.zz' in logcontent)
745        return
746
747class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase):
748    # Tests for CustomersContainer class views and pages
749
750    layer = FunctionalLayer
751
752    def wait_for_export_job_completed(self):
753        # helper function waiting until the current export job is completed
754        manager = getUtility(IJobManager)
755        job_id = self.app['datacenter'].running_exports[0][0]
756        job = manager.get(job_id)
757        wait_for_result(job)
758        return job_id
759
760    def test_datacenter_export(self):
761        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
762        self.browser.open('http://localhost/app/datacenter/@@export')
763        self.browser.getControl(name="exporter").value = ['customers']
764        self.browser.getControl("Create CSV file").click()
765
766        # When the job is finished and we reload the page...
767        job_id = self.wait_for_export_job_completed()
768        # ... the csv file can be downloaded ...
769        self.browser.open('http://localhost/app/datacenter/@@export')
770        self.browser.getLink("Download").click()
771        self.assertEqual(self.browser.headers['content-type'],
772            'text/csv; charset=UTF-8')
773        self.assertTrue(
774            'filename="WAeUP.Ikoba_customers_%s.csv' % job_id in
775            self.browser.headers['content-disposition'])
776        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
777        job_id = self.app['datacenter'].running_exports[0][0]
778        # ... and discarded
779        self.browser.open('http://localhost/app/datacenter/@@export')
780        self.browser.getControl("Discard").click()
781        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
782        # Creation, downloading and discarding is logged
783        logfile = os.path.join(
784            self.app['datacenter'].storage, 'logs', 'datacenter.log')
785        logcontent = open(logfile).read()
786        self.assertTrue(
787            'zope.mgr - browser.pages.ExportCSVPage - exported: '
788            'customers, job_id=%s'
789            % job_id in logcontent
790            )
791        self.assertTrue(
792            'zope.mgr - browser.pages.ExportCSVView - downloaded: '
793            'WAeUP.Ikoba_customers_%s.csv, job_id=%s'
794            % (job_id, job_id) in logcontent
795            )
796        self.assertTrue(
797            'zope.mgr - browser.pages.ExportCSVPage - discarded: '
798            'job_id=%s' % job_id in logcontent
799            )
800
801
802class DocumentUITests(CustomersFullSetup):
803    # Tests for CustomerSampleDocument relates views and pages
804
805    def test_manage_document(self):
806        # Managers can access the pages of customer documentsconter
807        # and can perform actions
808        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
809        self.browser.open(self.customer_path)
810        self.assertEqual(self.browser.headers['Status'], '200 Ok')
811        self.assertEqual(self.browser.url, self.customer_path)
812        self.browser.open(self.customer_path)
813        self.browser.getLink("Documents").click()
814        self.browser.getLink("Add document").click()
815        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
816        self.browser.getControl("Create document").click()
817        self.assertTrue('PDF Document created.' in self.browser.contents)
818        document = self.customer['documents']['d102']
819
820        # Document can be edited
821        self.browser.getLink("d102").click()
822        self.browser.getLink("Manage").click()
823        self.browser.getControl(name="form.title").value = 'My second doc'
824        self.browser.getControl("Save").click()
825        self.assertTrue('Form has been saved.' in self.browser.contents)
826        self.browser.getLink("View").click()
827        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
828
829        # Transitions can be performed
830        self.browser.getLink("Transition").click()
831        self.browser.getControl(name="transition").value = ['submit']
832        self.browser.getControl("Save").click()
833        self.browser.getControl(name="transition").value = ['verify']
834        self.browser.getControl("Save").click()
835        self.assertEqual(document.state, 'verified')
836
837        # Documents can be removed
838        self.browser.getLink("Documents").click()
839        ctrl = self.browser.getControl(name='val_id')
840        ctrl.getControl(value=document.document_id).selected = True
841        self.browser.getControl("Remove selected", index=0).click()
842        self.assertTrue('Successfully removed' in self.browser.contents)
843
844        # All actions are being logged
845        logfile = os.path.join(
846            self.app['datacenter'].storage, 'logs', 'customers.log')
847        logcontent = open(logfile).read()
848
849        self.assertTrue(
850            'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
851            '- K1000000 - saved: title'
852            in logcontent)
853
854        self.assertTrue(
855            'INFO - zope.mgr - customers.browser.DocumentAddFormPage '
856            '- K1000000 - added: PDF Document %s'
857            % document.document_id in logcontent)
858
859        self.assertTrue(
860            'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
861            '- K1000000 - removed: %s'
862            % document.document_id in logcontent)
863
864    def test_edit_sample_document(self):
865        # Customers can manage documents under certain conditions
866        self.browser.open(self.login_path)
867        self.browser.getControl(name="form.login").value = self.customer_id
868        self.browser.getControl(name="form.password").value = 'cpwd'
869        self.browser.getControl("Login").click()
870        self.assertMatches(
871            '...You logged in...', self.browser.contents)
872        self.browser.getLink("Documents").click()
873        self.browser.getLink("Add document").click()
874        self.browser.getControl(name="doctype").value = ['CustomerSampleDocument']
875        self.browser.getControl("Create document").click()
876        self.assertTrue('Sample Document created.' in self.browser.contents)
877        document = self.customer['documents']['d102']
878
879        # Document can be edited ...
880        self.browser.getLink("d102").click()
881        self.browser.open(self.documents_path + '/d102/edit')
882        #self.browser.getLink("Edit").click()
883        self.assertTrue('The requested form is locked' in self.browser.contents)
884        # Customer is in wrong state
885        IWorkflowState(self.customer).setState(APPROVED)
886        self.browser.open(self.documents_path + '/d102/edit')
887        self.browser.getControl(name="form.title").value = 'My second doc'
888        self.browser.getControl("Save").click()
889        self.assertEqual(document.title, 'My second doc')
890        self.assertTrue('Form has been saved.' in self.browser.contents)
891        self.browser.getLink("View").click()
892        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
893        # Costumer can upload a document.
894        self.browser.getLink("Edit").click()
895        ctrl = self.browser.getControl(name='samplescaneditupload')
896        file_obj = open(SAMPLE_IMAGE, 'rb')
897        file_ctrl = ctrl.mech_control
898        file_ctrl.add_file(file_obj, filename='my_document.jpg')
899        self.browser.getControl(
900            name='upload_samplescaneditupload').click()
901        self.assertTrue(
902            'href="http://localhost/app/customers/K1000000/documents/d102/sample"'
903            in self.browser.contents)
904        # Costumer can submit the form. The form is also saved.
905        self.browser.getControl(name="form.title").value = 'My third doc'
906        self.browser.getControl("Final Submit").click()
907        self.assertEqual(document.title, 'My third doc')
908        self.assertEqual(document.state, 'submitted')
909        self.assertTrue('Document State: submitted for verification' in self.browser.contents)
910        # Customer can't edit the document once it has been submitted
911        self.browser.open(self.documents_path + '/d102/edit')
912        self.assertTrue('The requested form is locked' in self.browser.contents)
913
914    def test_manage_upload_sample_file(self):
915        # Managers can upload a file via the DocumentManageFormPage
916        # The image is stored even if form has errors
917        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
918        self.browser.open(self.customer_path + '/documents/d101/manage')
919        # Create a pseudo image file and select it to be uploaded
920        image = open(SAMPLE_IMAGE, 'rb')
921        ctrl = self.browser.getControl(name='samplescanmanageupload')
922        file_ctrl = ctrl.mech_control
923        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
924        # The Save action does not upload files
925        self.browser.getControl("Save").click() # submit form
926        self.assertFalse(
927            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
928            in self.browser.contents)
929        # ... but the correct upload submit button does
930        image = open(SAMPLE_IMAGE)
931        ctrl = self.browser.getControl(name='samplescanmanageupload')
932        file_ctrl = ctrl.mech_control
933        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
934        self.browser.getControl(
935            name='upload_samplescanmanageupload').click()
936        self.assertTrue(
937            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
938            in self.browser.contents)
939        # Browsing the link shows a real image
940        self.browser.open('sample')
941        self.assertEqual(
942            self.browser.headers['content-type'], 'image/jpeg')
943        self.assertEqual(len(self.browser.contents), 2787)
944        # We can't reupload a file. The existing file must be deleted first.
945        self.browser.open(self.customer_path + '/documents/d101/manage')
946        self.assertFalse(
947            'upload_samplescanmanageupload' in self.browser.contents)
948        # File must be deleted first
949        self.browser.getControl(name='delete_samplescanmanageupload').click()
950        self.assertTrue(
951            'sample deleted' in self.browser.contents)
952        # Uploading a file which is bigger than 150k will raise an error
953        big_image = StringIO(open(SAMPLE_IMAGE, 'rb').read() * 75)
954        ctrl = self.browser.getControl(name='samplescanmanageupload')
955        file_ctrl = ctrl.mech_control
956        file_ctrl.add_file(big_image, filename='my_sample_scan.jpg')
957        self.browser.getControl(
958            name='upload_samplescanmanageupload').click()
959        self.assertTrue(
960            'Uploaded file is too big' in self.browser.contents)
961        # we do not rely on filename extensions given by uploaders
962        image = open(SAMPLE_IMAGE, 'rb') # a jpg-file
963        ctrl = self.browser.getControl(name='samplescanmanageupload')
964        file_ctrl = ctrl.mech_control
965        # tell uploaded file is bmp
966        file_ctrl.add_file(image, filename='my_sample_scan.bmp')
967        self.browser.getControl(
968            name='upload_samplescanmanageupload').click()
969        self.assertTrue(
970            # jpg file was recognized
971            'File sample.jpg uploaded.' in self.browser.contents)
972        # Delete file again
973        self.browser.getControl(name='delete_samplescanmanageupload').click()
974        self.assertTrue(
975            'sample deleted' in self.browser.contents)
976        # File names must meet several conditions
977        bmp_image = open(SAMPLE_IMAGE_BMP, 'rb')
978        ctrl = self.browser.getControl(name='samplescanmanageupload')
979        file_ctrl = ctrl.mech_control
980        file_ctrl.add_file(bmp_image, filename='my_sample_scan.bmp')
981        self.browser.getControl(
982            name='upload_samplescanmanageupload').click()
983        self.assertTrue('Only the following extensions are allowed'
984            in self.browser.contents)
985
986    def test_manage_upload_pdf_file(self):
987        # Managers can upload a file via the DocumentManageFormPage
988        # The image is stored even if form has errors
989        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
990        self.browser.open(self.customer_path + '/documents')
991        self.browser.getLink("Add document").click()
992        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
993        self.browser.getControl("Create document").click()
994        self.browser.open(self.documents_path + '/d102/manage')
995        # Create a pseudo image file and select it to be uploaded
996        image = open(SAMPLE_IMAGE, 'rb')
997        ctrl = self.browser.getControl(name='pdfscanmanageupload')
998        file_ctrl = ctrl.mech_control
999        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1000        self.browser.getControl(
1001            name='upload_pdfscanmanageupload').click()
1002        self.assertTrue(
1003            'pdf file extension expected' in self.browser.contents)
1004        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1005        file_ctrl = ctrl.mech_control
1006        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
1007        self.browser.getControl(
1008            name='upload_pdfscanmanageupload').click()
1009        self.assertTrue(
1010            'Could not determine file type' in self.browser.contents)
1011        pdf = open(SAMPLE_PDF, 'rb')
1012        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1013        file_ctrl = ctrl.mech_control
1014        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
1015        self.browser.getControl(
1016            name='upload_pdfscanmanageupload').click()
1017        self.assertTrue(
1018            'href="http://localhost/app/customers/K1000000/documents/d102/sample.pdf">PDF File</a>'
1019            in self.browser.contents)
1020        # Browsing the link shows a real pdf
1021        self.browser.open('sample.pdf')
1022        self.assertEqual(
1023            self.browser.headers['content-type'], 'application/pdf')
1024
1025    def test_view_slips(self):
1026        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1027        # Officers can open the document overview
1028        self.browser.open(self.customer_path + '/documents')
1029        self.browser.getLink("Download documents overview").click()
1030        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1031        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1032        path = os.path.join(samples_dir(), 'overview_slip.pdf')
1033        open(path, 'wb').write(self.browser.contents)
1034        print "Sample PDF overview_slip.pdf written to %s" % path
1035        # Officers can open document slips
1036        self.browser.open(self.customer_path + '/documents/d101')
1037        self.browser.getLink("Download document slip").click()
1038        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1039        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1040        path = os.path.join(samples_dir(), 'document_slip.pdf')
1041        open(path, 'wb').write(self.browser.contents)
1042        print "Sample document_slip.pdf written to %s" % path
Note: See TracBrowser for help on using the repository browser.