source: main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/customers/tests/test_browser.py @ 12701

Last change on this file since 12701 was 12694, checked in by uli, 10 years ago

Aggregate test helpers.

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