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

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

propset svn:keywords "Id"

  • Property svn:keywords set to Id
File size: 37.5 KB
Line 
1## $Id: test_browser.py 11997 2014-11-19 17:02:48Z 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
43from waeup.ikoba.authentication import LocalRoleSetEvent
44from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase
45
46PH_LEN = 15911  # Length of placeholder file
47
48SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
49SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
50
51def lookup_submit_value(name, value, browser):
52    """Find a button with a certain value."""
53    for num in range(0, 100):
54        try:
55            button = browser.getControl(name=name, index=num)
56            if button.value.endswith(value):
57                return button
58        except IndexError:
59            break
60    return None
61
62class CustomersFullSetup(FunctionalTestCase):
63    # A test case that only contains a setup and teardown
64    #
65    # Complete setup for customers handlings is rather complex and
66    # requires lots of things created before we can start. This is a
67    # setup that does all this, creates a university, creates PINs,
68    # etc.  so that we do not have to bother with that in different
69    # test cases.
70
71    layer = FunctionalLayer
72
73    def setUp(self):
74        super(CustomersFullSetup, self).setUp()
75
76        # Setup a sample site for each test
77        app = Company()
78        self.dc_root = tempfile.mkdtemp()
79        app['datacenter'].setStoragePath(self.dc_root)
80
81        # Prepopulate the ZODB...
82        self.getRootFolder()['app'] = app
83        # we add the site immediately after creation to the
84        # ZODB. Catalogs and other local utilities are not setup
85        # before that step.
86        self.app = self.getRootFolder()['app']
87        # Set site here. Some of the following setup code might need
88        # to access grok.getSite() and should get our new app then
89        setSite(app)
90
91        # Add customer with subobjects
92        customer = createObject('waeup.Customer')
93        customer.firstname = u'Anna'
94        customer.lastname = u'Tester'
95        customer.reg_number = u'123'
96        customer.sex = u'm'
97        customer.email = 'aa@aa.ng'
98        customer.phone = u'1234'
99        customer.date_of_birth = date(1981, 2, 4)
100        self.app['customers'].addCustomer(customer)
101        self.customer_id = customer.customer_id
102        self.customer = self.app['customers'][self.customer_id]
103
104        # Set password
105        IUserAccount(
106            self.app['customers'][self.customer_id]).setPassword('spwd')
107
108        self.login_path = 'http://localhost/app/login'
109        self.container_path = 'http://localhost/app/customers'
110        self.manage_container_path = self.container_path + '/@@manage'
111        self.add_customer_path = self.container_path + '/addcustomer'
112        self.customer_path = self.container_path + '/' + self.customer_id
113        self.manage_customer_path = self.customer_path + '/manage_base'
114        self.trigtrans_path = self.customer_path + '/trigtrans'
115        self.history_path = self.customer_path + '/history'
116
117        self.app['configuration'].carry_over = True
118        configuration = createObject('waeup.SessionConfiguration')
119        self.app['configuration'].addSessionConfiguration(configuration)
120
121        # Update the catalog
122        notify(grok.ObjectModifiedEvent(self.customer))
123
124        # Put the prepopulated site into test ZODB and prepare test
125        # browser
126        self.browser = Browser()
127        self.browser.handleErrors = False
128
129    def tearDown(self):
130        super(CustomersFullSetup, self).tearDown()
131        clearSite()
132        shutil.rmtree(self.dc_root)
133
134
135
136class CustomersContainerUITests(CustomersFullSetup):
137    # Tests for CustomersContainer class views and pages
138
139    layer = FunctionalLayer
140
141    def test_anonymous_access(self):
142        # Anonymous users can't access customers containers
143        self.assertRaises(
144            Unauthorized, self.browser.open, self.container_path)
145        self.assertRaises(
146            Unauthorized, self.browser.open, self.manage_container_path)
147        return
148
149    def test_manage_access(self):
150        # Managers can access the view page of customers
151        # containers and can perform actions
152        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
153        self.browser.open(self.container_path)
154        self.assertEqual(self.browser.headers['Status'], '200 Ok')
155        self.assertEqual(self.browser.url, self.container_path)
156        self.browser.getLink("Manage customer section").click()
157        self.assertEqual(self.browser.headers['Status'], '200 Ok')
158        self.assertEqual(self.browser.url, self.manage_container_path)
159        return
160
161    def test_add_search_delete_customers(self):
162        # Managers can add search and remove customers
163        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
164        self.browser.open(self.manage_container_path)
165        self.browser.getLink("Add customer").click()
166        self.assertEqual(self.browser.headers['Status'], '200 Ok')
167        self.assertEqual(self.browser.url, self.add_customer_path)
168        self.browser.getControl(name="form.firstname").value = 'Bob'
169        self.browser.getControl(name="form.lastname").value = 'Tester'
170        self.browser.getControl(name="form.reg_number").value = '123'
171        self.browser.getControl("Create customer record").click()
172        self.assertTrue('Registration number exists already'
173            in self.browser.contents)
174        self.browser.getControl(name="form.reg_number").value = '1234'
175        self.browser.getControl("Create customer record").click()
176        self.assertTrue('Customer record created' in self.browser.contents)
177
178        # Registration must be unique
179        self.browser.getLink("Manage").click()
180        self.browser.getControl(name="form.reg_number").value = '123'
181        self.browser.getControl("Save").click()
182        self.assertMatches('...Registration number exists...',
183                           self.browser.contents)
184
185        # We can find a customer with a certain customer_id
186        self.browser.open(self.container_path)
187        self.browser.getControl("Find customer(s)").click()
188        self.assertTrue('Empty search string' in self.browser.contents)
189        self.browser.getControl(name="searchtype").value = ['customer_id']
190        self.browser.getControl(name="searchterm").value = self.customer_id
191        self.browser.getControl("Find customer(s)").click()
192        self.assertTrue('Anna Tester' in self.browser.contents)
193
194        # We can find a customer by searching for all kind of name parts
195        self.browser.open(self.manage_container_path)
196        self.browser.getControl("Find customer(s)").click()
197        self.assertTrue('Empty search string' in self.browser.contents)
198        self.browser.getControl(name="searchtype").value = ['fullname']
199        self.browser.getControl(name="searchterm").value = 'Anna Tester'
200        self.browser.getControl("Find customer(s)").click()
201        self.assertTrue('Anna Tester' in self.browser.contents)
202        self.browser.open(self.manage_container_path)
203        self.browser.getControl(name="searchtype").value = ['fullname']
204        self.browser.getControl(name="searchterm").value = 'Anna'
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 = 'Tester'
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 = 'An'
215        self.browser.getControl("Find customer(s)").click()
216        self.assertFalse('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.assertTrue('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 = 'tester'
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 Ana'
230        self.browser.getControl("Find customer(s)").click()
231        self.assertFalse('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 Anna'
235        self.browser.getControl("Find customer(s)").click()
236        self.assertTrue('Anna Tester' in self.browser.contents)
237        # The old searchterm will be used again
238        self.browser.getControl("Find customer(s)").click()
239        self.assertTrue('Anna Tester' in self.browser.contents)
240
241        # We can find suspended customers
242        self.customer.suspended = True
243        notify(grok.ObjectModifiedEvent(self.customer))
244        self.browser.open(self.manage_container_path)
245        self.browser.getControl(name="searchtype").value = ['suspended']
246        self.browser.getControl("Find customer(s)").click()
247        self.assertTrue('Anna Tester' in self.browser.contents)
248
249        # Removed customers won't be found
250        ctrl = self.browser.getControl(name='entries')
251        ctrl.getControl(value=self.customer_id).selected = True
252        self.browser.getControl("Remove selected", index=0).click()
253        self.assertTrue('Successfully removed' in self.browser.contents)
254        self.browser.getControl(name="searchtype").value = ['customer_id']
255        self.browser.getControl(name="searchterm").value = self.customer_id
256        self.browser.getControl("Find customer(s)").click()
257        self.assertTrue('No customer found' in self.browser.contents)
258        return
259
260class OfficerUITests(CustomersFullSetup):
261    # Tests for Customer class views and pages
262
263    def test_basic_auth(self):
264        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
265        self.browser.open('http://localhost/app')
266        self.browser.getLink("Logout").click()
267        self.assertTrue('You have been logged out' in self.browser.contents)
268        # But we are still logged in since we've used basic authentication here.
269        # Wikipedia says: Existing browsers retain authentication information
270        # until the tab or browser is closed or the user clears the history.
271        # HTTP does not provide a method for a server to direct clients to
272        # discard these cached credentials. This means that there is no
273        # effective way for a server to "log out" the user without closing
274        # the browser. This is a significant defect that requires browser
275        # manufacturers to support a "logout" user interface element ...
276        self.assertTrue('Manager' in self.browser.contents)
277
278    def test_basic_auth_base64(self):
279        auth_token = base64.b64encode('mgr:mgrpw')
280        self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
281        self.browser.open(self.manage_container_path)
282        self.assertEqual(self.browser.headers['Status'], '200 Ok')
283
284    def test_manage_access(self):
285        # Managers can access the pages of customers
286        # and can perform actions
287        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
288        self.browser.open(self.customer_path)
289        self.assertEqual(self.browser.headers['Status'], '200 Ok')
290        self.assertEqual(self.browser.url, self.customer_path)
291        self.browser.getLink("Trigger").click()
292        self.assertEqual(self.browser.headers['Status'], '200 Ok')
293        # Managers can trigger transitions
294        self.browser.getControl(name="transition").value = ['start']
295        self.browser.getControl("Save").click()
296        # Managers can edit base
297        self.browser.open(self.customer_path)
298        self.browser.getLink("Manage").click()
299        self.assertEqual(self.browser.url, self.manage_customer_path)
300        self.assertEqual(self.browser.headers['Status'], '200 Ok')
301        self.browser.getControl(name="form.firstname").value = 'John'
302        self.browser.getControl(name="form.lastname").value = 'Tester'
303        self.browser.getControl(name="form.reg_number").value = '345'
304        self.browser.getControl(name="password").value = 'secret'
305        self.browser.getControl(name="control_password").value = 'secret'
306        self.browser.getControl("Save").click()
307        self.assertMatches('...Form has been saved...',
308                           self.browser.contents)
309
310    def test_manage_contact_customer(self):
311        # Managers can contact customer
312        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
313        self.customer.email = None
314        self.browser.open(self.customer_path)
315        self.browser.getLink("Send email").click()
316        self.browser.getControl(name="form.subject").value = 'Important subject'
317        self.browser.getControl(name="form.body").value = 'Hello!'
318        self.browser.getControl("Send message now").click()
319        self.assertTrue('An smtp server error occurred' in self.browser.contents)
320        self.customer.email = 'xx@yy.zz'
321        self.browser.getControl("Send message now").click()
322        self.assertTrue('Your message has been sent' in self.browser.contents)
323        return
324
325    def test_manage_upload_passport(self):
326        # Managers can upload a file via the CustomerBaseManageFormPage
327        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
328        self.browser.open(self.manage_customer_path)
329        image = open(SAMPLE_IMAGE_BMP, 'rb')
330        ctrl = self.browser.getControl(name='passportuploadmanage')
331        file_ctrl = ctrl.mech_control
332        file_ctrl.add_file(image, filename='my_photo.bmp')
333        self.browser.getControl(
334            name='upload_passportuploadmanage').click()
335        self.assertTrue('jpg file extension expected'
336            in self.browser.contents)
337        ctrl = self.browser.getControl(name='passportuploadmanage')
338        file_ctrl = ctrl.mech_control
339        image = open(SAMPLE_IMAGE, 'rb')
340        file_ctrl.add_file(image, filename='my_photo.jpg')
341        self.browser.getControl(
342            name='upload_passportuploadmanage').click()
343        self.assertTrue(
344            'src="http://localhost/app/customers/K1000000/passport.jpg"'
345            in self.browser.contents)
346        # We remove the passport file again
347        self.browser.open(self.manage_customer_path)
348        self.browser.getControl('Delete').click()
349        self.assertTrue('passport.jpg deleted' in self.browser.contents)
350
351
352    def test_manage_workflow(self):
353        # Managers can pass through the whole workflow
354        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
355        customer = self.app['customers'][self.customer_id]
356        self.browser.open(self.trigtrans_path)
357        self.browser.getControl(name="transition").value = ['start']
358        self.browser.getControl("Save").click()
359        self.browser.getControl(name="transition").value = ['request']
360        self.browser.getControl("Save").click()
361        self.browser.getControl(name="transition").value = ['reject']
362        self.browser.getControl("Save").click()
363        self.browser.getControl(name="transition").value = ['request']
364        self.browser.getControl("Save").click()
365        self.browser.getControl(name="transition").value = ['approve']
366        self.browser.getControl("Save").click()
367        self.browser.getControl(name="transition").value = ['reset1']
368        self.browser.getControl("Save").click()
369        return
370
371    def test_manage_import(self):
372        # Managers can import customer data files
373        datacenter_path = 'http://localhost/app/datacenter'
374        # Prepare a csv file for customers
375        open('customers.csv', 'wb').write(
376"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
377Aaren,Pieri,1,1990-01-02,aa@aa.ng,1234,m,mypwd1
378Claus,Finau,2,1990-01-03,aa@aa.ng,1234,m,mypwd1
379Brit,Berson,2,1990-01-04,aa@aa.ng,1234,m,mypwd1
380""")
381        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
382        self.browser.open(datacenter_path)
383        self.browser.getLink('Upload data').click()
384        filecontents = StringIO(open('customers.csv', 'rb').read())
385        filewidget = self.browser.getControl(name='uploadfile:file')
386        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
387        self.browser.getControl(name='SUBMIT').click()
388        self.browser.getLink('Process data').click()
389        button = lookup_submit_value(
390            'select', 'customers_zope.mgr.csv', self.browser)
391        button.click()
392        importerselect = self.browser.getControl(name='importer')
393        modeselect = self.browser.getControl(name='mode')
394        importerselect.getControl('Customer Processor').selected = True
395        modeselect.getControl(value='create').selected = True
396        self.browser.getControl('Proceed to step 3').click()
397        self.assertTrue('Header fields OK' in self.browser.contents)
398        self.browser.getControl('Perform import').click()
399        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
400        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
401        self.assertTrue('Batch processing finished' in self.browser.contents)
402
403        # The customers are properly indexed and we can
404        # thus find a customer in  the department
405        self.browser.open(self.manage_container_path)
406        # We can search for a new customer by name ...
407        self.browser.getControl(name="searchtype").value = ['fullname']
408        self.browser.getControl(name="searchterm").value = 'Claus'
409        self.browser.getControl("Find customer(s)").click()
410        self.assertTrue('Claus Finau' in self.browser.contents)
411        # ... and check if the imported password has been properly set
412        ctrl = self.browser.getControl(name='entries')
413        value = ctrl.options[0]
414        claus = self.app['customers'][value]
415        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
416        return
417
418    def test_activate_deactivate_buttons(self):
419        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
420        self.browser.open(self.customer_path)
421        self.browser.getLink("Deactivate").click()
422        self.assertTrue(
423            'Customer account has been deactivated.' in self.browser.contents)
424        self.assertTrue(
425            'Base Data (account deactivated)' in self.browser.contents)
426        self.assertTrue(self.customer.suspended)
427        self.browser.getLink("Activate").click()
428        self.assertTrue(
429            'Customer account has been activated.' in self.browser.contents)
430        self.assertFalse(
431            'Base Data (account deactivated)' in self.browser.contents)
432        self.assertFalse(self.customer.suspended)
433        # History messages have been added ...
434        self.browser.getLink("History").click()
435        self.assertTrue(
436            'Customer account deactivated by Manager<br />' in self.browser.contents)
437        self.assertTrue(
438            'Customer account activated by Manager<br />' in self.browser.contents)
439        # ... and actions have been logged.
440        logfile = os.path.join(
441            self.app['datacenter'].storage, 'logs', 'customers.log')
442        logcontent = open(logfile).read()
443        self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - '
444                        'K1000000 - account deactivated' in logcontent)
445        self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - '
446                        'K1000000 - account activated' in logcontent)
447
448
449    def test_login_as_customer(self):
450        # CustomerImpersonators can login as customer
451        # Create clearance officer
452        self.app['users'].addUser('mrofficer', 'mrofficersecret')
453        self.app['users']['mrofficer'].email = 'mrofficer@foo.ng'
454        self.app['users']['mrofficer'].title = 'Harry Actor'
455        prmglobal = IPrincipalRoleManager(self.app)
456        prmglobal.assignRoleToPrincipal('waeup.CustomerImpersonator', 'mrofficer')
457        prmglobal.assignRoleToPrincipal('waeup.CustomersManager', 'mrofficer')
458        # Login as customer impersonator
459        self.browser.open(self.login_path)
460        self.browser.getControl(name="form.login").value = 'mrofficer'
461        self.browser.getControl(name="form.password").value = 'mrofficersecret'
462        self.browser.getControl("Login").click()
463        self.assertMatches('...You logged in...', self.browser.contents)
464        self.browser.open(self.customer_path)
465        self.browser.getLink("Login as").click()
466        self.browser.getControl("Set password now").click()
467        temp_password = self.browser.getControl(name='form.password').value
468        self.browser.getControl("Login now").click()
469        self.assertMatches(
470            '...You successfully logged in as...', self.browser.contents)
471        # We are logged in as customer and can see the 'My Data' tab
472        self.assertMatches(
473            '...<a href="#" class="dropdown-toggle" data-toggle="dropdown">...',
474            self.browser.contents)
475        self.assertMatches(
476            '...My Data...',
477            self.browser.contents)
478        self.browser.getLink("Logout").click()
479        # The customer can't login with the original password ...
480        self.browser.open(self.login_path)
481        self.browser.getControl(name="form.login").value = self.customer_id
482        self.browser.getControl(name="form.password").value = 'spwd'
483        self.browser.getControl("Login").click()
484        self.assertMatches(
485            '...Your account has been temporarily deactivated...',
486            self.browser.contents)
487        # ... but with the temporary password
488        self.browser.open(self.login_path)
489        self.browser.getControl(name="form.login").value = self.customer_id
490        self.browser.getControl(name="form.password").value = temp_password
491        self.browser.getControl("Login").click()
492        self.assertMatches('...You logged in...', self.browser.contents)
493        # Creation of temp_password is properly logged
494        logfile = os.path.join(
495            self.app['datacenter'].storage, 'logs', 'customers.log')
496        logcontent = open(logfile).read()
497        self.assertTrue(
498            'mrofficer - customers.browser.LoginAsCustomerStep1 - K1000000 - '
499            'temp_password generated: %s' % temp_password in logcontent)
500
501class CustomerUITests(CustomersFullSetup):
502    # Tests for Customer class views and pages
503
504    def test_customer_change_password(self):
505        # Customers can change the password
506        self.customer.personal_updated = datetime.utcnow()
507        self.browser.open(self.login_path)
508        self.browser.getControl(name="form.login").value = self.customer_id
509        self.browser.getControl(name="form.password").value = 'spwd'
510        self.browser.getControl("Login").click()
511        self.assertEqual(self.browser.url, self.customer_path)
512        self.assertTrue('You logged in' in self.browser.contents)
513        # Change password
514        self.browser.getLink("Change password").click()
515        self.browser.getControl(name="change_password").value = 'pw'
516        self.browser.getControl(
517            name="change_password_repeat").value = 'pw'
518        self.browser.getControl("Save").click()
519        self.assertTrue('Password must have at least' in self.browser.contents)
520        self.browser.getControl(name="change_password").value = 'new_password'
521        self.browser.getControl(
522            name="change_password_repeat").value = 'new_passssword'
523        self.browser.getControl("Save").click()
524        self.assertTrue('Passwords do not match' 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_password'
528        self.browser.getControl("Save").click()
529        self.assertTrue('Password changed' in self.browser.contents)
530        # We are still logged in. Changing the password hasn't thrown us out.
531        self.browser.getLink("Base Data").click()
532        self.assertEqual(self.browser.url, self.customer_path)
533        # We can logout
534        self.browser.getLink("Logout").click()
535        self.assertTrue('You have been logged out' in self.browser.contents)
536        self.assertEqual(self.browser.url, 'http://localhost/app/index')
537        # We can login again with the new password
538        self.browser.getLink("Login").click()
539        self.browser.open(self.login_path)
540        self.browser.getControl(name="form.login").value = self.customer_id
541        self.browser.getControl(name="form.password").value = 'new_password'
542        self.browser.getControl("Login").click()
543        self.assertEqual(self.browser.url, self.customer_path)
544        self.assertTrue('You logged in' in self.browser.contents)
545        return
546
547    def test_customer_upload_passport(self):
548        # Customer cant login if their password is not set
549        IWorkflowInfo(self.customer).fireTransition('start')
550        self.browser.open(self.login_path)
551        self.browser.getControl(name="form.login").value = self.customer_id
552        self.browser.getControl(name="form.password").value = 'spwd'
553        self.browser.getControl("Login").click()
554        self.assertMatches(
555            '...You logged in...', self.browser.contents)
556        # Admitted customer can upload a passport picture
557        self.browser.getLink("Change portrait").click()
558        ctrl = self.browser.getControl(name='passportuploadedit')
559        file_obj = open(SAMPLE_IMAGE, 'rb')
560        file_ctrl = ctrl.mech_control
561        file_ctrl.add_file(file_obj, filename='my_photo.jpg')
562        self.browser.getControl(
563            name='upload_passportuploadedit').click()
564        self.assertTrue(
565            'src="http://localhost/app/customers/K1000000/passport.jpg"'
566            in self.browser.contents)
567
568    def test_customer_baseedit(self):
569        # Customers can change the password
570        self.customer.personal_updated = datetime.utcnow()
571        self.browser.open(self.login_path)
572        self.browser.getControl(name="form.login").value = self.customer_id
573        self.browser.getControl(name="form.password").value = 'spwd'
574        self.browser.getControl("Login").click()
575        self.assertEqual(self.browser.url, self.customer_path)
576        self.assertTrue('You logged in' in self.browser.contents)
577        self.browser.getLink("Edit").click()
578        self.browser.getControl(name="form.email").value = 'new_email@aa.ng'
579        self.browser.getControl("Save").click()
580        self.assertMatches('...Form has been saved...',
581                           self.browser.contents)
582        # Customer can view history
583        self.browser.getLink("History").click()
584        self.assertMatches('...Customer record created by system...',
585            self.browser.contents)
586
587    def test_customer_login(self):
588        # Customer cant login if their password is not set
589        self.customer.password = None
590        self.browser.open(self.login_path)
591        self.browser.getControl(name="form.login").value = self.customer_id
592        self.browser.getControl(name="form.password").value = 'spwd'
593        self.browser.getControl("Login").click()
594        self.assertTrue(
595            'You entered invalid credentials.' in self.browser.contents)
596        # We set the password again
597        IUserAccount(
598            self.app['customers'][self.customer_id]).setPassword('spwd')
599        # Customers can't login if their account is suspended/deactivated
600        self.customer.suspended = True
601        self.browser.open(self.login_path)
602        self.browser.getControl(name="form.login").value = self.customer_id
603        self.browser.getControl(name="form.password").value = 'spwd'
604        self.browser.getControl("Login").click()
605        self.assertMatches(
606            '...<div class="alert alert-warning">'
607            'Your account has been deactivated.</div>...', self.browser.contents)
608        # If suspended_comment is set this message will be flashed instead
609        self.customer.suspended_comment = u'Aetsch baetsch!'
610        self.browser.getControl(name="form.login").value = self.customer_id
611        self.browser.getControl(name="form.password").value = 'spwd'
612        self.browser.getControl("Login").click()
613        self.assertMatches(
614            '...<div class="alert alert-warning">Aetsch baetsch!</div>...',
615            self.browser.contents)
616        self.customer.suspended = False
617        # Customers can't login if a temporary password has been set and
618        # is not expired
619        self.app['customers'][self.customer_id].setTempPassword(
620            'anybody', 'temp_spwd')
621        self.browser.open(self.login_path)
622        self.browser.getControl(name="form.login").value = self.customer_id
623        self.browser.getControl(name="form.password").value = 'spwd'
624        self.browser.getControl("Login").click()
625        self.assertMatches(
626            '...Your account has been temporarily deactivated...',
627            self.browser.contents)
628        # The customer can login with the temporary password
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 = 'temp_spwd'
632        self.browser.getControl("Login").click()
633        self.assertMatches(
634            '...You logged in...', self.browser.contents)
635        # Customer can view the base data
636        self.browser.open(self.customer_path)
637        self.assertEqual(self.browser.headers['Status'], '200 Ok')
638        self.assertEqual(self.browser.url, self.customer_path)
639        # When the password expires ...
640        delta = timedelta(minutes=11)
641        self.app['customers'][self.customer_id].temp_password[
642            'timestamp'] = datetime.utcnow() - delta
643        self.app['customers'][self.customer_id]._p_changed = True
644        # ... the customer will be automatically logged out
645        self.assertRaises(
646            Unauthorized, self.browser.open, self.customer_path)
647        # Then the customer can login with the original password
648        self.browser.open(self.login_path)
649        self.browser.getControl(name="form.login").value = self.customer_id
650        self.browser.getControl(name="form.password").value = 'spwd'
651        self.browser.getControl("Login").click()
652        self.assertMatches(
653            '...You logged in...', self.browser.contents)
654
655    def test_change_password_request(self):
656        self.browser.open('http://localhost/app/changepw')
657        self.browser.getControl(name="form.identifier").value = '123'
658        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
659        self.browser.getControl("Send login credentials").click()
660        self.assertTrue('An email with' in self.browser.contents)
661
662class CustomerRequestPWTests(CustomersFullSetup):
663    # Tests for customer registration
664
665    layer = FunctionalLayer
666
667    def test_request_pw(self):
668        # Customer with wrong number can't be found.
669        self.browser.open('http://localhost/app/requestpw')
670        self.browser.getControl(name="form.firstname").value = 'Anna'
671        self.browser.getControl(name="form.number").value = 'anynumber'
672        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
673        self.browser.getControl("Send login credentials").click()
674        self.assertTrue('No customer record found.'
675            in self.browser.contents)
676        # Anonymous is not informed that firstname verification failed.
677        # It seems that the record doesn't exist.
678        self.browser.open('http://localhost/app/requestpw')
679        self.browser.getControl(name="form.firstname").value = 'Johnny'
680        self.browser.getControl(name="form.number").value = '123'
681        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
682        self.browser.getControl("Send login credentials").click()
683        self.assertTrue('No customer record found.'
684            in self.browser.contents)
685        # Even with the correct firstname we can't register if a
686        # password has been set and used.
687        self.browser.getControl(name="form.firstname").value = 'Anna'
688        self.browser.getControl(name="form.number").value = '123'
689        self.browser.getControl("Send login credentials").click()
690        self.assertTrue('Your password has already been set and used.'
691            in self.browser.contents)
692        self.browser.open('http://localhost/app/requestpw')
693        self.app['customers'][self.customer_id].password = None
694        # The firstname field, used for verification, is not case-sensitive.
695        self.browser.getControl(name="form.firstname").value = 'aNNa'
696        self.browser.getControl(name="form.number").value = '123'
697        self.browser.getControl(name="form.email").value = 'new@yy.zz'
698        self.browser.getControl("Send login credentials").click()
699        # Yeah, we succeded ...
700        self.assertTrue('Your password request was successful.'
701            in self.browser.contents)
702        # ... and  customer can be found in the catalog via the email address
703        cat = queryUtility(ICatalog, name='customers_catalog')
704        results = list(
705            cat.searchResults(
706            email=('new@yy.zz', 'new@yy.zz')))
707        self.assertEqual(self.customer,results[0])
708        logfile = os.path.join(
709            self.app['datacenter'].storage, 'logs', 'main.log')
710        logcontent = open(logfile).read()
711        self.assertTrue('zope.anybody - customers.browser.CustomerRequestPasswordPage - '
712                        '123 (K1000000) - new@yy.zz' in logcontent)
713        return
714
715class CustomerDataExportTests(CustomersFullSetup, FunctionalAsyncTestCase):
716    # Tests for CustomersContainer class views and pages
717
718    layer = FunctionalLayer
719
720    def wait_for_export_job_completed(self):
721        # helper function waiting until the current export job is completed
722        manager = getUtility(IJobManager)
723        job_id = self.app['datacenter'].running_exports[0][0]
724        job = manager.get(job_id)
725        wait_for_result(job)
726        return job_id
727
728    def test_datacenter_export(self):
729        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
730        self.browser.open('http://localhost/app/datacenter/@@export')
731        self.browser.getControl(name="exporter").value = ['customers']
732        self.browser.getControl("Create CSV file").click()
733
734        # When the job is finished and we reload the page...
735        job_id = self.wait_for_export_job_completed()
736        # ... the csv file can be downloaded ...
737        self.browser.open('http://localhost/app/datacenter/@@export')
738        self.browser.getLink("Download").click()
739        self.assertEqual(self.browser.headers['content-type'],
740            'text/csv; charset=UTF-8')
741        self.assertTrue(
742            'filename="WAeUP.Ikoba_customers_%s.csv' % job_id in
743            self.browser.headers['content-disposition'])
744        self.assertEqual(len(self.app['datacenter'].running_exports), 1)
745        job_id = self.app['datacenter'].running_exports[0][0]
746        # ... and discarded
747        self.browser.open('http://localhost/app/datacenter/@@export')
748        self.browser.getControl("Discard").click()
749        self.assertEqual(len(self.app['datacenter'].running_exports), 0)
750        # Creation, downloading and discarding is logged
751        logfile = os.path.join(
752            self.app['datacenter'].storage, 'logs', 'datacenter.log')
753        logcontent = open(logfile).read()
754        self.assertTrue(
755            'zope.mgr - browser.pages.ExportCSVPage - exported: '
756            'customers, job_id=%s'
757            % job_id in logcontent
758            )
759        self.assertTrue(
760            'zope.mgr - browser.pages.ExportCSVView - downloaded: '
761            'WAeUP.Ikoba_customers_%s.csv, job_id=%s'
762            % (job_id, job_id) in logcontent
763            )
764        self.assertTrue(
765            'zope.mgr - browser.pages.ExportCSVPage - discarded: '
766            'job_id=%s' % job_id in logcontent
767            )
Note: See TracBrowser for help on using the repository browser.