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

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

Add second customer document class.
Select document factory when adding documents.
Add last_transition_date attribute and further property attributes to documents.

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