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

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

Implement customer self-registration.

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