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

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

Adjust UI components in documents and customers package.

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