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

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

Catch InvalidTransitionError? in UI.

  • Property svn:keywords set to Id
File size: 62.2 KB
Line 
1## $Id: test_browser.py 12151 2014-12-05 15:43:24Z 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)
46from waeup.ikoba.authentication import LocalRoleSetEvent
47from waeup.ikoba.tests.test_async import FunctionalAsyncTestCase
48from waeup.ikoba.documents.workflow import VERIFIED
49from waeup.ikoba.browser.tests.test_pdf import samples_dir
50
51PH_LEN = 15911  # Length of placeholder file
52
53SAMPLE_IMAGE = os.path.join(os.path.dirname(__file__), 'test_image.jpg')
54SAMPLE_IMAGE_BMP = os.path.join(os.path.dirname(__file__), 'test_image.bmp')
55SAMPLE_PDF = os.path.join(os.path.dirname(__file__), 'test_pdf.pdf')
56
57def lookup_submit_value(name, value, browser):
58    """Find a button with a certain value."""
59    for num in range(0, 100):
60        try:
61            button = browser.getControl(name=name, index=num)
62            if button.value.endswith(value):
63                return button
64        except IndexError:
65            break
66    return None
67
68class CustomersFullSetup(FunctionalTestCase):
69    # A test case that only contains a setup and teardown
70    #
71    # Complete setup for customers handlings is rather complex and
72    # requires lots of things created before we can start. This is a
73    # setup that does all this, creates a company etc.
74    # so that we do not have to bother with that in different
75    # test cases.
76
77    layer = FunctionalLayer
78
79    def setUp(self):
80        super(CustomersFullSetup, self).setUp()
81
82        # Setup a sample site for each test
83        app = Company()
84        self.dc_root = tempfile.mkdtemp()
85        app['datacenter'].setStoragePath(self.dc_root)
86
87        # Prepopulate the ZODB...
88        self.getRootFolder()['app'] = app
89        # we add the site immediately after creation to the
90        # ZODB. Catalogs and other local utilities are not setup
91        # before that step.
92        self.app = self.getRootFolder()['app']
93        # Set site here. Some of the following setup code might need
94        # to access grok.getSite() and should get our new app then
95        setSite(app)
96
97        # Add some products
98        self.product = createObject('waeup.Product')
99        self.product.product_id = u'SAM'
100        self.product.title = u'Our Samle Product'
101        self.product.contract_category = u'sample'
102        self.app['products'].addProduct(self.product)
103
104        # Add customer with subobjects
105        customer = createObject('waeup.Customer')
106        customer.firstname = u'Anna'
107        customer.lastname = u'Tester'
108        customer.reg_number = u'123'
109        customer.sex = u'm'
110        customer.email = 'aa@aa.ng'
111        customer.phone = u'1234'
112        customer.date_of_birth = date(1981, 2, 4)
113        self.app['customers'].addCustomer(customer)
114        self.customer_id = customer.customer_id
115        self.customer = self.app['customers'][self.customer_id]
116        self.document = createObject('waeup.CustomerSampleDocument')
117        self.document.title = u'My first document'
118        self.customer['documents'].addDocument(self.document)
119        self.contract = createObject('waeup.SampleContract')
120        self.contract.title = u'My first contract'
121        self.customer['contracts'].addContract(self.contract)
122
123        # Set password
124        IUserAccount(
125            self.app['customers'][self.customer_id]).setPassword('cpwd')
126
127        self.login_path = 'http://localhost/app/login'
128        self.container_path = 'http://localhost/app/customers'
129        self.manage_container_path = self.container_path + '/@@manage'
130        self.add_customer_path = self.container_path + '/addcustomer'
131        self.customer_path = self.container_path + '/' + self.customer_id
132        self.manage_customer_path = self.customer_path + '/manage_base'
133        self.trigtrans_path = self.customer_path + '/trigtrans'
134        self.history_path = self.customer_path + '/history'
135        self.documents_path = self.customer_path + '/documents'
136        self.contracts_path = self.customer_path + '/contracts'
137
138        self.app['configuration'].carry_over = True
139        configuration = createObject('waeup.SessionConfiguration')
140        self.app['configuration'].addSessionConfiguration(configuration)
141
142        # Update the catalog
143        notify(grok.ObjectModifiedEvent(self.customer))
144
145        # Put the prepopulated site into test ZODB and prepare test
146        # browser
147        self.browser = Browser()
148        self.browser.handleErrors = False
149
150    def tearDown(self):
151        super(CustomersFullSetup, self).tearDown()
152        clearSite()
153        shutil.rmtree(self.dc_root)
154
155
156
157class CustomersContainerUITests(CustomersFullSetup):
158    # Tests for CustomersContainer class views and pages
159
160    layer = FunctionalLayer
161
162    def test_anonymous_access(self):
163        # Anonymous users can't access customers containers
164        self.assertRaises(
165            Unauthorized, self.browser.open, self.container_path)
166        self.assertRaises(
167            Unauthorized, self.browser.open, self.manage_container_path)
168        return
169
170    def test_manage_access(self):
171        # Managers can access the view page of customers
172        # containers and can perform actions
173        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
174        self.browser.open(self.container_path)
175        self.assertEqual(self.browser.headers['Status'], '200 Ok')
176        self.assertEqual(self.browser.url, self.container_path)
177        self.browser.getLink("Manage customer section").click()
178        self.assertEqual(self.browser.headers['Status'], '200 Ok')
179        self.assertEqual(self.browser.url, self.manage_container_path)
180        return
181
182    def test_add_search_delete_customers(self):
183        # Managers can add search and remove customers
184        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
185        self.browser.open(self.manage_container_path)
186        self.browser.getLink("Add customer").click()
187        self.assertEqual(self.browser.headers['Status'], '200 Ok')
188        self.assertEqual(self.browser.url, self.add_customer_path)
189        self.browser.getControl(name="form.firstname").value = 'Bob'
190        self.browser.getControl(name="form.lastname").value = 'Tester'
191        self.browser.getControl(name="form.reg_number").value = '123'
192        self.browser.getControl("Create customer record").click()
193        self.assertTrue('Registration number exists already'
194            in self.browser.contents)
195        self.browser.getControl(name="form.reg_number").value = '1234'
196        self.browser.getControl("Create customer record").click()
197        self.assertTrue('Customer record created' in self.browser.contents)
198
199        # Registration must be unique
200        self.browser.getLink("Manage").click()
201        self.browser.getControl(name="form.reg_number").value = '123'
202        self.browser.getControl("Save").click()
203        self.assertMatches('...Registration number exists...',
204                           self.browser.contents)
205
206        # We can find a customer with a certain customer_id
207        self.browser.open(self.container_path)
208        self.browser.getControl("Find customer(s)").click()
209        self.assertTrue('Empty search string' in self.browser.contents)
210        self.browser.getControl(name="searchtype").value = ['customer_id']
211        self.browser.getControl(name="searchterm").value = self.customer_id
212        self.browser.getControl("Find customer(s)").click()
213        self.assertTrue('Anna Tester' in self.browser.contents)
214
215        # We can find a customer by searching for all kind of name parts
216        self.browser.open(self.manage_container_path)
217        self.browser.getControl("Find customer(s)").click()
218        self.assertTrue('Empty search string' in self.browser.contents)
219        self.browser.getControl(name="searchtype").value = ['fullname']
220        self.browser.getControl(name="searchterm").value = 'Anna Tester'
221        self.browser.getControl("Find customer(s)").click()
222        self.assertTrue('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 = 'Anna'
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 = 'An'
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 = 'An*'
241        self.browser.getControl("Find customer(s)").click()
242        self.assertTrue('Anna Tester' in self.browser.contents)
243        self.browser.open(self.manage_container_path)
244        self.browser.getControl(name="searchtype").value = ['fullname']
245        self.browser.getControl(name="searchterm").value = 'tester'
246        self.browser.getControl("Find customer(s)").click()
247        self.assertTrue('Anna Tester' in self.browser.contents)
248        self.browser.open(self.manage_container_path)
249        self.browser.getControl(name="searchtype").value = ['fullname']
250        self.browser.getControl(name="searchterm").value = 'Tester Ana'
251        self.browser.getControl("Find customer(s)").click()
252        self.assertFalse('Anna Tester' in self.browser.contents)
253        self.browser.open(self.manage_container_path)
254        self.browser.getControl(name="searchtype").value = ['fullname']
255        self.browser.getControl(name="searchterm").value = 'Tester Anna'
256        self.browser.getControl("Find customer(s)").click()
257        self.assertTrue('Anna Tester' in self.browser.contents)
258        # The old searchterm will be used again
259        self.browser.getControl("Find customer(s)").click()
260        self.assertTrue('Anna Tester' in self.browser.contents)
261
262        # We can find suspended customers
263        self.customer.suspended = True
264        notify(grok.ObjectModifiedEvent(self.customer))
265        self.browser.open(self.manage_container_path)
266        self.browser.getControl(name="searchtype").value = ['suspended']
267        self.browser.getControl("Find customer(s)").click()
268        self.assertTrue('Anna Tester' in self.browser.contents)
269
270        # Removed customers won't be found
271        ctrl = self.browser.getControl(name='entries')
272        ctrl.getControl(value=self.customer_id).selected = True
273        self.browser.getControl("Remove selected", index=0).click()
274        self.assertTrue('Successfully removed' in self.browser.contents)
275        self.browser.getControl(name="searchtype").value = ['customer_id']
276        self.browser.getControl(name="searchterm").value = self.customer_id
277        self.browser.getControl("Find customer(s)").click()
278        self.assertTrue('No customer found' in self.browser.contents)
279        return
280
281class OfficerUITests(CustomersFullSetup):
282    # Tests for Customer class views and pages
283
284    def test_basic_auth(self):
285        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
286        self.browser.open('http://localhost/app')
287        self.browser.getLink("Logout").click()
288        self.assertTrue('You have been logged out' in self.browser.contents)
289        # But we are still logged in since we've used basic authentication here.
290        # Wikipedia says: Existing browsers retain authentication information
291        # until the tab or browser is closed or the user clears the history.
292        # HTTP does not provide a method for a server to direct clients to
293        # discard these cached credentials. This means that there is no
294        # effective way for a server to "log out" the user without closing
295        # the browser. This is a significant defect that requires browser
296        # manufacturers to support a "logout" user interface element ...
297        self.assertTrue('Manager' in self.browser.contents)
298
299    def test_basic_auth_base64(self):
300        auth_token = base64.b64encode('mgr:mgrpw')
301        self.browser.addHeader('Authorization', 'Basic %s' % auth_token)
302        self.browser.open(self.manage_container_path)
303        self.assertEqual(self.browser.headers['Status'], '200 Ok')
304
305    def test_manage_access(self):
306        # Managers can access the pages of customers
307        # and can perform actions
308        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
309        self.browser.open(self.customer_path)
310        self.assertEqual(self.browser.headers['Status'], '200 Ok')
311        self.assertEqual(self.browser.url, self.customer_path)
312        self.browser.getLink("Transition").click()
313        self.assertEqual(self.browser.headers['Status'], '200 Ok')
314        # Managers can trigger transitions
315        self.browser.getControl(name="transition").value = ['start']
316        self.browser.getControl("Save").click()
317        # Managers can edit base
318        self.browser.open(self.customer_path)
319        self.browser.getLink("Manage").click()
320        self.assertEqual(self.browser.url, self.manage_customer_path)
321        self.assertEqual(self.browser.headers['Status'], '200 Ok')
322        self.browser.getControl(name="form.firstname").value = 'John'
323        self.browser.getControl(name="form.lastname").value = 'Tester'
324        self.browser.getControl(name="form.reg_number").value = '345'
325        self.browser.getControl(name="password").value = 'secret'
326        self.browser.getControl(name="control_password").value = 'secret'
327        self.browser.getControl("Save").click()
328        self.assertMatches('...Form has been saved...',
329                           self.browser.contents)
330
331    def test_manage_contact_customer(self):
332        # Managers can contact customer
333        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
334        self.customer.email = None
335        self.browser.open(self.customer_path)
336        self.browser.getLink("Send email").click()
337        self.browser.getControl(name="form.subject").value = 'Important subject'
338        self.browser.getControl(name="form.body").value = 'Hello!'
339        self.browser.getControl("Send message now").click()
340        self.assertTrue('An smtp server error occurred' in self.browser.contents)
341        self.customer.email = 'xx@yy.zz'
342        self.browser.getControl("Send message now").click()
343        self.assertTrue('Your message has been sent' in self.browser.contents)
344        return
345
346    def test_manage_upload_passport(self):
347        # Managers can upload a file via the CustomerBaseManageFormPage
348        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
349        self.browser.open(self.manage_customer_path)
350        image = open(SAMPLE_IMAGE_BMP, 'rb')
351        ctrl = self.browser.getControl(name='passportmanageupload')
352        file_ctrl = ctrl.mech_control
353        file_ctrl.add_file(image, filename='my_photo.bmp')
354        self.browser.getControl(
355            name='upload_passportmanageupload').click()
356        self.assertTrue('jpg file extension expected'
357            in self.browser.contents)
358        ctrl = self.browser.getControl(name='passportmanageupload')
359        file_ctrl = ctrl.mech_control
360        image = open(SAMPLE_IMAGE, 'rb')
361        file_ctrl.add_file(image, filename='my_photo.jpg')
362        self.browser.getControl(
363            name='upload_passportmanageupload').click()
364        self.assertTrue(
365            'src="http://localhost/app/customers/K1000000/passport.jpg"'
366            in self.browser.contents)
367        # We remove the passport file again
368        self.browser.open(self.manage_customer_path)
369        self.browser.getControl('Delete').click()
370        self.assertTrue('passport.jpg deleted' in self.browser.contents)
371
372
373    def test_manage_workflow(self):
374        # Managers can pass through the whole workflow
375        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
376        customer = self.app['customers'][self.customer_id]
377        self.browser.open(self.trigtrans_path)
378        self.browser.getControl(name="transition").value = ['start']
379        self.browser.getControl("Save").click()
380        self.browser.getControl(name="transition").value = ['request']
381        self.browser.getControl("Save").click()
382        self.browser.getControl(name="transition").value = ['reject']
383        self.browser.getControl("Save").click()
384        self.browser.getControl(name="transition").value = ['request']
385        self.browser.getControl("Save").click()
386        self.browser.getControl(name="transition").value = ['approve']
387        self.browser.getControl("Save").click()
388        self.browser.getControl(name="transition").value = ['reset1']
389        self.browser.getControl("Save").click()
390        return
391
392    def test_manage_import(self):
393        # Managers can import customer data files
394        datacenter_path = 'http://localhost/app/datacenter'
395        # Prepare a csv file for customers
396        open('customers.csv', 'wb').write(
397"""firstname,lastname,reg_number,date_of_birth,email,phone,sex,password
398Aaren,Pieri,1,1990-01-02,aa@aa.ng,1234,m,mypwd1
399Claus,Finau,2,1990-01-03,aa@aa.ng,1234,m,mypwd1
400Brit,Berson,2,1990-01-04,aa@aa.ng,1234,m,mypwd1
401""")
402        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
403        self.browser.open(datacenter_path)
404        self.browser.getLink('Upload data').click()
405        filecontents = StringIO(open('customers.csv', 'rb').read())
406        filewidget = self.browser.getControl(name='uploadfile:file')
407        filewidget.add_file(filecontents, 'text/plain', 'customers.csv')
408        self.browser.getControl(name='SUBMIT').click()
409        self.browser.getLink('Process data').click()
410        button = lookup_submit_value(
411            'select', 'customers_zope.mgr.csv', self.browser)
412        button.click()
413        importerselect = self.browser.getControl(name='importer')
414        modeselect = self.browser.getControl(name='mode')
415        importerselect.getControl('Customer Processor').selected = True
416        modeselect.getControl(value='create').selected = True
417        self.browser.getControl('Proceed to step 3').click()
418        self.assertTrue('Header fields OK' in self.browser.contents)
419        self.browser.getControl('Perform import').click()
420        self.assertTrue('Processing of 1 rows failed' in self.browser.contents)
421        self.assertTrue('Successfully processed 2 rows' in self.browser.contents)
422        self.assertTrue('Batch processing finished' in self.browser.contents)
423
424        # The customers are properly indexed and we can
425        # thus find a customer in  the department
426        self.browser.open(self.manage_container_path)
427        # We can search for a new customer by name ...
428        self.browser.getControl(name="searchtype").value = ['fullname']
429        self.browser.getControl(name="searchterm").value = 'Claus'
430        self.browser.getControl("Find customer(s)").click()
431        self.assertTrue('Claus Finau' in self.browser.contents)
432        # ... and check if the imported password has been properly set
433        ctrl = self.browser.getControl(name='entries')
434        value = ctrl.options[0]
435        claus = self.app['customers'][value]
436        self.assertTrue(IUserAccount(claus).checkPassword('mypwd1'))
437        return
438
439    def test_activate_deactivate_buttons(self):
440        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
441        self.browser.open(self.customer_path)
442        self.browser.getLink("Deactivate").click()
443        self.assertTrue(
444            'Customer account has been deactivated.' in self.browser.contents)
445        self.assertTrue(
446            'Base Data (account deactivated)' in self.browser.contents)
447        self.assertTrue(self.customer.suspended)
448        self.browser.getLink("Activate").click()
449        self.assertTrue(
450            'Customer account has been activated.' in self.browser.contents)
451        self.assertFalse(
452            'Base Data (account deactivated)' in self.browser.contents)
453        self.assertFalse(self.customer.suspended)
454        # History messages have been added ...
455        self.browser.getLink("History").click()
456        self.assertTrue(
457            'Customer account deactivated by Manager<br />' in self.browser.contents)
458        self.assertTrue(
459            'Customer account activated by Manager<br />' in self.browser.contents)
460        # ... and actions have been logged.
461        logfile = os.path.join(
462            self.app['datacenter'].storage, 'logs', 'customers.log')
463        logcontent = open(logfile).read()
464        self.assertTrue('zope.mgr - customers.browser.CustomerDeactivatePage - '
465                        'K1000000 - account deactivated' in logcontent)
466        self.assertTrue('zope.mgr - customers.browser.CustomerActivatePage - '
467                        'K1000000 - account activated' in logcontent)
468
469
470    def test_login_as_customer(self):
471        # CustomerImpersonators can login as customer
472        # Create clearance officer
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").click()
828        self.browser.getLink("Add document").click()
829        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
830        self.browser.getControl("Create document").click()
831        self.assertTrue('PDF Document created.' 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        self.browser.getControl(name="transition").value = ['verify']
848        self.browser.getControl("Save").click()
849        self.assertEqual(document.state, 'verified')
850
851        # Documents can be removed
852        self.browser.getLink("Documents").click()
853        ctrl = self.browser.getControl(name='val_id')
854        ctrl.getControl(value=document.document_id).selected = True
855        self.browser.getControl("Remove selected", index=0).click()
856        self.assertTrue('Successfully removed' in self.browser.contents)
857
858        # All actions are being logged
859        logfile = os.path.join(
860            self.app['datacenter'].storage, 'logs', 'customers.log')
861        logcontent = open(logfile).read()
862
863        self.assertTrue(
864            'INFO - zope.mgr - customers.browser.DocumentManageFormPage '
865            '- K1000000 - d102 - saved: title'
866            in logcontent)
867        self.assertTrue(
868            'INFO - zope.mgr - customers.browser.DocumentAddFormPage '
869            '- K1000000 - added: PDF Document %s'
870            % document.document_id in logcontent)
871        self.assertTrue(
872            'INFO - zope.mgr - customers.browser.DocumentsManageFormPage '
873            '- K1000000 - removed: %s'
874            % document.document_id in logcontent)
875
876    def test_edit_sample_document(self):
877        # Customers can manage documents under certain conditions
878        self.browser.open(self.login_path)
879        self.browser.getControl(name="form.login").value = self.customer_id
880        self.browser.getControl(name="form.password").value = 'cpwd'
881        self.browser.getControl("Login").click()
882        self.assertMatches(
883            '...You logged in...', self.browser.contents)
884        self.browser.getLink("Documents").click()
885        self.browser.getLink("Add document").click()
886        self.browser.getControl(name="doctype").value = ['CustomerSampleDocument']
887        self.browser.getControl("Create document").click()
888        self.assertTrue('Sample Document created.' in self.browser.contents)
889        document = self.customer['documents']['d102']
890
891        # Document can be edited ...
892        self.browser.getLink("d102").click()
893        self.browser.open(self.documents_path + '/d102/edit')
894        #self.browser.getLink("Edit").click()
895        self.assertTrue('The requested form is locked' in self.browser.contents)
896        # Customer is in wrong state
897        IWorkflowState(self.customer).setState(APPROVED)
898        self.browser.open(self.documents_path + '/d102/edit')
899        self.browser.getControl(name="form.title").value = 'My second doc'
900        self.browser.getControl("Save").click()
901        self.assertEqual(document.title, 'My second doc')
902        self.assertTrue('Form has been saved.' in self.browser.contents)
903        self.browser.getLink("View").click()
904        self.assertEqual(self.browser.url, self.documents_path + '/d102/index')
905        # Costumer can upload a document.
906        self.browser.getLink("Edit").click()
907        ctrl = self.browser.getControl(name='samplescaneditupload')
908        file_obj = open(SAMPLE_IMAGE, 'rb')
909        file_ctrl = ctrl.mech_control
910        file_ctrl.add_file(file_obj, filename='my_document.jpg')
911        self.browser.getControl(
912            name='upload_samplescaneditupload').click()
913        self.assertTrue(
914            'href="http://localhost/app/customers/K1000000/documents/d102/sample"'
915            in self.browser.contents)
916        # Costumer can submit the form. The form is also saved.
917        self.browser.getControl(name="form.title").value = 'My third doc'
918        self.browser.getControl("Final Submit").click()
919        self.assertEqual(document.title, 'My third doc')
920        self.assertEqual(document.state, 'submitted')
921        self.assertTrue('Document State: submitted for verification' in self.browser.contents)
922        # Customer can't edit the document once it has been submitted
923        self.browser.open(self.documents_path + '/d102/edit')
924        self.assertTrue('The requested form is locked' in self.browser.contents)
925
926    def test_manage_upload_sample_file(self):
927        # Managers can upload a file via the DocumentManageFormPage
928        # The image is stored even if form has errors
929        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
930        self.browser.open(self.customer_path + '/documents/d101/manage')
931        # Create a pseudo image file and select it to be uploaded
932        image = open(SAMPLE_IMAGE, 'rb')
933        ctrl = self.browser.getControl(name='samplescanmanageupload')
934        file_ctrl = ctrl.mech_control
935        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
936        # The Save action does not upload files
937        self.browser.getControl("Save").click() # submit form
938        self.assertFalse(
939            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
940            in self.browser.contents)
941        # ... but the correct upload submit button does
942        image = open(SAMPLE_IMAGE)
943        ctrl = self.browser.getControl(name='samplescanmanageupload')
944        file_ctrl = ctrl.mech_control
945        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
946        self.browser.getControl(
947            name='upload_samplescanmanageupload').click()
948        self.assertTrue(
949            'href="http://localhost/app/customers/K1000000/documents/d101/sample"'
950            in self.browser.contents)
951        # Browsing the link shows a real image
952        self.browser.open('sample')
953        self.assertEqual(
954            self.browser.headers['content-type'], 'image/jpeg')
955        self.assertEqual(len(self.browser.contents), 2787)
956        # We can't reupload a file. The existing file must be deleted first.
957        self.browser.open(self.customer_path + '/documents/d101/manage')
958        self.assertFalse(
959            'upload_samplescanmanageupload' in self.browser.contents)
960        # File must be deleted first
961        self.browser.getControl(name='delete_samplescanmanageupload').click()
962        self.assertTrue(
963            'sample deleted' in self.browser.contents)
964        # Uploading a file which is bigger than 150k will raise an error
965        big_image = StringIO(open(SAMPLE_IMAGE, 'rb').read() * 75)
966        ctrl = self.browser.getControl(name='samplescanmanageupload')
967        file_ctrl = ctrl.mech_control
968        file_ctrl.add_file(big_image, filename='my_sample_scan.jpg')
969        self.browser.getControl(
970            name='upload_samplescanmanageupload').click()
971        self.assertTrue(
972            'Uploaded file is too big' in self.browser.contents)
973        # we do not rely on filename extensions given by uploaders
974        image = open(SAMPLE_IMAGE, 'rb') # a jpg-file
975        ctrl = self.browser.getControl(name='samplescanmanageupload')
976        file_ctrl = ctrl.mech_control
977        # tell uploaded file is bmp
978        file_ctrl.add_file(image, filename='my_sample_scan.bmp')
979        self.browser.getControl(
980            name='upload_samplescanmanageupload').click()
981        self.assertTrue(
982            # jpg file was recognized
983            'File sample.jpg uploaded.' in self.browser.contents)
984        # Delete file again
985        self.browser.getControl(name='delete_samplescanmanageupload').click()
986        self.assertTrue(
987            'sample deleted' in self.browser.contents)
988        # File names must meet several conditions
989        bmp_image = open(SAMPLE_IMAGE_BMP, 'rb')
990        ctrl = self.browser.getControl(name='samplescanmanageupload')
991        file_ctrl = ctrl.mech_control
992        file_ctrl.add_file(bmp_image, filename='my_sample_scan.bmp')
993        self.browser.getControl(
994            name='upload_samplescanmanageupload').click()
995        self.assertTrue('Only the following extensions are allowed'
996            in self.browser.contents)
997
998    def test_manage_upload_pdf_file(self):
999        # Managers can upload a file via the DocumentManageFormPage
1000        # The image is stored even if form has errors
1001        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1002        self.browser.open(self.customer_path + '/documents')
1003        self.browser.getLink("Add document").click()
1004        self.browser.getControl(name="doctype").value = ['CustomerPDFDocument']
1005        self.browser.getControl("Create document").click()
1006        self.browser.open(self.documents_path + '/d102/manage')
1007        # Create a pseudo image file and select it to be uploaded
1008        image = open(SAMPLE_IMAGE, 'rb')
1009        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1010        file_ctrl = ctrl.mech_control
1011        file_ctrl.add_file(image, filename='my_sample_scan.jpg')
1012        self.browser.getControl(
1013            name='upload_pdfscanmanageupload').click()
1014        self.assertTrue(
1015            'pdf file extension expected' in self.browser.contents)
1016        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1017        file_ctrl = ctrl.mech_control
1018        file_ctrl.add_file(image, filename='my_sample_scan.pdf')
1019        self.browser.getControl(
1020            name='upload_pdfscanmanageupload').click()
1021        self.assertTrue(
1022            'Could not determine file type' in self.browser.contents)
1023        pdf = open(SAMPLE_PDF, 'rb')
1024        ctrl = self.browser.getControl(name='pdfscanmanageupload')
1025        file_ctrl = ctrl.mech_control
1026        file_ctrl.add_file(pdf, filename='my_sample_scan.pdf')
1027        self.browser.getControl(
1028            name='upload_pdfscanmanageupload').click()
1029        self.assertTrue(
1030            'href="http://localhost/app/customers/K1000000/documents/d102/sample.pdf">PDF File</a>'
1031            in self.browser.contents)
1032        # Browsing the link shows a real pdf
1033        self.browser.open('sample.pdf')
1034        self.assertEqual(
1035            self.browser.headers['content-type'], 'application/pdf')
1036
1037    def test_view_slips(self):
1038        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1039        # Officers can open the document overview
1040        self.browser.open(self.customer_path + '/documents')
1041        self.browser.getLink("Download documents overview").click()
1042        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1043        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1044        path = os.path.join(samples_dir(), 'documents_overview_slip.pdf')
1045        open(path, 'wb').write(self.browser.contents)
1046        print "Sample PDF overview_slip.pdf written to %s" % path
1047        # Officers can open document slips
1048        self.browser.open(self.customer_path + '/documents/d101')
1049        self.browser.getLink("Download document slip").click()
1050        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1051        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1052        path = os.path.join(samples_dir(), 'document_slip.pdf')
1053        open(path, 'wb').write(self.browser.contents)
1054        print "Sample document_slip.pdf written to %s" % path
1055
1056
1057class ContractUITests(CustomersFullSetup):
1058    # Tests for CustomerSampleContract relates views and pages
1059
1060    def test_manage_contract(self):
1061        # Managers can access the pages of customer contractsconter
1062        # and can perform actions
1063        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1064        self.browser.open(self.customer_path)
1065        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1066        self.assertEqual(self.browser.url, self.customer_path)
1067        self.browser.open(self.customer_path)
1068        self.browser.getLink("Contracts").click()
1069        self.browser.getLink("Add contract").click()
1070        self.browser.getControl(name="contype").value = ['SampleContract']
1071        self.browser.getControl("Create contract").click()
1072        self.assertTrue('Sample Contract created.' in self.browser.contents)
1073        contract = self.customer['contracts']['c102']
1074
1075        # Contract can be edited
1076        self.browser.getLink("c102").click()
1077        self.browser.getLink("Manage").click()
1078        self.browser.getControl(name="form.product_object").value = ['SAM']
1079        self.browser.getControl(name="form.title").value = 'My second contract'
1080        self.browser.getControl("Save").click()
1081        self.assertTrue('Form has been saved.' in self.browser.contents)
1082        self.browser.getLink("View").click()
1083        self.assertEqual(self.browser.url, self.contracts_path + '/c102/index')
1084
1085        # Transitions can be performed
1086        self.browser.getLink("Transition").click()
1087        self.browser.getControl(name="transition").value = ['submit']
1088        self.browser.getControl("Save").click()
1089        self.browser.getControl(name="transition").value = ['approve']
1090        self.browser.getControl("Save").click()
1091        self.assertEqual(contract.state, 'approved')
1092
1093        # Contracts can be removed
1094        self.browser.getLink("Contracts").click()
1095        ctrl = self.browser.getControl(name='val_id')
1096        ctrl.getControl(value=contract.contract_id).selected = True
1097        self.browser.getControl("Remove selected", index=0).click()
1098        self.assertTrue('Successfully removed' in self.browser.contents)
1099
1100        # All actions are being logged
1101        logfile = os.path.join(
1102            self.app['datacenter'].storage, 'logs', 'customers.log')
1103        logcontent = open(logfile).read()
1104        self.assertTrue(
1105            'INFO - zope.mgr - customers.browser.ContractManageFormPage '
1106            '- K1000000 - c102 - saved: title'
1107            in logcontent)
1108        self.assertTrue(
1109            'INFO - zope.mgr - customers.browser.ContractAddFormPage '
1110            '- K1000000 - added: Sample Contract %s'
1111            % contract.contract_id in logcontent)
1112        self.assertTrue(
1113            'INFO - zope.mgr - customers.browser.ContractsManageFormPage '
1114            '- K1000000 - removed: %s'
1115            % contract.contract_id in logcontent)
1116
1117    def test_edit_sample_contract(self):
1118        # We add a second product.
1119        product = createObject('waeup.Product')
1120        product.product_id = u'LIC'
1121        product.title = u'Our License Product'
1122        product.contract_category = u'license'
1123        self.app['products'].addProduct(product)
1124        # Customers can manage contracts under certain conditions
1125        self.browser.open(self.login_path)
1126        self.browser.getControl(name="form.login").value = self.customer_id
1127        self.browser.getControl(name="form.password").value = 'cpwd'
1128        self.browser.getControl("Login").click()
1129        self.assertMatches(
1130            '...You logged in...', self.browser.contents)
1131        self.browser.getLink("Contracts").click()
1132        self.browser.getLink("Add contract").click()
1133        self.browser.getControl(name="contype").value = ['SampleContract']
1134        self.browser.getControl("Create contract").click()
1135        self.assertTrue('Sample Contract created.' in self.browser.contents)
1136        contract = self.customer['contracts']['c102']
1137        # Contract can be edited ...
1138        self.browser.open(self.contracts_path + '/c102/edit')
1139        #self.browser.getLink("Edit").click()
1140        self.assertTrue('The requested form is locked' in self.browser.contents)
1141        # Customer is in wrong state
1142        IWorkflowState(self.customer).setState(APPROVED)
1143        self.browser.open(self.contracts_path + '/c102/edit')
1144        self.browser.getControl(name="form.title").value = 'My second contract'
1145        # SAM is in the correct contract_category ...
1146        self.assertTrue('<option value="SAM">' in self.browser.contents)
1147        # ... but NOTSAM not.
1148        self.assertFalse('<option value="LIC">' in self.browser.contents)
1149        # So far last_product_id is None.
1150        self.assertTrue(self.customer['contracts']['c102'].last_product_id is None)
1151        self.browser.getControl(name="form.product_object").value = ['SAM']
1152        self.browser.getControl("Save").click()
1153        # Document is a required field on edit form page.
1154        self.assertTrue('Document: <span class="error">Required input is missing.</span>'
1155            in self.browser.contents)
1156        # But our document can't be selected because it's not submitted
1157        self.assertFalse('My first document' in self.browser.contents)
1158        IWorkflowState(self.document).setState(SUBMITTED)
1159        self.browser.open(self.contracts_path + '/c102/edit')
1160        self.browser.getControl(name="form.product_object").value = ['SAM']
1161        self.browser.getControl(name="form.document_object").value = ['d101']
1162        self.browser.getControl(name="form.title").value = 'My second contract'
1163        self.browser.getControl("Save").click()
1164        # After saving the form, last_product_id and other attributes are set
1165        self.assertTrue('Form has been saved.' in self.browser.contents)
1166        self.assertEqual(self.customer['contracts']['c102'].last_product_id, 'SAM')
1167        self.assertEqual(contract.title, 'My second contract')
1168        self.assertEqual(contract.product_object, self.product)
1169        self.assertEqual(contract.document_object, self.document)
1170        # Saving the form again does not unset last_product_id
1171        self.browser.getControl(name="form.title").value = 'My third contract'
1172        self.browser.getControl("Save").click()
1173        self.assertEqual(self.customer['contracts']['c102'].last_product_id, 'SAM')
1174        self.assertTrue('Form has been saved.' in self.browser.contents)
1175        self.browser.getLink("View").click()
1176        self.assertEqual(self.browser.url, self.contracts_path + '/c102/index')
1177        # An href attribute is referring to the document and product objects
1178        self.assertTrue('<a href="http://localhost/app/products/SAM">SAM -'
1179            in self.browser.contents)
1180        self.assertTrue(
1181            '<a href="http://localhost/app/customers/K1000000/documents/d101">d101 -'
1182            in self.browser.contents)
1183        # Customer can submit the form. The form is also saved.
1184        self.browser.getLink("Edit").click()
1185        self.browser.getControl(name="form.title").value = 'My fourth contract'
1186        self.browser.getControl("Apply now").click()
1187        self.assertEqual(contract.title, 'My fourth contract')
1188        self.assertEqual(contract.state, 'submitted')
1189        self.assertTrue('Contract State: submitted for approval' in self.browser.contents)
1190        # Customer can't edit the contract once it has been submitted
1191        self.browser.open(self.contracts_path + '/c102/edit')
1192        self.assertTrue('The requested form is locked' in self.browser.contents)
1193
1194    def test_view_slips(self):
1195        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1196        # Officers can open the contract overview
1197        self.browser.open(self.customer_path + '/contracts')
1198        self.browser.getLink("Download contracts overview").click()
1199        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1200        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1201        path = os.path.join(samples_dir(), 'contracts_overview_slip.pdf')
1202        open(path, 'wb').write(self.browser.contents)
1203        print "Sample PDF overview_slip.pdf written to %s" % path
1204        # Officers can open contract slips
1205        self.browser.open(self.customer_path + '/contracts/c101')
1206        self.browser.getLink("Download contract slip").click()
1207        self.assertEqual(self.browser.headers['Status'], '200 Ok')
1208        self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
1209        path = os.path.join(samples_dir(), 'contract_slip.pdf')
1210        open(path, 'wb').write(self.browser.contents)
1211        print "Sample contract_slip.pdf written to %s" % path
1212
1213    def test_contract_approval(self):
1214        # This is not a UI test. It just tests the approval
1215        # of contracts.
1216        self.assertRaises(ConstraintNotSatisfied,
1217            self.contract.document_object, self.document)
1218        # Document must be at least submitted
1219        IWorkflowState(self.document).setState('submitted')
1220        self.contract.document_object = self.document
1221        IWorkflowState(self.contract).setState('submitted')
1222        self.assertRaises(InvalidTransitionError,
1223            IWorkflowInfo(self.contract).fireTransition, 'approve')
1224        # Document must be verified for the approval of contracts
1225        IWorkflowState(self.document).setState('verified')
1226        IWorkflowInfo(self.contract).fireTransition('approve')
1227        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
1228
1229
1230    def test_contract_approval_in_UI(self):
1231        # Now let's see what the UI says why trying to approve a contract
1232        # with unverified documents.
1233        IWorkflowState(self.document).setState('submitted')
1234        self.contract.document_object = self.document
1235        IWorkflowState(self.contract).setState('submitted')
1236        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
1237        self.browser.open(self.contracts_path + '/c101/trigtrans')
1238        self.browser.getControl(name="transition").value = ['approve']
1239        self.browser.getControl("Save").click()
1240        # InvalidTransitionError is catched
1241        self.assertTrue(
1242            '<div class="alert alert-warning">Attached documents must be verified first.</div>'
1243            in self.browser.contents)
1244        IWorkflowState(self.document).setState('verified')
1245        self.browser.getControl(name="transition").value = ['approve']
1246        self.browser.getControl("Save").click()
1247        self.assertEqual(IWorkflowState(self.contract).getState(), 'approved')
Note: See TracBrowser for help on using the repository browser.